aboutsummaryrefslogtreecommitdiffstats
path: root/subsystem/karuta
diff options
context:
space:
mode:
authorMarcos Magueta <maguetamarcos@gmail.com>2026-11-07 03:41:09 -0300
committerMarcos Magueta <maguetamarcos@gmail.com>2026-11-07 03:41:09 -0300
commit58a5090a85e2deb7332686facd0bf9a3b8106ad5 (patch)
treefcc63d6521254e3373695b0dd1d8f973a17b6c8d /subsystem/karuta
parent38e60910a40a4b009db87049f11563f55d88b20f (diff)
downloadRNT-sakura-karuta-contract.tar.gz
RNT-sakura-karuta-contract.zip
bound queries from sakurasakura-karuta-contract
Diffstat (limited to 'subsystem/karuta')
-rw-r--r--subsystem/karuta/Beam.ml122
1 files changed, 83 insertions, 39 deletions
diff --git a/subsystem/karuta/Beam.ml b/subsystem/karuta/Beam.ml
index 82ae827..e0def90 100644
--- a/subsystem/karuta/Beam.ml
+++ b/subsystem/karuta/Beam.ml
@@ -8,12 +8,14 @@ module Error = struct
let malformed () =
condition "malformed-beam-program"
- "A beam program is not {Module, Function, Beam, #{Name => Domain}} of binaries" empty
+ "A beam program is not {Module, Beam, #{Name => Domain}} of binaries" empty
let not_a_program () =
condition "not-a-beam-program" "The evaluator was given a program of another kind" empty
- let inputs () = condition "beam-program-inputs" "A beam program takes no inputs" empty
+ let inputs () =
+ condition "beam-program-inputs"
+ "A beam program takes at most one input, of at most one tuple: what its caller knows" empty
let failed message =
condition "beam-failed" "The BEAM node failed to answer a call"
@@ -79,7 +81,6 @@ let name = "karuta"
type program =
{ module_: string;
- function_: string;
beam: string;
heading: Protocols.Schematics.relation_description }
@@ -90,12 +91,11 @@ let decode source =
| Concepts.Value.String domain -> Some {Protocols.Schematics.domain; provenance= []}
| Concepts.Value.Integer _ -> None
in
- match Translator.read 4 source with
- | Some ([module_; function_; beam], attributes)
- when String.length module_ <= 0xffff && String.length function_ <= 0xffff ->
+ match Translator.read 3 source with
+ | Some ([module_; beam], attributes) when String.length module_ <= 0xffff ->
let heading = BatMap.String.filter_map domain attributes in
if BatMap.String.cardinal heading = BatMap.String.cardinal attributes then
- Ok (Beam {module_; function_; beam; heading})
+ Ok (Beam {module_; beam; heading})
else Error (Error.malformed ())
| _ -> Error (Error.malformed ())
@@ -104,19 +104,22 @@ let decode source =
can call back into RNT, and so on, as deep as the calls nest.
RNT asks the node:
- - h run every loaded rnt_init/0 -> o | e
- - i Id:64 M:16 Module F:16 Function B:32 Beam
- start Module:Function() from Beam
+ - h run every loaded rnt-init -> o | e
+ - i Id:64 M:16 Module B:32 Beam [Bound]
+ start Module's query from Beam
- f Id:64 Limit:32 the next batch of it -> b | e
- c Id:64 forget it
The node asks RNT:
- D Path Evaluator:16 Source define a program at Path -> o | e
- - X Path invoke the program at Path -> r Id:64 | e
+ - X Path [Bound] invoke what is at Path -> r Id:64 | e
- E Evaluator:16 Source invoke a program of no path -> r Id:64 | e
- N Id:64 Limit:32 the next batch of its result -> b | e
- C Id:64 release that result
A Path is Count:16 then each segment as Length:16 Segment, and a
- batch b is Exhausted:8 then each tuple as Size:32 term_to_binary. *)
+ batch b is Exhausted:8 then each tuple as Size:32 term_to_binary.
+ Bound, when present, is the tuple of the attributes the caller
+ already knows as term_to_binary, which is how a procedural program,
+ one that can only check what it is given, gets called. *)
module Make (T : TRANSPORT) = struct
(* [root] is borrowed, not held: the evaluator lives under it, so
holding it would keep both alive forever. [cursors] are the
@@ -132,7 +135,7 @@ module Make (T : TRANSPORT) = struct
module Request = struct
type t =
| Define of string list * string * string
- | Invoke of string list
+ | Invoke of string list * Concepts.Tuple.t option
| Evaluate of string * string
| Next of int * int
| Close of int
@@ -165,7 +168,13 @@ module Make (T : TRANSPORT) = struct
| 'E' ->
let evaluator = sized () in
Some (Evaluate (evaluator, String.sub message !at (length - !at)))
- | 'X' -> finished (Invoke (path ()))
+ | 'X' -> (
+ let path = path () in
+ if !at = length then Some (Invoke (path, None))
+ else
+ match Translator.decode (String.sub message !at (length - !at)) with
+ | Ok bound -> Some (Invoke (path, Some bound))
+ | Error _ -> None )
| 'N' ->
let id = u64 () in
finished (Next (id, u32 ()))
@@ -216,14 +225,17 @@ module Make (T : TRANSPORT) = struct
Error (Error.program_taken (Kernel.Path.of_list path))
| Error c -> Protocols.Handle.release program; Error c )
- (* Runs [program], which it releases, keeping a cursor on the result
- for the node to read. *)
- let invoke node program =
+ (* Runs [target], which it releases, keeping a cursor on the result
+ for the node to read: a program's result given [inputs], or the
+ relation itself when [target] is not a program. *)
+ let invoke node ?(inputs = []) target =
let open Utilities.Result in
let* relation =
- Protocols.Handle.releasing program (fun () ->
- let* executable = Protocols.Executable.require program in
- Protocols.Executable.invoke executable [] ~within:node.root )
+ match Protocols.Executable.from target with
+ | None -> Ok target
+ | Some executable ->
+ Protocols.Handle.releasing target (fun () ->
+ Protocols.Executable.invoke executable inputs ~within:node.root )
in
match Protocols.Enumerable.cursor relation with
| Error c -> Protocols.Handle.release relation; Error c
@@ -243,6 +255,19 @@ module Make (T : TRANSPORT) = struct
if batch.exhausted then forget node id;
Ok (batch_message batch)
+ (* What a caller already knows, as the one-tuple relation a program
+ is invoked with. *)
+ let literal ({Concepts.Tuple.attributes; _} as tuple) =
+ let domain = function
+ | Concepts.Value.String _ -> "string"
+ | Concepts.Value.Integer _ -> "integer"
+ in
+ Kernel.EphemeralRelation.literal
+ (BatMap.String.map
+ (fun value -> {Protocols.Schematics.domain= domain value; provenance= []})
+ attributes )
+ [tuple]
+
let serve node request =
let answer = function
| Ok message -> T.send node.transport message
@@ -250,8 +275,15 @@ module Make (T : TRANSPORT) = struct
in
match request with
| Request.Define (path, evaluator, source) -> answer (define node path evaluator source)
- | Request.Invoke path ->
- answer (Result.bind (Kernel.Path.lookup node.root (Kernel.Path.of_list path)) (invoke node))
+ | Request.Invoke (path, bound) ->
+ let inputs = Option.to_list (Option.map literal bound) in
+ let result =
+ Result.bind
+ (Kernel.Path.lookup node.root (Kernel.Path.of_list path))
+ (invoke node ~inputs)
+ in
+ List.iter Protocols.Handle.release inputs;
+ answer result
| Request.Evaluate (evaluator, source) ->
answer (Result.bind (Kernel.Program.load node.root ~evaluator ~source) (invoke node))
| Request.Next (id, limit) -> answer (fetch node id limit)
@@ -291,7 +323,7 @@ module Make (T : TRANSPORT) = struct
let* () = serve node request in
await node )
- (* Lets the node's rnt_init/0 functions define their programs. *)
+ (* Lets the node's rnt-init closures define their programs. *)
let handshake node =
let open Utilities.Result in
let* () = T.send node.transport "h" in
@@ -299,17 +331,15 @@ module Make (T : TRANSPORT) = struct
match reply with `Done -> Ok () | `Batch _ -> Error (Error.unexpected ())
module Poll = struct
- let invoke_message id {module_; function_; beam; _} =
+ let invoke_message id {module_; beam; _} bound =
let buffer = Buffer.create (64 + String.length beam) in
Buffer.add_char buffer 'i';
Buffer.add_int64_be buffer (Int64.of_int id);
- List.iter
- (fun name ->
- Buffer.add_uint16_be buffer (String.length name);
- Buffer.add_string buffer name )
- [module_; function_];
+ Buffer.add_uint16_be buffer (String.length module_);
+ Buffer.add_string buffer module_;
Buffer.add_int32_be buffer (Int32.of_int (String.length beam));
Buffer.add_string buffer beam;
+ Option.iter (fun tuple -> Buffer.add_string buffer (Translator.encode tuple)) bound;
Buffer.contents buffer
let fetch_message id limit =
@@ -341,12 +371,25 @@ module Make (T : TRANSPORT) = struct
method protocols : Protocols.Handle.protocol list = Protocols.[Cursor.make self]
end
- let start node program =
+ let start node program bound =
let poll = new t node in
- T.send node.transport (invoke_message (Oo.id poll) program)
+ T.send node.transport (invoke_message (Oo.id poll) program bound)
|> Result.map (fun () -> Protocols.Handle.make poll)
end
+ (* The tuple a program is invoked with, if any: what its caller
+ already knows. It is read now, so the input is only borrowed. *)
+ let bound = function
+ | [] -> Ok None
+ | [input] -> (
+ let open Utilities.Result in
+ let* _, tuples = Protocols.Relation.read input in
+ match tuples with
+ | [] -> Ok None
+ | [tuple] -> Ok (Some tuple)
+ | _ -> Error (Error.inputs ()) )
+ | _ -> Error (Error.inputs ())
+
class evaluator node =
object (self)
inherit Kernel.Lifecycle.counted
@@ -365,14 +408,15 @@ module Make (T : TRANSPORT) = struct
within:Protocols.Handle.t ->
(Protocols.Handle.t, Concepts.Condition.condition) result =
fun kind inputs ~within:_ ->
- match kind, inputs with
- | Beam program, [] ->
- Ok
- (Kernel.EphemeralRelation.instantiate program.heading
- ~modes:(fun () -> Ok [Concepts.Mode.mode [] Concepts.Cardinality.Countable])
- (Kernel.EphemeralRelation.temporary program.heading)
- (fun () -> Poll.start node program) )
- | Beam _, _ -> Error (Error.inputs ())
+ match kind with
+ | Beam program ->
+ Result.map
+ (fun bound ->
+ Kernel.EphemeralRelation.instantiate program.heading
+ ~modes:(fun () -> Ok [Concepts.Mode.mode [] Concepts.Cardinality.Countable])
+ (Kernel.EphemeralRelation.temporary program.heading)
+ (fun () -> Poll.start node program bound) )
+ (bound inputs)
| _ -> Error (Error.not_a_program ())
method protocols : Protocols.Handle.protocol list = [Protocols.Evaluator.make self]