tricu

A lazy functional language based on Tree Calculus
Log | Files | Refs | README | LICENSE

io-profile.js (3165B)


      1 // This table is the implemented browser provider, not the native catalogue.
      2 import { canonicalNat, decodeAction, ProtocolError } from './io-protocol.js';
      3 export const coreNames = ['pure', 'bind', 'fail', 'scope', 'current-scope', 'spawn', 'join', 'discard', 'cancel', 'cancelled'];
      4 const groups = Object.freeze({
      5     runtime: ['capabilities', 'inspect'], standard: ['input', 'output', 'error'],
      6     stream: ['read', 'write'], resource: ['close'], utf8: ['encode', 'decode'],
      7 });
      8 export function available(group, revision, operation) {
      9     return revision === 1 && Object.hasOwn(groups, group) && groups[group].includes(operation);
     10 }
     11 export function capabilities(wire, backend) {
     12     const { tree } = wire, text = (s) => tree.text(s), number = (n) => tree.natural(BigInt(n));
     13     const strings = (xs) => wire.list(xs.map(text)), row = (name, value) => wire.list([text(name), value]);
     14     return wire.list([
     15         row('schema', number(1)), row('io-version', number(2)), row('backend', text(backend)), row('authority', text('browser-terminal')),
     16         row('core', strings(coreNames)), row('groups', wire.list(Object.entries(groups).map(([name, ops]) => wire.list([text(name), number(1), strings(ops)])))),
     17         row('limits', wire.list(Object.entries({ 'io-actions': 65536, 'chunk-bytes': 4096, 'transfer-handles': 256, 'utf8-encode-scalars': 1024, 'input-line-scalars': 256, 'output-attempted-bytes': 16384 }).map(([key, value]) => row(key, number(value))))),
     18         row('restrictions', strings(['action-boundary-cancellation', 'no-hard-deadlines', 'borrowed-standard-streams', 'standard-stream-leases-per-run', 'utf8-strict-scalars', 'text-line-input', 'byte-preserving-output', 'no-filesystem', 'no-network', 'no-processes'])),
     19     ]);
     20 }
     21 export function inspect(wire, value) {
     22     const action = decodeAction(wire.tree, value), t = wire.tree;
     23     return action.kind === 'core' ? wire.list([t.text('core'), t.text(coreNames[action.code])]) :
     24         wire.list([t.text('facility'), t.text(action.group), t.natural(BigInt(action.revision)), t.text(action.operation), t.text(available(action.group, action.revision, action.operation) ? 'available' : 'unsupported')]);
     25 }
     26 // Authenticate framing before selecting an interpreter. No action is observed.
     27 export function envelope(tree, value) {
     28     const root = tree.observe(value).node;
     29     if (root.kind !== 'fork')
     30         throw new ProtocolError('invalid IO envelope');
     31     let rest = root.left;
     32     for (const char of 'tricuIO') {
     33         const node = tree.observe(rest).node;
     34         if (node.kind !== 'fork' || canonicalNat(tree, node.left, 7) !== BigInt(char.charCodeAt(0)))
     35             throw new ProtocolError('Missing tricuIO sentinel');
     36         rest = node.right;
     37     }
     38     if (tree.observe(rest).node.kind !== 'leaf')
     39         throw new ProtocolError('Missing tricuIO sentinel');
     40     const body = tree.observe(root.right).node;
     41     if (body.kind !== 'fork')
     42         throw new ProtocolError('invalid IO envelope');
     43     const version = canonicalNat(tree, body.left, 2);
     44     if (version !== 2n)
     45         throw new ProtocolError('Unsupported tricuIO version');
     46     return { version: 2, action: body.right };
     47 }