aboutsummaryrefslogtreecommitdiffstats
path: root/prototypes/connections/examples
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-24 17:14:54 +0100
committereunhhu <[email protected]>2026-09-24 17:14:54 +0100
commitb1ce1927022d374198441afafeb27199fc8a052a (patch)
tree6021f175f4c67ed03b44240eaa2f90d846f12f6f /prototypes/connections/examples
parentd34f9426d5317a1948f12f229439946728bc342a (diff)
downloadpure-b1ce1927022d374198441afafeb27199fc8a052a.tar.gz
pure-b1ce1927022d374198441afafeb27199fc8a052a.zip
Establish native micro runtime checkpoint
Diffstat (limited to 'prototypes/connections/examples')
-rw-r--r--prototypes/connections/examples/bounded-editor.pure19
-rw-r--r--prototypes/connections/examples/editor.pure19
-rw-r--r--prototypes/connections/examples/excerpt.pure13
-rw-r--r--prototypes/connections/examples/select-text.py72
-rw-r--r--prototypes/connections/examples/selection.pure19
-rw-r--r--prototypes/connections/examples/storage.pure11
6 files changed, 153 insertions, 0 deletions
diff --git a/prototypes/connections/examples/bounded-editor.pure b/prototypes/connections/examples/bounded-editor.pure
new file mode 100644
index 0000000..e9f2634
--- /dev/null
+++ b/prototypes/connections/examples/bounded-editor.pure
@@ -0,0 +1,19 @@
+// Same document edit as editor.pure, with an authored final-size policy.
+// The store checks the limit against the current version under its writer lock.
+layout Edit {
+ start: u32le;
+ remove: u32le;
+ insert: bytes;
+}
+
+on get {
+ let document = store.read(request.key);
+ reply(document, document.body);
+}
+
+on put {
+ let edit = view(Edit, request.body);
+ let saved = store.splice(request.key, request.revision,
+ edit.start, edit.remove, edit.insert, 8);
+ reply(saved, edit.insert);
+}
diff --git a/prototypes/connections/examples/editor.pure b/prototypes/connections/examples/editor.pure
new file mode 100644
index 0000000..4de78bc
--- /dev/null
+++ b/prototypes/connections/examples/editor.pure
@@ -0,0 +1,19 @@
+// A revision-checked byte edit. The input carries only the replacement.
+// UTF-8 cursor/grapheme positions are translated to byte ranges by the UI.
+layout Edit {
+ start: u32le;
+ remove: u32le;
+ insert: bytes;
+}
+
+on get {
+ let document = store.read(request.key);
+ reply(document, document.body);
+}
+
+on put {
+ let edit = view(Edit, request.body);
+ let saved = store.splice(request.key, request.revision,
+ edit.start, edit.remove, edit.insert);
+ reply(saved, edit.insert);
+}
diff --git a/prototypes/connections/examples/excerpt.pure b/prototypes/connections/examples/excerpt.pure
new file mode 100644
index 0000000..622f9bb
--- /dev/null
+++ b/prototypes/connections/examples/excerpt.pure
@@ -0,0 +1,13 @@
+// Read bytes 32..47 of an object that must contain the complete 64-byte window.
+// Preparation keeps the size check for 16..79, and maps only 32..47 for reply.
+on get {
+ let object = store.read(request.key);
+ let window = range(object.body, 16, 64);
+ let excerpt = range(window, 16, 16);
+ reply(object, excerpt);
+}
+
+on put {
+ let saved = store.write(request.key, request.revision, request.body);
+ reply(saved);
+}
diff --git a/prototypes/connections/examples/select-text.py b/prototypes/connections/examples/select-text.py
new file mode 100644
index 0000000..ffaf80b
--- /dev/null
+++ b/prototypes/connections/examples/select-text.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+"""Save a UTF-8 document selection through selection.pure (character indices)."""
+import argparse
+import http.client
+import json
+from pathlib import Path
+import re
+import struct
+from urllib.parse import urlsplit
+
+LIMIT = (2 * 6 + 32) * 32768 + 8192
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('file', type=Path)
+ parser.add_argument('--key', required=True)
+ parser.add_argument('--start', type=int, required=True, help='first Unicode code point, starting at 0')
+ parser.add_argument('--end', type=int, required=True, help='exclusive Unicode code point boundary')
+ parser.add_argument('--revision', type=int, default=0, help='0 creates; otherwise expected stored revision')
+ parser.add_argument('--url', default='http://127.0.0.1:8767')
+ args = parser.parse_args()
+ url = urlsplit(args.url)
+ try:
+ port = url.port or 80
+ except ValueError as error:
+ parser.error(str(error))
+ if (url.scheme != 'http' or url.hostname not in ['localhost', '127.0.0.1'] or
+ url.username is not None or url.password is not None or url.path not in ['', '/'] or
+ url.query or url.fragment):
+ parser.error('use a local HTTP server origin')
+ if not re.fullmatch(r'[A-Za-z0-9_-]{1,64}', args.key) or not 0 <= args.revision <= 2**63 - 1:
+ parser.error('invalid object key or revision')
+ try:
+ with args.file.open('rb') as source:
+ document = source.read(LIMIT - 8 + 1)
+ if len(document) > LIMIT - 8:
+ parser.error('document exceeds the prototype request limit')
+ text = document.decode('utf-8')
+ except (OSError, UnicodeError) as error:
+ parser.error(str(error))
+ if not 0 <= args.start <= args.end <= len(text):
+ parser.error('selection is outside the document')
+ start = len(text[:args.start].encode('utf-8'))
+ selected = text[args.start:args.end].encode('utf-8')
+ # The boundary layout is explicit; storage receives only selected bytes.
+ payload = struct.pack('<II', start, len(selected)) + document
+ headers = {'Content-Type': 'application/octet-stream'}
+ headers['If-None-Match' if args.revision == 0 else 'If-Match'] = (
+ '*' if args.revision == 0 else f'"{args.revision}"')
+ connection = http.client.HTTPConnection(url.hostname, port, timeout=12)
+ try:
+ connection.request('PUT', '/objects/' + args.key, payload, headers)
+ response = connection.getresponse()
+ body = response.read(LIMIT + 1)
+ if response.status != 200:
+ parser.error(f'storage response {response.status}: {response.getheader("X-Pure-Error")}')
+ if body != selected:
+ parser.error('response differs from the selection; check the installed program (write may have occurred)')
+ revision = response.getheader('ETag', '')
+ if not re.fullmatch(r'"[1-9][0-9]*"', revision) or int(revision[1:-1]) > 2**63 - 1:
+ parser.error('response has no valid stored revision (write may have occurred)')
+ except (OSError, http.client.HTTPException) as error:
+ parser.error(f'{error}; storage outcome is unknown if the request was sent')
+ finally:
+ connection.close()
+ print(json.dumps({'revision': revision[1:-1], 'selected': selected.decode('utf-8'),
+ 'stored_bytes': len(selected)}, ensure_ascii=False))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/prototypes/connections/examples/selection.pure b/prototypes/connections/examples/selection.pure
new file mode 100644
index 0000000..7d9d4ec
--- /dev/null
+++ b/prototypes/connections/examples/selection.pure
@@ -0,0 +1,19 @@
+// This is an input boundary layout, not a required storage or RAM model.
+// The client sends two little-endian u32 values followed by document bytes.
+layout Selection {
+ start: u32le;
+ count: u32le;
+ document: bytes;
+}
+
+on get {
+ let saved = store.read(request.key);
+ reply(saved, saved.body);
+}
+
+on put {
+ let input = view(Selection, request.body);
+ let selected = range(input.document, input.start, input.count);
+ let saved = store.write(request.key, request.revision, selected);
+ reply(saved, selected);
+}
diff --git a/prototypes/connections/examples/storage.pure b/prototypes/connections/examples/storage.pure
new file mode 100644
index 0000000..ff54ea3
--- /dev/null
+++ b/prototypes/connections/examples/storage.pure
@@ -0,0 +1,11 @@
+// The host supplies request bytes, an object name, and the expected revision.
+// Failed storage results propagate to the host's response without executing reply.
+on get {
+ let object = store.read(request.key);
+ reply(object, object.body);
+}
+
+on put {
+ let saved = store.write(request.key, request.revision, request.body);
+ reply(saved);
+}