diff options
| author | Marcos Magueta <maguetamarcos@gmail.com> | 2026-09-25 21:51:33 -0300 |
|---|---|---|
| committer | Marcos Magueta <maguetamarcos@gmail.com> | 2026-09-25 21:51:33 -0300 |
| commit | 584fbca6d920e9a9f91d451667f9380714ac2175 (patch) | |
| tree | a163b916a6f8cb550c8b38ceb01ab01558687a40 | |
| parent | c7b754e96714eeeb9d315ee3de402d73a27d47db (diff) | |
| download | RNT-584fbca6d920e9a9f91d451667f9380714ac2175.tar.gz RNT-584fbca6d920e9a9f91d451667f9380714ac2175.zip | |
dune fmt
Diffstat (limited to '')
58 files changed, 1123 insertions, 1190 deletions
diff --git a/lib/Utilities.ml b/lib/Utilities.ml index fb5a7b3..c16be2e 100644 --- a/lib/Utilities.ml +++ b/lib/Utilities.ml @@ -7,9 +7,7 @@ end module Option = struct let ( let* ) = Option.bind let fmap f m = Option.bind m f - let sequence = function - | None -> Ok None - | Some x -> Result.map Option.some x + let sequence = function None -> Ok None | Some x -> Result.map Option.some x end module Result = struct @@ -32,9 +30,8 @@ module Generic (S : SEQUENCE) = struct (fun m acc -> let* acc = acc in let* m = m in - Ok (S.cons m acc)) - ms - (Ok S.empty) + Ok (S.cons m acc) ) + ms (Ok S.empty) end module List = struct @@ -42,15 +39,13 @@ module List = struct type 'a t = 'a list let empty = [] - let cons x xs = x::xs + let cons x xs = x :: xs let fold = List.fold_right end include Generic (ListSequence) - let hd_opt = function - | x::_ -> Some x - | [] -> None + let hd_opt = function x :: _ -> Some x | [] -> None end module FingerTree = struct @@ -59,10 +54,7 @@ module FingerTree = struct let empty = BatFingerTree.empty let cons x xs = BatFingerTree.cons xs x - let fold f xs acc = BatFingerTree.fold_right - (Fun.flip f) - acc - xs + let fold f xs acc = BatFingerTree.fold_right (Fun.flip f) acc xs end include Generic (FingerTreeSequence) @@ -71,38 +63,30 @@ module FingerTree = struct let rec frob xs ys acc = match BatFingerTree.front xs with | None -> acc - | Some (xs', x) -> - match BatFingerTree.front ys with - | None -> acc - | Some (ys', y) -> - f x y - |> BatFingerTree.snoc acc - |> frob xs' ys' + | Some (xs', x) -> ( + match BatFingerTree.front ys with + | None -> acc + | Some (ys', y) -> f x y |> BatFingerTree.snoc acc |> frob xs' ys' ) in frob xs ys BatFingerTree.empty let zip xs ys = map2 (fun x y -> x, y) xs ys let join ss sep = - BatFingerTree.print ~first:"" ~last:"" ~sep:sep BatIO.nwrite - |> Fun.flip BatIO.to_string ss + BatFingerTree.print ~first:"" ~last:"" ~sep BatIO.nwrite |> Fun.flip BatIO.to_string ss end module Atomic = struct let rec swap atom f = let v = Atomic.get atom in let v' = f v in - if Atomic.compare_and_set atom v v' - then atom - else swap atom f + if Atomic.compare_and_set atom v v' then atom else swap atom f let rec mswap atom f = let open Result in let v = Atomic.get atom in let* v' = f v in - if Atomic.compare_and_set atom v v' - then Ok atom - else mswap atom f + if Atomic.compare_and_set atom v v' then Ok atom else mswap atom f end module Fun = struct diff --git a/lib/Utilities.mli b/lib/Utilities.mli index 2b9591c..4ab7674 100644 --- a/lib/Utilities.mli +++ b/lib/Utilities.mli @@ -22,6 +22,7 @@ end module Atomic : sig val swap : 'a Atomic.t -> ('a -> 'a) -> 'a Atomic.t + (* This is silly *) val mswap : 'a Atomic.t -> ('a -> ('a, 'b) result) -> ('a Atomic.t, 'b) result end @@ -29,9 +30,7 @@ end module FingerTree : sig val map2 : ('a -> 'b -> 'c) -> 'a BatFingerTree.t -> 'b BatFingerTree.t -> 'c BatFingerTree.t val zip : 'a BatFingerTree.t -> 'b BatFingerTree.t -> ('a * 'b) BatFingerTree.t - val sequence : ('a, 'b) result BatFingerTree.t -> ('a BatFingerTree.t, 'b) result - val join : string BatFingerTree.t -> string -> string end diff --git a/lib/abstract/Storage.ml b/lib/abstract/Storage.ml index afd1a3c..e189cd7 100644 --- a/lib/abstract/Storage.ml +++ b/lib/abstract/Storage.ml @@ -1,7 +1,6 @@ module type STORAGE = sig type connection type transaction - type address = Label of string | Hash of Concepts.Hash.hash val connect : Concepts.Configuration.term -> (connection, Concepts.Condition.condition) result @@ -22,15 +21,8 @@ module type STORAGE = sig val abort : transaction -> (unit, Concepts.Condition.condition) result (** within a transaction, fetch a blob from disk *) - val get : - transaction -> - address -> - (Concepts.Blob.t option, Concepts.Condition.condition) result + val get : transaction -> address -> (Concepts.Blob.t option, Concepts.Condition.condition) result (** within a transaction, associate a hash with a blob on disk *) - val put : - transaction -> - address -> - Concepts.Blob.t -> - (unit, Concepts.Condition.condition) result + val put : transaction -> address -> Concepts.Blob.t -> (unit, Concepts.Condition.condition) result end diff --git a/lib/backend/storage/LMDB.ml b/lib/backend/storage/LMDB.ml index e364b6a..cf5bd97 100644 --- a/lib/backend/storage/LMDB.ml +++ b/lib/backend/storage/LMDB.ml @@ -82,8 +82,7 @@ module C = struct point could allow collection of the buffer before LMDB is done with it. The Sys.opaque_identity hides it from OCaml's optimizations. *) - Fun.protect ~finally:(fun () -> ignore (Sys.opaque_identity buf)) - (fun () -> body (addr s)) + Fun.protect ~finally:(fun () -> ignore (Sys.opaque_identity buf)) (fun () -> body (addr s)) let bytes_of_mdb_val (s : mdb_val structure) = let buf = @@ -96,8 +95,7 @@ module C = struct (ptr mdb_txn @-> mdb_dbi @-> ptr mdb_val @-> ptr mdb_val @-> returning mdb_result) let mdb_get' txn dbi key = - with_mdb_val key (fun key -> - with_output_pointer mdb_val (make mdb_val) (mdb_get txn dbi key)) + with_mdb_val key (fun key -> with_output_pointer mdb_val (make mdb_val) (mdb_get txn dbi key)) |> Result.map bytes_of_mdb_val let mdb_put = @@ -105,8 +103,7 @@ module C = struct (ptr mdb_txn @-> mdb_dbi @-> ptr mdb_val @-> ptr mdb_val @-> uint @-> returning mdb_result) let mdb_put' txn dbi key data flags = - with_mdb_val key (fun key -> - with_mdb_val data (fun data -> mdb_put txn dbi key data flags)) + with_mdb_val key (fun key -> with_mdb_val data (fun data -> mdb_put txn dbi key data flags)) let mdb_strerror = foreign "mdb_strerror" (int @-> returning string) @@ -127,8 +124,8 @@ end module Error = struct open Concepts.Condition - let closed_transaction = - condition "closed-transaction" "The transaction has already ended" empty + + let closed_transaction = condition "closed-transaction" "The transaction has already ended" empty let lmdb_error code = condition "lmdb-error" (C.mdb_strerror code) ("code" |=| Concepts.Value.Integer code) @@ -136,7 +133,6 @@ end type connection = {env: C.mdb_env_ptr; dbi: C.mdb_dbi} type transaction = {tx: C.mdb_txn_ptr; dbi: C.mdb_dbi; mutable active: bool} - type address = Label of string | Hash of Concepts.Hash.hash let parse (c : Concepts.Configuration.term) = @@ -171,7 +167,7 @@ let disconnect ({env; _} : connection) = C.mdb_env_close env let begin_with flags ({env; dbi} : connection) = C.mdb_txn_begin' env C.null_txn flags - |> Result.map (fun tx -> {tx; dbi; active = true;}) + |> Result.map (fun tx -> {tx; dbi; active= true}) |> Result.map_error Error.lmdb_error let start = begin_with Unsigned.UInt.zero @@ -203,17 +199,17 @@ let bytes_of_address = function | Hash h -> Concepts.Hash.bytes_of_hash h let get ({tx; dbi; active} : transaction) (addr : address) = - if not active then Error Error.closed_transaction else - begin match C.mdb_get' tx dbi (bytes_of_address addr) with - | Ok x -> Ok (Some (Concepts.Blob.blob_of_bytes x)) - | Error e when e = C.Errors.mdb_notfound -> Ok None - | Error e -> Error e - end - |> Result.map_error Error.lmdb_error + if not active then Error Error.closed_transaction + else + begin match C.mdb_get' tx dbi (bytes_of_address addr) with + | Ok x -> Ok (Some (Concepts.Blob.blob_of_bytes x)) + | Error e when e = C.Errors.mdb_notfound -> Ok None + | Error e -> Error e + end + |> Result.map_error Error.lmdb_error let put ({tx; dbi; active} : transaction) (addr : address) (b : Concepts.Blob.t) = - if not active then Error Error.closed_transaction else - C.mdb_put' tx dbi (bytes_of_address addr) - (Concepts.Blob.bytes_of_blob b) - Unsigned.UInt.zero - |> Result.map_error Error.lmdb_error + if not active then Error Error.closed_transaction + else + C.mdb_put' tx dbi (bytes_of_address addr) (Concepts.Blob.bytes_of_blob b) Unsigned.UInt.zero + |> Result.map_error Error.lmdb_error diff --git a/lib/concepts/Blob.mli b/lib/concepts/Blob.mli index b7c5da3..b09ee64 100644 --- a/lib/concepts/Blob.mli +++ b/lib/concepts/Blob.mli @@ -10,17 +10,10 @@ val blob_of_bytes : bytes -> t val bytes_of_blob : t -> bytes val create : int -> t - val set : t -> int -> char -> unit - val set_int64_be : t -> int -> int64 -> unit - val blit_string : string -> int -> t -> int -> int -> unit - val length : t -> int - val get : t -> int -> char - val sub_string : t -> int -> int -> string - val get_int64_be : t -> int -> int64 diff --git a/lib/concepts/Encoding.ml b/lib/concepts/Encoding.ml index 5bb9b16..733ff67 100644 --- a/lib/concepts/Encoding.ml +++ b/lib/concepts/Encoding.ml @@ -28,7 +28,7 @@ let value_of_blob (b : Blob.t) = Value.Integer (Int64.to_int (Blob.get_int64_be b 1)) | c -> invalid_arg (Printf.sprintf "value_of_blob: unknown tag %C" c) - module Error = struct +module Error = struct open Condition let unexpected_end = @@ -46,21 +46,19 @@ let value_of_blob (b : Blob.t) = condition "codec-string-out-of-bounds" "A string length runs past the end of input" ("length" |=| Value.Integer length) - let trailing_bytes = - condition "codec-trailing-bytes" "Bytes remain after a complete value" empty + let trailing_bytes = condition "codec-trailing-bytes" "Bytes remain after a complete value" empty let tag_mismatch ~expected ~actual = condition "codec-tag-mismatch" "A value with a different tag was expected" - ("expected" |=| Value.String (String.make 1 expected) & - "actual" |=| Value.String (String.make 1 actual)) + ( "expected" |=| Value.String (String.make 1 expected) + & "actual" |=| Value.String (String.make 1 actual) ) let type_mismatch ~expected = condition "codec-type-mismatch" "A Bencode value of a different shape was expected" ("expected" |=| Value.String expected) let missing_field key = - condition "codec-missing-field" "A required field is absent" - ("field" |=| Value.String key) + condition "codec-missing-field" "A required field is absent" ("field" |=| Value.String key) let unexpected_object ~expected = condition "codec-unexpected-object" "The decoded object is not of the expected kind" @@ -79,38 +77,37 @@ end - List "l" <element>* "e" - Dict "d" (<String key> <value>)* "e" keys sorted on encode *) module Bencode = struct - type t = Tagged of char * t | Int of int | String of string | List of t list | Dict of (string * t) list + type t = + | Tagged of char * t + | Int of int + | String of string + | List of t list + | Dict of (string * t) list let rec encode buf = function - | Tagged (tag, value) -> - Buffer.add_char buf 't'; - Buffer.add_char buf tag; - encode buf value + | Tagged (tag, value) -> Buffer.add_char buf 't'; Buffer.add_char buf tag; encode buf value | Int n -> - Buffer.add_char buf 'i'; - Buffer.add_string buf (string_of_int n); - Buffer.add_char buf 'e' + Buffer.add_char buf 'i'; + Buffer.add_string buf (string_of_int n); + Buffer.add_char buf 'e' | String s -> - Buffer.add_string buf (string_of_int (String.length s)); - Buffer.add_char buf ':'; - Buffer.add_string buf s + Buffer.add_string buf (string_of_int (String.length s)); + Buffer.add_char buf ':'; + Buffer.add_string buf s | List xs -> - Buffer.add_char buf 'l'; - List.iter (encode buf) xs; - Buffer.add_char buf 'e' + Buffer.add_char buf 'l'; + List.iter (encode buf) xs; + Buffer.add_char buf 'e' | Dict kvs -> - Buffer.add_char buf 'd'; - List.iter - (fun (k, v) -> - encode buf (String k); - encode buf v ) - (List.sort (fun (a, _) (b, _) -> String.compare a b) kvs); - Buffer.add_char buf 'e' + Buffer.add_char buf 'd'; + List.iter + (fun (k, v) -> encode buf (String k); encode buf v) + (List.sort (fun (a, _) (b, _) -> String.compare a b) kvs); + Buffer.add_char buf 'e' let to_bytes (value : t) : bytes = let buf = Buffer.create 256 in - encode buf value; - Buffer.to_bytes buf + encode buf value; Buffer.to_bytes buf let as_string = function String s -> Ok s | _ -> Error (Error.type_mismatch ~expected:"string") let as_int = function Int n -> Ok n | _ -> Error (Error.type_mismatch ~expected:"integer") @@ -122,7 +119,7 @@ module Bencode = struct let s = Bytes.to_string bytes in let n = String.length s in let pos = ref 0 in - let peek () = if !pos >= n then Error (Error.unexpected_end) else Ok (s.[!pos]) in + let peek () = if !pos >= n then Error Error.unexpected_end else Ok s.[!pos] in let advance () = incr pos in (* Read the decimal run up to (and consuming) [term]. *) let read_int_from start term = @@ -136,8 +133,7 @@ module Bencode = struct | None -> Error (Error.malformed_integer digits) end else begin - advance (); - scan () + advance (); scan () end in scan () @@ -145,43 +141,44 @@ module Bencode = struct let read_int term = read_int_from !pos term in let read_char () = let* c = peek () in - advance (); - Ok c + advance (); Ok c in let rec parse () = let* c = peek () in advance (); match c with | 't' -> - let* tag = read_char () in - let* data = parse () in - Ok (Tagged (tag, data)) + let* tag = read_char () in + let* data = parse () in + Ok (Tagged (tag, data)) | 'i' -> - let* n = read_int 'e' in - Ok (Int n) + let* n = read_int 'e' in + Ok (Int n) | 'l' -> parse_list [] | 'd' -> parse_dict [] | c when c >= '0' && c <= '9' -> parse_string_from (!pos - 1) | c -> Error (Error.unexpected_byte c) - and parse_string () = - parse_string_from !pos + and parse_string () = parse_string_from !pos and parse_string_from start = let* len = read_int_from start ':' in - if len < 0 || !pos + len > n then - Error (Error.string_out_of_bounds len) + if len < 0 || !pos + len > n then Error (Error.string_out_of_bounds len) else let str = String.sub s !pos len in pos := !pos + len; Ok (String str) and parse_list acc = let* c = peek () in - if c = 'e' then (advance (); Ok (List (List.rev acc))) + if c = 'e' then ( + advance (); + Ok (List (List.rev acc)) ) else let* result = parse () in parse_list (result :: acc) and parse_dict acc = let* c = peek () in - if c = 'e' then (advance (); Ok (Dict (List.rev acc))) + if c = 'e' then ( + advance (); + Ok (Dict (List.rev acc)) ) else let* key = parse_string () in let* key = as_string key in @@ -189,55 +186,43 @@ module Bencode = struct parse_dict ((key, value) :: acc) in let* value = parse () in - if !pos <> n then Error Error.trailing_bytes else - Ok value + if !pos <> n then Error Error.trailing_bytes else Ok value let to_blob x = to_bytes x |> Blob.blob_of_bytes let of_blob b = Blob.bytes_of_blob b |> of_bytes let with_tag t = function - | Tagged (t', v) -> - if t = t' then - Ok v - else - Error (Error.tag_mismatch ~expected:t ~actual:t') + | Tagged (t', v) -> if t = t' then Ok v else Error (Error.tag_mismatch ~expected:t ~actual:t') | _ -> Error (Error.type_mismatch ~expected:"tagged") let field key = function | Dict kvs -> ( - match List.assoc_opt key kvs with - | Some v -> Ok v - | None -> Error (Error.missing_field key) ) + match List.assoc_opt key kvs with Some v -> Ok v | None -> Error (Error.missing_field key) ) | _ -> Error (Error.type_mismatch ~expected:"dict") end module Value = struct let bencode_of_hash hash = Bencode.Tagged ('h', Bencode.String (Hash.to_raw_string hash)) + let hash_of_bencode value = let open Utilities.Result in - Bencode.with_tag 'h' value - |> fmap Bencode.as_string - |> Result.map Hash.of_raw_string + Bencode.with_tag 'h' value |> fmap Bencode.as_string |> Result.map Hash.of_raw_string + + let bencode_of_option f option = + Bencode.Tagged ('?', Option.map f option |> Option.to_list |> fun x -> Bencode.List x) - let bencode_of_option f option = Bencode.Tagged ('?', Option.map f option - |> Option.to_list - |> (fun x -> Bencode.List x)) let option_of_bencode f value = let open Utilities.Result in Bencode.with_tag '?' value |> fmap Bencode.as_list |> Result.map Utilities.List.hd_opt - |> fmap (function - | None -> Ok None - | Some v -> f v |> Result.map Option.some) + |> fmap (function None -> Ok None | Some v -> f v |> Result.map Option.some) end module Field = struct let string value = Bencode.String value let address address = Bencode.String (Hash.to_raw_string address) - - let require_string key data = - Bencode.field key data |> Utilities.Result.fmap Bencode.as_string + let require_string key data = Bencode.field key data |> Utilities.Result.fmap Bencode.as_string let require_address ~malformed key data = let open Utilities.Result in @@ -252,10 +237,8 @@ module Record = struct val to_bencode : t -> Bencode.t val of_bencode : Bencode.t -> (t, Condition.condition) result - val to_blob : t -> Blob.t val of_blob : Blob.t -> (t, Condition.condition) result - val to_bytes : t -> bytes val of_bytes : bytes -> (t, Condition.condition) result end @@ -275,13 +258,11 @@ module Record = struct let to_bencode object_ = Bencode.Tagged (B.tag, Bencode.Dict (B.fields object_)) let of_bencode = function - | Bencode.Tagged (tag, (Bencode.Dict _ as data)) when Char.equal tag B.tag -> - B.of_fields data + | Bencode.Tagged (tag, (Bencode.Dict _ as data)) when Char.equal tag B.tag -> B.of_fields data | _ -> Error (B.malformed ()) let to_blob object_ = to_bencode object_ |> Bencode.to_blob let of_blob blob = Bencode.of_blob blob |> Utilities.Result.fmap of_bencode - let to_bytes object_ = to_blob object_ |> Blob.bytes_of_blob let of_bytes bytes = Bencode.of_bytes bytes |> Utilities.Result.fmap of_bencode end diff --git a/lib/concepts/Hash.ml b/lib/concepts/Hash.ml index 5f023fc..263ceed 100644 --- a/lib/concepts/Hash.ml +++ b/lib/concepts/Hash.ml @@ -2,13 +2,9 @@ type hash = Digestif.SHA256.t -let size = 256/8 - -let compare h1 h2 = Digestif.SHA256.unsafe_compare h1 h2 - |> Utilities.Ordering.of_int - +let size = 256 / 8 +let compare h1 h2 = Digestif.SHA256.unsafe_compare h1 h2 |> Utilities.Ordering.of_int let hash_of_bytes bytes = Digestif.SHA256.digest_bytes bytes - let hash_of_blob blob = Blob.bytes_of_blob blob |> Digestif.SHA256.digest_bytes let hash_of_int i = @@ -17,15 +13,10 @@ let hash_of_int i = hash_of_blob b let bytes_of_hash (h : hash) = Bytes.of_string (Digestif.SHA256.to_raw_string h) - let blob_of_hash h = bytes_of_hash h |> Blob.blob_of_bytes - let to_raw_string hash = Digestif.SHA256.to_raw_string hash - let of_raw_string str = Digestif.SHA256.of_raw_string str - let to_hum_string hash = Digestif.SHA256.to_hex hash - let hash_equals = Digestif.SHA256.equal let power_of_two p = diff --git a/lib/concepts/Tuple.ml b/lib/concepts/Tuple.ml index 296bf26..28dadc5 100644 --- a/lib/concepts/Tuple.ml +++ b/lib/concepts/Tuple.ml @@ -1,8 +1,8 @@ -type t = { type_ : string; attributes : Value.value BatMap.String.t } +type t = {type_: string; attributes: Value.value BatMap.String.t} let malformed_value () = - Condition.condition "malformed-tuple-value" - "A tuple field did not conform to what was expected" Condition.empty + Condition.condition "malformed-tuple-value" "A tuple field did not conform to what was expected" + Condition.empty let bencode_of_value = function | Value.String s -> Encoding.Bencode.Tagged ('s', Encoding.Bencode.String s) @@ -13,8 +13,7 @@ let value_of_bencode = function | Encoding.Bencode.Tagged ('i', Encoding.Bencode.Int n) -> Ok (Value.Integer n) | _ -> Error (malformed_value ()) -module rec Representation : (Encoding.Record.S with type t = t) = - Encoding.Record.Make (Body) +module rec Representation : (Encoding.Record.S with type t = t) = Encoding.Record.Make (Body) and Body : Encoding.Record.BODY = struct type nonrec t = t @@ -22,24 +21,21 @@ and Body : Encoding.Record.BODY = struct let tag = 'T' let malformed = malformed_value - let fields { type_; attributes } = + let fields {type_; attributes} = [ "type", Encoding.Bencode.String type_; - "attributes", - Encoding.Bencode.Dict - (BatMap.String.enum attributes - |> BatEnum.fold - (fun acc (name, value) -> (name, bencode_of_value value) :: acc) - []) ] + ( "attributes", + Encoding.Bencode.Dict + ( BatMap.String.enum attributes + |> BatEnum.fold (fun acc (name, value) -> (name, bencode_of_value value) :: acc) [] ) ) ] let of_fields data = let open Utilities.Result in let* type_ = Encoding.Bencode.field "type" data |> fmap Encoding.Bencode.as_string in let* kvs = Encoding.Bencode.field "attributes" data |> fmap Encoding.Bencode.as_dict in kvs - |> List.map (fun (name, v) -> value_of_bencode v |> Result.map (fun v -> (name, v))) + |> List.map (fun (name, v) -> value_of_bencode v |> Result.map (fun v -> name, v)) |> Utilities.List.sequence - |> Result.map (fun kvs -> - { type_; attributes = BatMap.String.of_list kvs }) + |> Result.map (fun kvs -> {type_; attributes= BatMap.String.of_list kvs}) end let hash tuple = Representation.to_blob tuple |> Hash.hash_of_blob diff --git a/lib/evaluators/FOL.ml b/lib/evaluators/FOL.ml index eba57a1..4299524 100644 --- a/lib/evaluators/FOL.ml +++ b/lib/evaluators/FOL.ml @@ -9,8 +9,7 @@ module Error = struct condition "evaluation-cancelled" "An evaluation was stopped before it produced its result" empty end -type plan = Base of Protocols.Handle.t - | Project of plan * string BatFingerTree.t +type plan = Base of Protocols.Handle.t | Project of plan * string BatFingerTree.t module Program = Protocols.Program.Make (struct type t = plan @@ -20,21 +19,20 @@ let execute = let open Utilities.Result in function | Base relation_handle -> - Fun.protect - ~finally:(fun () -> Protocols.Handle.release relation_handle) - (fun () -> - let* enumerable = Protocols.Enumerable.require relation_handle in - Protocols.Enumerable.enumerate enumerable) + Fun.protect + ~finally:(fun () -> Protocols.Handle.release relation_handle) + (fun () -> + let* enumerable = Protocols.Enumerable.require relation_handle in + Protocols.Enumerable.enumerate enumerable ) | Project (_plan, _attributes) -> failwith "TODO" -class evaluator = object (self) - inherit Kernel.Lifecycle.null - inherit Kernel.Identity.of_id - - method to_string = "fol-evaluator" - - method invoke = execute - method protocols : Protocols.Handle.protocol list = [Program.make self] -end +class evaluator = + object (self) + inherit Kernel.Lifecycle.null + inherit Kernel.Identity.of_id + method to_string = "fol-evaluator" + method invoke = execute + method protocols : Protocols.Handle.protocol list = [Program.make self] + end let make () = new evaluator |> Protocols.Handle.make diff --git a/lib/evaluators/Lambda.ml b/lib/evaluators/Lambda.ml index 53b0301..d864ca1 100644 --- a/lib/evaluators/Lambda.ml +++ b/lib/evaluators/Lambda.ml @@ -5,13 +5,16 @@ module Error = struct condition "unknown-name" "A term named neither a bound variable nor a relation existing under this snapshot" ("name" |=| Concepts.Value.String name) + let not_applicable () = condition "not-applicable" "A term was applied to an argument, but it denotes a relation rather than an abstraction" empty + let unapplied_abstraction () = condition "unapplied-abstraction" "A program reduced to an abstraction, which names no relation to enumerate" empty + let cancelled () = condition "evaluation-cancelled" "An evaluation was stopped before it produced its result" empty end @@ -20,20 +23,14 @@ end look for a name in the environment first and resolved through the context otherwise, so the relations reachable under the snapshot are the outer environment every program is evaluated on *) -type term = - | Name of string - | Abstract of string * term - | Apply of term * term - +type term = Name of string | Abstract of string * term | Apply of term * term type program = Program of term * Protocols.Directory.t Protocols.Handle.interface module Program = Protocols.Program.Make (struct type t = program end) -type value = - | Relation of Protocols.Handle.t - | Closure of string * term * environment +type value = Relation of Protocols.Handle.t | Closure of string * term * environment and environment = value BatMap.String.t (* let reduce context term = *) @@ -68,21 +65,22 @@ let reduce (Program (term, dir)) = let rec eval env term = match term with | Name name -> - begin - match BatMap.String.find_opt name env with - | Some value -> Ok value - | None -> - let* handle = Directory.find dir name |> fmap (Option.to_result ~none:(Error.unknown_name name)) in - Ok (Relation handle) - end + begin match BatMap.String.find_opt name env with + | Some value -> Ok value + | None -> + let* handle = + Directory.find dir name |> fmap (Option.to_result ~none:(Error.unknown_name name)) + in + Ok (Relation handle) + end | Abstract (binder, body) -> Ok (Closure (binder, body, env)) - | Apply (operator, operand) -> - let* operator = eval env operator in - match operator with - | Relation _ -> Error (Error.not_applicable ()) - | Closure (binder, body, closed) -> - let* argument = eval env operand in - eval (BatMap.String.add binder argument closed) body + | Apply (operator, operand) -> ( + let* operator = eval env operator in + match operator with + | Relation _ -> Error (Error.not_applicable ()) + | Closure (binder, body, closed) -> + let* argument = eval env operand in + eval (BatMap.String.add binder argument closed) body ) in eval BatMap.String.empty term @@ -92,17 +90,16 @@ let execute term = match value with | Closure _ -> Error (Error.unapplied_abstraction ()) | Relation handle -> - let* enumerable = Protocols.Enumerable.require handle in - Protocols.Enumerable.enumerate enumerable + let* enumerable = Protocols.Enumerable.require handle in + Protocols.Enumerable.enumerate enumerable -class evaluator = object (self) - inherit Kernel.Lifecycle.null - inherit Kernel.Identity.of_id - - method to_string = "lambda-evaluator" - - method invoke program = execute program - method protocols : Protocols.Handle.protocol list = [Program.make self] -end +class evaluator = + object (self) + inherit Kernel.Lifecycle.null + inherit Kernel.Identity.of_id + method to_string = "lambda-evaluator" + method invoke program = execute program + method protocols : Protocols.Handle.protocol list = [Program.make self] + end let make () = new evaluator |> Protocols.Handle.make diff --git a/lib/kernel/Branch.ml b/lib/kernel/Branch.ml index 53f6fa1..d398707 100644 --- a/lib/kernel/Branch.ml +++ b/lib/kernel/Branch.ml @@ -7,7 +7,6 @@ module Make (S : Abstract.Storage.STORAGE) = struct *) module SI = Storage.Make (S) - module M = Multigroup.Make (S) module MultigroupM = Merkle.Interface (S) (Merkle.StringKey) (M) module MMDirectory = Prototype.Directory.OfTree (S) (Merkle.StringKey) (M) @@ -18,112 +17,117 @@ module Make (S : Abstract.Storage.STORAGE) = struct open Concepts.Condition let incomplete_branch addr = - condition "incomplete-branch" "A stored branch is missing part of its expected structure. Is your storage corrupted?" + condition "incomplete-branch" + "A stored branch is missing part of its expected structure. Is your storage corrupted?" ("address" |=| Concepts.Value.String (Concepts.Hash.to_hum_string addr)) end - type t = { - multigroups : MultigroupM.address; - previous : t SI.Pointer.t option - } + type t = {multigroups: MultigroupM.address; previous: t SI.Pointer.t option} + + module rec Representation : (Concepts.Encoding.Record.S with type t = t) = + Concepts.Encoding.Record.Make (Body) - module rec Representation : Concepts.Encoding.Record.S with type t = t = Concepts.Encoding.Record.Make (Body) and Body : Concepts.Encoding.Record.BODY = struct type nonrec t = t let tag = 'Y' + let malformed () = - Concepts.Condition. - (condition "malformed-branch" "The on-disk representation of a branch did not conform to what was expected. Is your database corrupted?" - empty) + Concepts.Condition.( + condition "malformed-branch" + "The on-disk representation of a branch did not conform to what was expected. Is your \ + database corrupted?" + empty ) - let fields { multigroups; previous } = + let fields {multigroups; previous} = let open Concepts.Encoding in - ["multigroups", Value.bencode_of_hash multigroups; - "previous", Value.bencode_of_option - (fun v -> SI.Pointer.address_of v - |> SI.as_hash - |> Value.bencode_of_hash) - previous] + [ "multigroups", Value.bencode_of_hash multigroups; + ( "previous", + Value.bencode_of_option + (fun v -> SI.Pointer.address_of v |> SI.as_hash |> Value.bencode_of_hash) + previous ) ] let of_fields fields = let open Utilities.Result in let open Concepts.Encoding in let* multigroups = Bencode.field "multigroups" fields |> fmap Value.hash_of_bencode in - let* previous = Bencode.field "previous" fields - |> fmap (Value.option_of_bencode - (fun v -> Value.hash_of_bencode v - |> Result.map (fun hash -> S.Hash hash) - |> Result.map (SI.Pointer.make Loader.load))) in - Ok { multigroups; previous } + let* previous = + Bencode.field "previous" fields + |> fmap + (Value.option_of_bencode (fun v -> + Value.hash_of_bencode v + |> Result.map (fun hash -> S.Hash hash) + |> Result.map (SI.Pointer.make Loader.load) ) ) + in + Ok {multigroups; previous} end - and Loader : sig val load : (S.transaction -> S.address -> (t, Concepts.Condition.condition) result) end = struct - let load tx addr = - SI.get_req tx addr - |> Utilities.Result.fmap Representation.of_blob + + and Loader : sig + val load : S.transaction -> S.address -> (t, Concepts.Condition.condition) result + end = struct + let load tx addr = SI.get_req tx addr |> Utilities.Result.fmap Representation.of_blob end let pointer_of hash = SI.Pointer.make Loader.load (S.Hash hash) - class branch storage value node = object (self) - inherit Lifecycle.null - - method to_string = "branch" - - val storage : S.connection = storage - val branch : t = value - val node = node (* FIXME: can we not place this inside `t`? *) - - method deriving branch' = - let open Utilities.Result in - let branch'' = { branch' with previous = self#address - |> pointer_of - |> Option.some } in - let* node' = SI.with_transaction storage (fun tx -> - let* _ = SI.store_blob tx (Representation.to_blob branch'') in - MultigroupM.find tx branch'.multigroups - |> fmap (Option.to_result ~none:(Error.incomplete_branch branch'.multigroups))) in - new branch storage branch'' node' |> Protocols.Handle.make |> Result.ok - - method protocols : Protocols.Handle.protocol list = - let open Utilities.Result in - Protocols.[ Addressable.make self; - Prototype.Associative.(of_properties - [ "multigroup", update_only (fun node' -> - Handle.require Addressable.from node' - |> Result.map Addressable.address - |> fmap (fun addr -> self#deriving { branch with multigroups = addr })) ]); - Prototype.Directory.of_properties - [ "multigroup", Prototype.mixture_of node - (fun make node -> - [ MMAddressable.make - ~node:(MultigroupM.into node); - MMDirectory.make - ~storage ~node - ~constructor:(M.wrap storage); - MMAssociative.make - ~storage ~node:(MultigroupM.into node) - ~constructor:(fun node' -> MultigroupM.from node' |> make |> Result.ok) ]) ] ] - - method hash = - Representation.to_blob branch - |> Concepts.Hash.hash_of_blob - - method address = self#hash - end + class branch storage value node = + object (self) + inherit Lifecycle.null + method to_string = "branch" + val storage : S.connection = storage + val branch : t = value + val node = node (* FIXME: can we not place this inside `t`? *) + + method deriving branch' = + let open Utilities.Result in + let branch'' = {branch' with previous= self#address |> pointer_of |> Option.some} in + let* node' = + SI.with_transaction storage (fun tx -> + let* _ = SI.store_blob tx (Representation.to_blob branch'') in + MultigroupM.find tx branch'.multigroups + |> fmap (Option.to_result ~none:(Error.incomplete_branch branch'.multigroups)) ) + in + new branch storage branch'' node' |> Protocols.Handle.make |> Result.ok + + method protocols : Protocols.Handle.protocol list = + let open Utilities.Result in + Protocols. + [ Addressable.make self; + Prototype.Associative.( + of_properties + [ ( "multigroup", + update_only (fun node' -> + Handle.require Addressable.from node' + |> Result.map Addressable.address + |> fmap (fun addr -> self#deriving {branch with multigroups= addr}) ) ) ] ); + Prototype.Directory.of_properties + [ ( "multigroup", + Prototype.mixture_of node (fun make node -> + [ MMAddressable.make ~node:(MultigroupM.into node); + MMDirectory.make ~storage ~node ~constructor:(M.wrap storage); + MMAssociative.make ~storage ~node:(MultigroupM.into node) + ~constructor:(fun node' -> MultigroupM.from node' |> make |> Result.ok ) + ] ) ) ] ] + + method hash = Representation.to_blob branch |> Concepts.Hash.hash_of_blob + method address = self#hash + end let load tx conn addr = let open Utilities.Result in let* data = SI.get_req tx (S.Hash addr) in let* branch = Representation.of_blob data in - let* node = MultigroupM.find tx branch.multigroups |> fmap (Option.to_result ~none:(Error.incomplete_branch branch.multigroups)) in + let* node = + MultigroupM.find tx branch.multigroups + |> fmap (Option.to_result ~none:(Error.incomplete_branch branch.multigroups)) + in Ok (new branch conn branch node |> Protocols.Handle.make) let make conn = let open Utilities.Result in SI.with_transaction conn (fun tx -> let* empty = MultigroupM.empty_under tx in - let branch = { multigroups = empty; previous = None } in + let branch = {multigroups= empty; previous= None} in let* _ = SI.store_blob tx (Representation.to_blob branch) in - Ok (new branch conn branch MultigroupM.empty |> Protocols.Handle.make)) + Ok (new branch conn branch MultigroupM.empty |> Protocols.Handle.make) ) end diff --git a/lib/kernel/Branch.mli b/lib/kernel/Branch.mli index 82bdbb7..c08e781 100644 --- a/lib/kernel/Branch.mli +++ b/lib/kernel/Branch.mli @@ -2,5 +2,10 @@ module Make (S : Abstract.Storage.STORAGE) : sig type t val make : S.connection -> (Protocols.Handle.t, Concepts.Condition.condition) result - val load : S.transaction -> S.connection -> Concepts.Hash.hash -> (Protocols.Handle.t, Concepts.Condition.condition) result + + val load : + S.transaction -> + S.connection -> + Concepts.Hash.hash -> + (Protocols.Handle.t, Concepts.Condition.condition) result end diff --git a/lib/kernel/BranchManager.ml b/lib/kernel/BranchManager.ml index bda4233..3531748 100644 --- a/lib/kernel/BranchManager.ml +++ b/lib/kernel/BranchManager.ml @@ -2,8 +2,10 @@ module Error = struct open Concepts.Condition let invalid_root head = - condition "invalid-root" "The root hash for the database state is missing from the backend. Either your storage is corrupted, or this is a bug in RNT!" - ("hash" |=| (Concepts.Value.String (Concepts.Hash.to_hum_string head))) + condition "invalid-root" + "The root hash for the database state is missing from the backend. Either your storage is \ + corrupted, or this is a bug in RNT!" + ("hash" |=| Concepts.Value.String (Concepts.Hash.to_hum_string head)) end module Make (S : Abstract.Storage.STORAGE) = struct @@ -14,89 +16,90 @@ module Make (S : Abstract.Storage.STORAGE) = struct let root_for tx label = let open Utilities.Result in let* label = S.get tx (S.Label label) in - let data = Option.map (fun blob -> Concepts.Blob.bytes_of_blob blob - |> Bytes.to_string - |> Concepts.Hash.of_raw_string) - label in + let data = + Option.map + (fun blob -> + Concepts.Blob.bytes_of_blob blob |> Bytes.to_string |> Concepts.Hash.of_raw_string ) + label + in Ok data let persist_root tx label addr = let data = Concepts.Hash.blob_of_hash addr in S.put tx (S.Label label) data - class manager storage label head = object (self) - inherit Lifecycle.null - inherit Identity.of_id + class manager storage label head = + object (self) + inherit Lifecycle.null + inherit Identity.of_id + method to_string = "branch-manager" + val storage : S.connection = storage + val label : string = label + val head : M.node Atomic.t = Atomic.make head - method to_string = "branch-manager" + method fetch branch_name = + SI.with_transaction storage (fun tx -> + let head = Atomic.get head in + M.lookup tx branch_name head ) - val storage : S.connection = storage - val label : string = label - val head : M.node Atomic.t = Atomic.make head + method protocols = Protocols.[Directory.make self; Registry.make self] + method list = SI.with_transaction storage (fun tx -> Atomic.get head |> M.keys tx) - method fetch branch_name = - SI.with_transaction storage (fun tx -> - let head = Atomic.get head in - M.lookup tx branch_name head) + method find key = + let open Utilities.Result in + SI.with_transaction storage (fun tx -> + let* head = Atomic.get head |> M.lookup tx key in + match head with + | None -> Ok None + | Some head -> B.load tx storage head |> Result.map Option.some ) - method protocols = Protocols.[Directory.make self; Registry.make self] - - method list = SI.with_transaction storage (fun tx -> Atomic.get head |> M.keys tx) - - method find key = - let open Utilities.Result in - SI.with_transaction storage (fun tx -> - let* head = Atomic.get head |> M.lookup tx key in - match head with - | None -> Ok None - | Some head -> B.load tx storage head |> Result.map Option.some) - - method update key reference value = - let open Utilities.Result in - let open Protocols in - SI.with_transaction storage (fun tx -> - match - Utilities.Atomic.mswap head (fun head -> - let address_of h = - let* i = Handle.require Addressable.from h in - Ok (Addressable.address i) - in - let* branch = M.lookup tx key head |> Result.map_error (fun e -> Some e) in - let* reference = Option.map address_of reference - |> Utilities.Option.sequence - |> Result.map_error (fun e -> Some e) in - let* value = Option.map address_of value - |> Utilities.Option.sequence - |> Result.map_error (fun e -> Some e) in - if branch = reference then - begin - let* new_head = match value with - | Some value -> M.insert tx key value head - | None -> M.remove tx key head - in - let* _ = persist_root tx label (M.hash_of new_head) in - Ok new_head - end - |> Result.map_error (fun e -> Some e) - else - Error None) - with - | Ok _ -> Ok true - | Error None -> Ok false - | Error (Some e) -> Error e) - - end + method update key reference value = + let open Utilities.Result in + let open Protocols in + SI.with_transaction storage (fun tx -> + match + Utilities.Atomic.mswap head (fun head -> + let address_of h = + let* i = Handle.require Addressable.from h in + Ok (Addressable.address i) + in + let* branch = M.lookup tx key head |> Result.map_error (fun e -> Some e) in + let* reference = + Option.map address_of reference + |> Utilities.Option.sequence + |> Result.map_error (fun e -> Some e) + in + let* value = + Option.map address_of value + |> Utilities.Option.sequence + |> Result.map_error (fun e -> Some e) + in + if branch = reference then + begin + let* new_head = + match value with + | Some value -> M.insert tx key value head + | None -> M.remove tx key head + in + let* _ = persist_root tx label (M.hash_of new_head) in + Ok new_head + end + |> Result.map_error (fun e -> Some e) + else Error None ) + with + | Ok _ -> Ok true + | Error None -> Ok false + | Error (Some e) -> Error e ) + end let make storage label = let open Utilities.Result in SI.with_transaction storage (fun tx -> let* addr = root_for tx label in match addr with - | None -> - Ok (new manager storage label M.empty |> Protocols.Handle.make) + | None -> Ok (new manager storage label M.empty |> Protocols.Handle.make) | Some addr -> - let* head = M.find tx addr in - let* head = Option.to_result ~none:(Error.invalid_root addr) head in - Ok (new manager storage label head |> Protocols.Handle.make)) - + let* head = M.find tx addr in + let* head = Option.to_result ~none:(Error.invalid_root addr) head in + Ok (new manager storage label head |> Protocols.Handle.make) ) end diff --git a/lib/kernel/EphemeralRelation.ml b/lib/kernel/EphemeralRelation.ml index b403e13..8aa0463 100644 --- a/lib/kernel/EphemeralRelation.ml +++ b/lib/kernel/EphemeralRelation.ml @@ -41,7 +41,7 @@ module Make (D : DERIVATION) = struct method generate binding = D.generate plan binding |> Result.map (fun cursor -> - new Lifecycle.retaining cursor (self :> Lifecycle.lifecycle) |> Protocols.Handle.make ) + new Lifecycle.retaining cursor (self :> Lifecycle.lifecycle) |> Protocols.Handle.make ) method enumerate = self#generate Protocols.Generative.nothing method describe () = Ok (Protocols.Schematics.Relation description) diff --git a/lib/kernel/Generator.ml b/lib/kernel/Generator.ml index 204699f..272bb86 100644 --- a/lib/kernel/Generator.ml +++ b/lib/kernel/Generator.ml @@ -5,8 +5,8 @@ type step = | Finished of (unit, Concepts.Condition.condition) result let start produce = - try Finished (produce ~yield:(fun tuple -> Effect.perform (Yield tuple))) with - | effect (Yield tuple), k -> Element (tuple, k) + try Finished (produce ~yield:(fun tuple -> Effect.perform (Yield tuple))) + with effect Yield tuple, k -> Element (tuple, k) let resume k = Effect.Deep.continue k () @@ -14,9 +14,7 @@ class producer_cursor produce finally = object (self) inherit Lifecycle.null inherit Identity.of_id - method to_string = "producer-cursor" - val mutable state : [`Fresh | `Live of (unit, step) Effect.Deep.continuation | `Done] = `Fresh method protocols : Protocols.Handle.protocol list = Protocols.[Cursor.make self] @@ -48,12 +46,10 @@ class producer_cursor produce finally = | None -> Ok Protocols.Cursor.{tuples; exhausted= true} | Some tuple -> fill (taken + 1) (BatFingerTree.snoc tuples tuple) in - if limit <= 0 then - Ok Protocols.Cursor.{tuples= BatFingerTree.empty; exhausted= (state = `Done)} + if limit <= 0 then Ok Protocols.Cursor.{tuples= BatFingerTree.empty; exhausted= state = `Done} else fill 0 BatFingerTree.empty method! release = match state with `Fresh | `Live _ -> self#finish | `Done -> () end -let cursor_of ?finally produce = - new producer_cursor produce finally |> Protocols.Handle.make +let cursor_of ?finally produce = new producer_cursor produce finally |> Protocols.Handle.make diff --git a/lib/kernel/Identity.ml b/lib/kernel/Identity.ml index ce3d30c..2205958 100644 --- a/lib/kernel/Identity.ml +++ b/lib/kernel/Identity.ml @@ -2,6 +2,7 @@ class type identity = object method hash : Concepts.Hash.hash end -class of_id = object (self) - method hash = Oo.id self |> Concepts.Hash.hash_of_int -end +class of_id = + object (self) + method hash = Oo.id self |> Concepts.Hash.hash_of_int + end diff --git a/lib/kernel/Initialization.ml b/lib/kernel/Initialization.ml index ae041fc..25c2b3d 100644 --- a/lib/kernel/Initialization.ml +++ b/lib/kernel/Initialization.ml @@ -14,7 +14,7 @@ module Make (S : Abstract.Storage.STORAGE) = struct List.fold_left (fun acc (name, handle) -> let* _ = acc in - Registry.update evaluator_registry name None (Some handle)) + Registry.update evaluator_registry name None (Some handle) ) (Ok true) evaluators in let* _ = Registry.update registry "evaluator" None (Some evaluator_namespace) in diff --git a/lib/kernel/Lifecycle.ml b/lib/kernel/Lifecycle.ml index 772cb6e..bf0b544 100644 --- a/lib/kernel/Lifecycle.ml +++ b/lib/kernel/Lifecycle.ml @@ -8,33 +8,25 @@ class type virtual controlled_lifecycle = object method virtual destroy : unit end -class null = object - method reference = true - method release = () -end - -class virtual counted = object (self) - val references = Atomic.make 1 - - method virtual destroy : unit - - method reference = - Atomic.incr references; - true - - method release = - if Atomic.fetch_and_add references (-1) = 1 then - self#destroy -end - -class retaining inner (owner : lifecycle) = object - inherit counted - initializer ignore owner#reference - - method destroy = - Protocols.Handle.release inner; - owner#release - - method hash = Protocols.Handle.hash inner - method protocols = Protocols.Handle.protocols inner -end +class null = + object + method reference = true + method release = () + end + +class virtual counted = + object (self) + val references = Atomic.make 1 + method virtual destroy : unit + method reference = Atomic.incr references; true + method release = if Atomic.fetch_and_add references (-1) = 1 then self#destroy + end + +class retaining inner (owner : lifecycle) = + object + inherit counted + initializer ignore owner#reference + method destroy = Protocols.Handle.release inner; owner#release + method hash = Protocols.Handle.hash inner + method protocols = Protocols.Handle.protocols inner + end diff --git a/lib/kernel/Merkle.ml b/lib/kernel/Merkle.ml index fc076ac..af5b19f 100644 --- a/lib/kernel/Merkle.ml +++ b/lib/kernel/Merkle.ml @@ -13,234 +13,238 @@ end module type TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> sig type address = Concepts.Hash.hash - type node - val with_batch: S.transaction -> (unit -> (node, Concepts.Condition.condition) result) -> (node, Concepts.Condition.condition) result + val with_batch : + S.transaction -> + (unit -> (node, Concepts.Condition.condition) result) -> + (node, Concepts.Condition.condition) result val find : S.transaction -> address -> (node option, Concepts.Condition.condition) result val persist : S.transaction -> node -> (address, Concepts.Condition.condition) result - val empty : node val empty_under : S.transaction -> (address, Concepts.Condition.condition) result - val hash_of : node -> address - val insert : S.transaction -> K.t -> address -> node -> (node, Concepts.Condition.condition) result + val insert : + S.transaction -> K.t -> address -> node -> (node, Concepts.Condition.condition) result + val remove : S.transaction -> K.t -> node -> (node, Concepts.Condition.condition) result val lookup : S.transaction -> K.t -> node -> (address option, Concepts.Condition.condition) result - val fold_left : S.transaction -> ('c -> K.t -> address -> 'c) -> 'c -> node -> ('c, Concepts.Condition.condition) result + val fold_left : + S.transaction -> + ('c -> K.t -> address -> 'c) -> + 'c -> + node -> + ('c, Concepts.Condition.condition) result + val keys : S.transaction -> node -> (K.t BatFingerTree.t, Concepts.Condition.condition) result end -module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct - type address = Concepts.Hash.hash +module Make : TREE = +functor + (S : Abstract.Storage.STORAGE) + (K : KEY) + -> + struct + type address = Concepts.Hash.hash - module Error = struct - open Concepts.Condition + module Error = struct + open Concepts.Condition - let malformed_node () = condition "malformed-node" "A node representation did not conform to what was expected" empty - end + let malformed_node () = + condition "malformed-node" "A node representation did not conform to what was expected" + empty + end - type node = - Leaf of - { keys : K.t BatFingerTree.t; - values : address BatFingerTree.t } - | Trunk of - { keys : K.t BatFingerTree.t; - children : address BatFingerTree.t } - - let empty = Leaf { keys = BatFingerTree.empty; values = BatFingerTree.empty } - - let rec lookup1' keys key bottom top = - let open Utilities.Ordering in - if bottom >= top then (bottom, false) - else - let mid = bottom + (top - bottom) / 2 in - let node = BatFingerTree.get keys mid in - match K.compare node key with - | Equal -> (mid, true) - | Greater -> lookup1' keys key bottom mid - | Smaller -> lookup1' keys key (mid + 1) top - - let lookup1 keys key = lookup1' keys key 0 (BatFingerTree.size keys) - - let keys_of = function - | Leaf { keys; _ } -> keys - | Trunk { keys; _ } -> keys - - let of_bencode = - let open Concepts.Encoding.Bencode in - let open Utilities.Result in - (* This is terrible *) - let decode_key t = as_string t - |> Result.map String.to_bytes - |> Result.map Concepts.Blob.blob_of_bytes - |> fmap K.decode in - let decode_value t = as_string t |> Result.map Concepts.Hash.of_raw_string in - let decode_list f data = data - |> fmap as_list - |> Result.map (List.map f) - |> fmap Utilities.List.sequence - |> Result.map BatFingerTree.of_list in - function - | Tagged ('!', (Dict _ as data)) -> - let* keys = field "keys" data |> decode_list decode_key in - let* values = field "values" data |> decode_list decode_value in - Ok (Leaf { keys; values }) - | Tagged ('#', (Dict _ as data)) -> - let* keys = field "keys" data |> decode_list decode_key in - let* children = field "children" data |> decode_list decode_value in - Ok (Trunk { keys; children }) - | _ -> Error (Error.malformed_node ()) - - let from_blob blob = Concepts.Encoding.Bencode.of_blob blob - |> Utilities.Result.fmap of_bencode - - let to_bencode = - let open Concepts.Encoding.Bencode in - (* Ditto. *) - let bencode_key k = K.encode k - |> Concepts.Blob.bytes_of_blob - |> String.of_bytes - |> (fun s -> String s) in - let bencode_hash h = String (Concepts.Hash.to_raw_string h) in - function - | Leaf { keys; values } -> - Tagged ('!', Dict [("keys", List (BatFingerTree.to_list keys |> List.map bencode_key)); - ("values", List (BatFingerTree.to_list values |> List.map bencode_hash))]) - | Trunk { keys; children } -> - Tagged ('#', Dict [("keys", List (BatFingerTree.to_list keys |> List.map bencode_key)); - ("children", List (BatFingerTree.to_list children |> List.map bencode_hash))]) - - let to_blob node = to_bencode node |> Concepts.Encoding.Bencode.to_blob - - (* TODO: we should probably cache this inside the node itself rather + type node = + | Leaf of {keys: K.t BatFingerTree.t; values: address BatFingerTree.t} + | Trunk of {keys: K.t BatFingerTree.t; children: address BatFingerTree.t} + + let empty = Leaf {keys= BatFingerTree.empty; values= BatFingerTree.empty} + + let rec lookup1' keys key bottom top = + let open Utilities.Ordering in + if bottom >= top then bottom, false + else + let mid = bottom + ((top - bottom) / 2) in + let node = BatFingerTree.get keys mid in + match K.compare node key with + | Equal -> mid, true + | Greater -> lookup1' keys key bottom mid + | Smaller -> lookup1' keys key (mid + 1) top + + let lookup1 keys key = lookup1' keys key 0 (BatFingerTree.size keys) + let keys_of = function Leaf {keys; _} -> keys | Trunk {keys; _} -> keys + + let of_bencode = + let open Concepts.Encoding.Bencode in + let open Utilities.Result in + (* This is terrible *) + let decode_key t = + as_string t + |> Result.map String.to_bytes + |> Result.map Concepts.Blob.blob_of_bytes + |> fmap K.decode + in + let decode_value t = as_string t |> Result.map Concepts.Hash.of_raw_string in + let decode_list f data = + data + |> fmap as_list + |> Result.map (List.map f) + |> fmap Utilities.List.sequence + |> Result.map BatFingerTree.of_list + in + function + | Tagged ('!', (Dict _ as data)) -> + let* keys = field "keys" data |> decode_list decode_key in + let* values = field "values" data |> decode_list decode_value in + Ok (Leaf {keys; values}) + | Tagged ('#', (Dict _ as data)) -> + let* keys = field "keys" data |> decode_list decode_key in + let* children = field "children" data |> decode_list decode_value in + Ok (Trunk {keys; children}) + | _ -> Error (Error.malformed_node ()) + + let from_blob blob = Concepts.Encoding.Bencode.of_blob blob |> Utilities.Result.fmap of_bencode + + let to_bencode = + let open Concepts.Encoding.Bencode in + (* Ditto. *) + let bencode_key k = + K.encode k |> Concepts.Blob.bytes_of_blob |> String.of_bytes |> fun s -> String s + in + let bencode_hash h = String (Concepts.Hash.to_raw_string h) in + function + | Leaf {keys; values} -> + Tagged + ( '!', + Dict + [ "keys", List (BatFingerTree.to_list keys |> List.map bencode_key); + "values", List (BatFingerTree.to_list values |> List.map bencode_hash) ] ) + | Trunk {keys; children} -> + Tagged + ( '#', + Dict + [ "keys", List (BatFingerTree.to_list keys |> List.map bencode_key); + "children", List (BatFingerTree.to_list children |> List.map bencode_hash) ] ) + + let to_blob node = to_bencode node |> Concepts.Encoding.Bencode.to_blob + + (* TODO: we should probably cache this inside the node itself rather than recalculating it every time. We could also allow the user to create "uninterned" nodes that are not storage-backed, that could be used for intermediates and the like. *) - let hash_of node = to_blob node |> Concepts.Hash.hash_of_blob - - type _ Effect.t += Intern: (address * node * Concepts.Blob.t) -> unit Effect.t | Retrieve: address -> (node * Concepts.Blob.t) option Effect.t - - let rec flush tx buffer addr = - let open Utilities.Result in - match BatMap.find_opt addr buffer with - | None -> Ok () - | Some (node, data) -> - let* _ = S.put tx (S.Hash addr) data in - match node with - | Leaf _ -> Ok () - | Trunk { children; _ } -> - BatFingerTree.map (fun addr -> flush tx buffer addr) children - |> Utilities.FingerTree.sequence - |> Result.map ignore - - let with_batch tx f = - let open Utilities.Result in - let buffer = ref BatMap.empty in - try - let* node = f () in - let* _ = flush tx !buffer (hash_of node) in - Ok node - with - | effect (Intern (addr, node, data)), k -> - buffer := BatMap.add addr (node, data) !buffer; - Effect.Deep.continue k () - | effect (Retrieve addr), k -> - Effect.Deep.continue k (BatMap.find_opt addr !buffer) - - let find tx addr = - let open Utilities.Result in - try Effect.perform (Retrieve addr) |> Option.map fst |> Result.ok - with - | Effect.Unhandled _ -> - let* data = S.get tx (S.Hash addr) in - match data with - | None -> Ok None - | Some data -> - let* node = from_blob data in - Ok (Some node) - - let persist tx node = - let data = to_blob node in - let addr = Concepts.Hash.hash_of_blob data in - begin - try Ok (Effect.perform (Intern (addr, node, data))) + let hash_of node = to_blob node |> Concepts.Hash.hash_of_blob + + type _ Effect.t += + | Intern : (address * node * Concepts.Blob.t) -> unit Effect.t + | Retrieve : address -> (node * Concepts.Blob.t) option Effect.t + + let rec flush tx buffer addr = + let open Utilities.Result in + match BatMap.find_opt addr buffer with + | None -> Ok () + | Some (node, data) -> ( + let* _ = S.put tx (S.Hash addr) data in + match node with + | Leaf _ -> Ok () + | Trunk {children; _} -> + BatFingerTree.map (fun addr -> flush tx buffer addr) children + |> Utilities.FingerTree.sequence + |> Result.map ignore ) + + let with_batch tx f = + let open Utilities.Result in + let buffer = ref BatMap.empty in + try + let* node = f () in + let* _ = flush tx !buffer (hash_of node) in + Ok node with - | Effect.Unhandled _ -> - S.put tx (S.Hash addr) data - end - |> Result.map (fun () -> addr) - - let find' tx addr = - let open Utilities.Result in - let* child = find tx addr in - match child with - | Some child -> Ok child - | None -> failwith "A child node was not found on the underlying storage. Either your database is corrupted, or this is a bug on RNT!" - - let rec lookup tx key node = - let open Utilities.Result in - let i, found = lookup1 (keys_of node) key in - match node with - | Leaf { values; _ } -> - if found then Ok (Some (BatFingerTree.get values i)) else Ok None - | Trunk { children; _ } -> - let* child = BatFingerTree.get children (if found then i+1 else i) |> find' tx in - lookup tx key child - - let empty_under tx = persist tx empty - - type op = Update of address * node | Split of address * K.t * address - - let emplace i v ft = - let size = BatFingerTree.size ft in - if i < 0 || i > size then - invalid_arg "Merkle.emplace: index out of bounds" - else if size = 0 then - BatFingerTree.singleton v - else if i = size then - BatFingerTree.snoc ft v - else - let fl, fr = BatFingerTree.split_at ft i in - BatFingerTree.singleton v - |> BatFingerTree.append fl - |> (Fun.flip BatFingerTree.append) fr - - let insert1 key value node = - let i, present = lookup1 (keys_of node) key in - match node with - | Leaf ({ keys; values } as leaf) -> - if present then - Leaf { leaf with values = BatFingerTree.set values i value } - else - Leaf { keys = emplace i key keys; values = emplace i value values } - (* When in danger or in doubt: run in circles, scream and shout. *) - | Trunk _ -> failwith "Cannot insert a value on a trunk node. This is a bug in RNT!" - - let pivot_at ft i = - let l, r' = BatFingerTree.split_at ft i in - let r, p = BatFingerTree.front_exn r' in - l, p, r - - let split_at pivot = function - | Leaf { keys; values } -> - let kl, kr = BatFingerTree.split_at keys pivot in - let vl, vr = BatFingerTree.split_at values pivot in - let p = BatFingerTree.get kr 0 in - Leaf { keys = kl; values = vl }, - p, - Leaf { keys = kr; values = vr } - | Trunk { keys; children } -> - let kl, kp, kr = pivot_at keys pivot in - let cl, cr = BatFingerTree.split_at children (pivot + 1) in - Trunk { keys = kl; children = cl }, - kp, - Trunk { keys = kr; children = cr } - - (* FIXME: this works out to a geometric distribution with roughly 64 + | effect Intern (addr, node, data), k -> + buffer := BatMap.add addr (node, data) !buffer; + Effect.Deep.continue k () + | effect Retrieve addr, k -> Effect.Deep.continue k (BatMap.find_opt addr !buffer) + + let find tx addr = + let open Utilities.Result in + try Effect.perform (Retrieve addr) |> Option.map fst |> Result.ok + with Effect.Unhandled _ -> ( + let* data = S.get tx (S.Hash addr) in + match data with + | None -> Ok None + | Some data -> + let* node = from_blob data in + Ok (Some node) ) + + let persist tx node = + let data = to_blob node in + let addr = Concepts.Hash.hash_of_blob data in + begin try Ok (Effect.perform (Intern (addr, node, data))) + with Effect.Unhandled _ -> S.put tx (S.Hash addr) data + end + |> Result.map (fun () -> addr) + + let find' tx addr = + let open Utilities.Result in + let* child = find tx addr in + match child with + | Some child -> Ok child + | None -> + failwith + "A child node was not found on the underlying storage. Either your database is \ + corrupted, or this is a bug on RNT!" + + let rec lookup tx key node = + let open Utilities.Result in + let i, found = lookup1 (keys_of node) key in + match node with + | Leaf {values; _} -> if found then Ok (Some (BatFingerTree.get values i)) else Ok None + | Trunk {children; _} -> + let* child = BatFingerTree.get children (if found then i + 1 else i) |> find' tx in + lookup tx key child + + let empty_under tx = persist tx empty + + type op = Update of address * node | Split of address * K.t * address + + let emplace i v ft = + let size = BatFingerTree.size ft in + if i < 0 || i > size then invalid_arg "Merkle.emplace: index out of bounds" + else if size = 0 then BatFingerTree.singleton v + else if i = size then BatFingerTree.snoc ft v + else + let fl, fr = BatFingerTree.split_at ft i in + BatFingerTree.singleton v |> BatFingerTree.append fl |> (Fun.flip BatFingerTree.append) fr + + let insert1 key value node = + let i, present = lookup1 (keys_of node) key in + match node with + | Leaf ({keys; values} as leaf) -> + if present then Leaf {leaf with values= BatFingerTree.set values i value} + else Leaf {keys= emplace i key keys; values= emplace i value values} + (* When in danger or in doubt: run in circles, scream and shout. *) + | Trunk _ -> failwith "Cannot insert a value on a trunk node. This is a bug in RNT!" + + let pivot_at ft i = + let l, r' = BatFingerTree.split_at ft i in + let r, p = BatFingerTree.front_exn r' in + l, p, r + + let split_at pivot = function + | Leaf {keys; values} -> + let kl, kr = BatFingerTree.split_at keys pivot in + let vl, vr = BatFingerTree.split_at values pivot in + let p = BatFingerTree.get kr 0 in + Leaf {keys= kl; values= vl}, p, Leaf {keys= kr; values= vr} + | Trunk {keys; children} -> + let kl, kp, kr = pivot_at keys pivot in + let cl, cr = BatFingerTree.split_at children (pivot + 1) in + Trunk {keys= kl; children= cl}, kp, Trunk {keys= kr; children= cr} + + (* FIXME: this works out to a geometric distribution with roughly 64 keys per node. Some of the consequences of this are that: - most of our nodes will end up with one or a few elements, which would make our trees taller than they would normally need to be @@ -251,98 +255,94 @@ module Make : TREE = functor (S : Abstract.Storage.STORAGE) (K : KEY) -> struct node size. See https://www.dolthub.com/docs/architecture/storage-engine/prolly-tree/#controlling-chunk-size *) - let should_split = Concepts.Hash.pick 6 - - let hash_of_keys ks = - let buffer = Buffer.create 1024 in - BatFingerTree.iter - (fun k -> - K.encode k - |> Concepts.Blob.bytes_of_blob - |> Buffer.add_bytes buffer) - ks; - Concepts.Hash.hash_of_bytes (Buffer.to_bytes buffer) - - let split_position keys = - let rec loop left right = - match BatFingerTree.front right with - | None -> None - | Some (tail, head) -> - (* TODO: rolling hash *) - let left' = BatFingerTree.snoc left head in - let hash = hash_of_keys left' in - if should_split hash then - Some (BatFingerTree.size left) - else - loop left' tail - in - loop BatFingerTree.empty keys - - let commit_node tx node = - let open Utilities.Result in - match split_position (keys_of node) with - | Some i -> - let l, p, r = split_at i node in - let* l_addr = persist tx l in - let* r_addr = persist tx r in - Ok (Split (l_addr, p, r_addr)) - | None -> - let* addr = persist tx node in - Ok (Update (addr, node)) - - let rec insert' tx key value node = - let open Utilities.Result in - match node with - | Leaf _ -> - insert1 key value node - |> commit_node tx - | Trunk { keys; children } -> - let i, found = lookup1 keys key in - let i = if found then i+1 else i in - let* child = BatFingerTree.get children i |> find' tx in - let* r = insert' tx key value child in - match r with - | Update (addr, _) -> - Trunk { keys; children = BatFingerTree.set children i addr } - |> commit_node tx - | Split (l, p, r) -> - Trunk { keys = emplace i p keys; - children = BatFingerTree.set children i l |> emplace (i + 1) r } - |> commit_node tx - - let insert tx key value node = - let open Utilities.Result in - let* op = insert' tx key value node in - match op with - | Update (_, node) -> Ok node - | Split (l, p, r) -> - let new_root = - Trunk { keys = BatFingerTree.singleton p; - children = BatFingerTree.empty - |> (Fun.flip BatFingerTree.snoc) l - |> (Fun.flip BatFingerTree.snoc) r } in - let* _ = persist tx new_root in - Ok new_root - - let remove tx key node = failwith "TODO" [@@warning "-27"] - - let rec fold_left tx f acc = - let open Utilities.Result in - function - | Leaf { keys; values } -> - Utilities.FingerTree.zip keys values - |> BatFingerTree.fold_left (fun acc (k, v) -> f acc k v) acc - |> Result.ok - | Trunk { children; _ } -> - BatFingerTree.fold_left - (fun acc addr -> - let* acc = acc in - let* node = find' tx addr in - fold_left tx f acc node) - (Ok acc) children - - let keys tx node = fold_left tx (fun acc k _ -> BatFingerTree.snoc acc k) BatFingerTree.empty node -end + let should_split = Concepts.Hash.pick 6 + + let hash_of_keys ks = + let buffer = Buffer.create 1024 in + BatFingerTree.iter + (fun k -> K.encode k |> Concepts.Blob.bytes_of_blob |> Buffer.add_bytes buffer) + ks; + Concepts.Hash.hash_of_bytes (Buffer.to_bytes buffer) + + let split_position keys = + let rec loop left right = + match BatFingerTree.front right with + | None -> None + | Some (tail, head) -> + (* TODO: rolling hash *) + let left' = BatFingerTree.snoc left head in + let hash = hash_of_keys left' in + if should_split hash then Some (BatFingerTree.size left) else loop left' tail + in + loop BatFingerTree.empty keys + + let commit_node tx node = + let open Utilities.Result in + match split_position (keys_of node) with + | Some i -> + let l, p, r = split_at i node in + let* l_addr = persist tx l in + let* r_addr = persist tx r in + Ok (Split (l_addr, p, r_addr)) + | None -> + let* addr = persist tx node in + Ok (Update (addr, node)) + + let rec insert' tx key value node = + let open Utilities.Result in + match node with + | Leaf _ -> insert1 key value node |> commit_node tx + | Trunk {keys; children} -> ( + let i, found = lookup1 keys key in + let i = if found then i + 1 else i in + let* child = BatFingerTree.get children i |> find' tx in + let* r = insert' tx key value child in + match r with + | Update (addr, _) -> + Trunk {keys; children= BatFingerTree.set children i addr} |> commit_node tx + | Split (l, p, r) -> + Trunk + { keys= emplace i p keys; + children= BatFingerTree.set children i l |> emplace (i + 1) r } + |> commit_node tx ) + + let insert tx key value node = + let open Utilities.Result in + let* op = insert' tx key value node in + match op with + | Update (_, node) -> Ok node + | Split (l, p, r) -> + let new_root = + Trunk + { keys= BatFingerTree.singleton p; + children= + BatFingerTree.empty + |> (Fun.flip BatFingerTree.snoc) l + |> (Fun.flip BatFingerTree.snoc) r } + in + let* _ = persist tx new_root in + Ok new_root + + let remove tx key node = failwith "TODO" [@@warning "-27"] + + let rec fold_left tx f acc = + let open Utilities.Result in + function + | Leaf {keys; values} -> + Utilities.FingerTree.zip keys values + |> BatFingerTree.fold_left (fun acc (k, v) -> f acc k v) acc + |> Result.ok + | Trunk {children; _} -> + BatFingerTree.fold_left + (fun acc addr -> + let* acc = acc in + let* node = find' tx addr in + fold_left tx f acc node ) + (Ok acc) children + + let keys tx node = + fold_left tx (fun acc k _ -> BatFingerTree.snoc acc k) BatFingerTree.empty node + end module type INTERFACE = functor (S : Abstract.Storage.STORAGE) (K : KEY) (V : VALUE) -> sig module Tree : module type of Make (S) (K) @@ -350,83 +350,90 @@ module type INTERFACE = functor (S : Abstract.Storage.STORAGE) (K : KEY) (V : VA type address = Concepts.Hash.hash type node - val with_batch: S.transaction -> (unit -> (node, Concepts.Condition.condition) result) -> (node, Concepts.Condition.condition) result + val with_batch : + S.transaction -> + (unit -> (node, Concepts.Condition.condition) result) -> + (node, Concepts.Condition.condition) result val find : S.transaction -> address -> (node option, Concepts.Condition.condition) result val from : Tree.node -> node val into : node -> Tree.node - val empty : node val empty_under : S.transaction -> (address, Concepts.Condition.condition) result - val hash_of : node -> address - val insert : S.transaction -> K.t -> V.t -> node -> (node, Concepts.Condition.condition) result val remove : S.transaction -> K.t -> node -> (node, Concepts.Condition.condition) result val lookup : S.transaction -> K.t -> node -> (V.t option, Concepts.Condition.condition) result val mem : S.transaction -> K.t -> node -> (bool, Concepts.Condition.condition) result - val fold_left : S.transaction -> ('c -> K.t -> V.t -> 'c) -> 'c -> node -> ('c, Concepts.Condition.condition) result - val iter : S.transaction -> (K.t -> V.t -> 'a) -> node -> (unit, Concepts.Condition.condition) result - val keys : S.transaction -> node -> (K.t BatFingerTree.t, Concepts.Condition.condition) result -end - -module Interface : INTERFACE = functor (S : Abstract.Storage.STORAGE) (K : KEY) (V : VALUE) -> struct - module Tree = Make (S) (K) - module SI = Storage.Make (S) - - type address = Tree.address - type node = Tree.node - - open Utilities.Result - - let intern tx v = - let data = V.encode v in - let addr = Concepts.Hash.hash_of_blob data in - let* () = S.put tx (S.Hash addr) data in - Ok addr - - let retrieve tx addr = SI.get_req tx (S.Hash addr) |> fmap V.decode - - let find = Tree.find - let from x = x - let into x = x - let empty = Tree.empty - let empty_under = Tree.empty_under - let hash_of = Tree.hash_of - let with_batch = Tree.with_batch - - let insert tx k v node = - let* addr = intern tx v in - Tree.insert tx k addr node + val fold_left : + S.transaction -> + ('c -> K.t -> V.t -> 'c) -> + 'c -> + node -> + ('c, Concepts.Condition.condition) result - let remove = Tree.remove + val iter : + S.transaction -> (K.t -> V.t -> 'a) -> node -> (unit, Concepts.Condition.condition) result - let lookup tx k node = - let* addr = Tree.lookup tx k node in - match addr with - | None -> Ok None - | Some addr -> retrieve tx addr |> Result.map Option.some - - let mem tx k node = Tree.lookup tx k node |> Result.map Option.is_some - - let fold_left tx f acc node = - Tree.fold_left tx - (fun acc k addr -> - let* acc = acc in - let* v = retrieve tx addr in - Ok (f acc k v)) - (Ok acc) node - |> Result.join - - let iter tx f node = - fold_left tx - (fun _ k v -> f k v |> ignore) - () node - - let keys = Tree.keys + val keys : S.transaction -> node -> (K.t BatFingerTree.t, Concepts.Condition.condition) result end +module Interface : INTERFACE = +functor + (S : Abstract.Storage.STORAGE) + (K : KEY) + (V : VALUE) + -> + struct + module Tree = Make (S) (K) + module SI = Storage.Make (S) + + type address = Tree.address + type node = Tree.node + + open Utilities.Result + + let intern tx v = + let data = V.encode v in + let addr = Concepts.Hash.hash_of_blob data in + let* () = S.put tx (S.Hash addr) data in + Ok addr + + let retrieve tx addr = SI.get_req tx (S.Hash addr) |> fmap V.decode + let find = Tree.find + let from x = x + let into x = x + let empty = Tree.empty + let empty_under = Tree.empty_under + let hash_of = Tree.hash_of + let with_batch = Tree.with_batch + + let insert tx k v node = + let* addr = intern tx v in + Tree.insert tx k addr node + + let remove = Tree.remove + + let lookup tx k node = + let* addr = Tree.lookup tx k node in + match addr with None -> Ok None | Some addr -> retrieve tx addr |> Result.map Option.some + + let mem tx k node = Tree.lookup tx k node |> Result.map Option.is_some + + let fold_left tx f acc node = + Tree.fold_left tx + (fun acc k addr -> + let* acc = acc in + let* v = retrieve tx addr in + Ok (f acc k v) ) + (Ok acc) node + |> Result.join + + let iter tx f node = fold_left tx (fun _ k v -> f k v |> ignore) () node + let keys = Tree.keys + end + module StringKey : KEY with type t = string = struct type t = string diff --git a/lib/kernel/Multigroup.ml b/lib/kernel/Multigroup.ml index c8ffa62..602f3a9 100644 --- a/lib/kernel/Multigroup.ml +++ b/lib/kernel/Multigroup.ml @@ -1,30 +1,36 @@ module Make (S : Abstract.Storage.STORAGE) = struct module SI = Storage.Make (S) - module R = SubstantialRelation.Make (S) module RelationM = Merkle.Interface (S) (Merkle.StringKey) (R) module RMDirectory = Prototype.Directory.OfTree (S) (Merkle.StringKey) (R) - type t = { relations : RelationM.address } + type t = {relations: RelationM.address} module Error = struct open Concepts.Condition - let malformed_multigroup () = condition "malformed-multigroup" "The on-disk representation of a multigroup did not conform to what was expected. Is your database corrupted?" - empty + let malformed_multigroup () = + condition "malformed-multigroup" + "The on-disk representation of a multigroup did not conform to what was expected. Is your \ + database corrupted?" + empty - let incomplete_multigroup addr = condition "incomplete-multigroup" "A stored multigroup is missing part of its expected structure. Is your storage corrupted?" - ("address" |=| Concepts.Value.String (Concepts.Hash.to_hum_string addr)) + let incomplete_multigroup addr = + condition "incomplete-multigroup" + "A stored multigroup is missing part of its expected structure. Is your storage corrupted?" + ("address" |=| Concepts.Value.String (Concepts.Hash.to_hum_string addr)) end - module rec Representation : Concepts.Encoding.Record.S with type t = t = Concepts.Encoding.Record.Make (Body) + module rec Representation : (Concepts.Encoding.Record.S with type t = t) = + Concepts.Encoding.Record.Make (Body) + and Body : Concepts.Encoding.Record.BODY = struct type nonrec t = t let tag = '*' let malformed = Error.malformed_multigroup - let fields { relations } = + let fields {relations} = let open Concepts.Encoding in ["relations", Value.bencode_of_hash relations] @@ -32,47 +38,45 @@ module Make (S : Abstract.Storage.STORAGE) = struct let open Utilities.Result in let open Concepts.Encoding in let* relations = Bencode.field "relations" fields |> fmap Value.hash_of_bencode in - Ok { relations } + Ok {relations} end let encode = Representation.to_blob let decode = Representation.of_blob - class multigroup conn value node = object (self) - inherit Lifecycle.null - - method to_string = "multigroup" - - val multigroup = value - val storage = conn - val node = node (* FIXME: see the comment on Branch.ml *) - - method protocols : Protocols.Handle.protocol list = - Protocols.[ Addressable.make self; - Prototype.Directory.of_properties - [ "relation", Prototype.mixture - [ RMDirectory.make - ~storage ~node - ~constructor:(R.wrap storage) ] ] ] - - method hash = - Representation.to_blob multigroup - |> Concepts.Hash.hash_of_blob - - method address = self#hash - end + class multigroup conn value node = + object (self) + inherit Lifecycle.null + method to_string = "multigroup" + val multigroup = value + val storage = conn + val node = node (* FIXME: see the comment on Branch.ml *) + + method protocols : Protocols.Handle.protocol list = + Protocols. + [ Addressable.make self; + Prototype.Directory.of_properties + [ ( "relation", + Prototype.mixture [RMDirectory.make ~storage ~node ~constructor:(R.wrap storage)] + ) ] ] + + method hash = Representation.to_blob multigroup |> Concepts.Hash.hash_of_blob + method address = self#hash + end let wrap conn value = let open Utilities.Result in - let* node = SI.with_transaction conn (fun tx -> RelationM.find tx value.relations) - |> fmap (Option.to_result ~none:(Error.incomplete_multigroup value.relations)) in + let* node = + SI.with_transaction conn (fun tx -> RelationM.find tx value.relations) + |> fmap (Option.to_result ~none:(Error.incomplete_multigroup value.relations)) + in new multigroup conn value node |> Protocols.Handle.make |> Result.ok let make conn = let open Utilities.Result in SI.with_transaction conn (fun tx -> let* empty = RelationM.empty_under tx in - let multigroup = { relations = empty } in + let multigroup = {relations= empty} in let* _ = SI.store_blob tx (Representation.to_blob multigroup) in - new multigroup conn multigroup RelationM.empty |> Protocols.Handle.make |> Result.ok) + new multigroup conn multigroup RelationM.empty |> Protocols.Handle.make |> Result.ok ) end diff --git a/lib/kernel/Multigroup.mli b/lib/kernel/Multigroup.mli index fc58dad..2df41e6 100644 --- a/lib/kernel/Multigroup.mli +++ b/lib/kernel/Multigroup.mli @@ -3,7 +3,6 @@ module Make (S : Abstract.Storage.STORAGE) : sig val encode : t -> Concepts.Blob.t val decode : Concepts.Blob.t -> (t, Concepts.Condition.condition) result - val wrap : S.connection -> t -> (Protocols.Handle.t, Concepts.Condition.condition) result val make : S.connection -> (Protocols.Handle.t, Concepts.Condition.condition) result end diff --git a/lib/kernel/Namespace.ml b/lib/kernel/Namespace.ml index 728c307..340e813 100644 --- a/lib/kernel/Namespace.ml +++ b/lib/kernel/Namespace.ml @@ -1,39 +1,30 @@ -class namespace = object (self) - inherit Lifecycle.null - inherit Identity.of_id +class namespace = + object (self) + inherit Lifecycle.null + inherit Identity.of_id + method to_string = "namespace" + val entries : (string, Protocols.Handle.t) BatMap.t Atomic.t = Atomic.make BatMap.empty + method protocols = Protocols.[Directory.make self; Registry.make self] - method to_string = "namespace" + method update key reference value = + match + Utilities.Atomic.mswap entries (fun e -> + if BatMap.find_opt key e = reference then + match value with + | Some v -> Ok (BatMap.add key v e) + | None -> Ok (BatMap.remove key e) + else Error () ) + with + | Ok _ -> Ok true + | Error _ -> Ok false - val entries : (string, Protocols.Handle.t) BatMap.t Atomic.t = - Atomic.make BatMap.empty + method list = Atomic.get entries |> BatMap.keys |> BatFingerTree.of_enum |> Result.ok - method protocols = Protocols.[Directory.make self; Registry.make self] - - method update key reference value = - match - Utilities.Atomic.mswap entries - (fun e -> - if BatMap.find_opt key e = reference then - match value with - | Some v -> Ok (BatMap.add key v e) - | None -> Ok (BatMap.remove key e) - else - Error ()) - with - | Ok _ -> Ok true - | Error _ -> Ok false - - method list = - Atomic.get entries - |> BatMap.keys - |> BatFingerTree.of_enum - |> Result.ok - - method find key = - Atomic.get entries - |> BatMap.find_opt key - |> Utilities.Option.fmap Protocols.Handle.copy - |> Result.ok -end + method find key = + Atomic.get entries + |> BatMap.find_opt key + |> Utilities.Option.fmap Protocols.Handle.copy + |> Result.ok + end let make () = Protocols.Handle.make (new namespace) diff --git a/lib/kernel/Path.ml b/lib/kernel/Path.ml index b83c9b2..f34abe2 100644 --- a/lib/kernel/Path.ml +++ b/lib/kernel/Path.ml @@ -1,38 +1,42 @@ type t = string list let this = [] -let (@/) x y = x::y +let ( @/ ) x y = x :: y let to_string path = path |> List.map (fun x -> - let str = BatString.replace ~str:x ~sub:"^" ~by:"^^" |> snd in - BatString.replace ~str ~sub:"/" ~by:"^/" |> snd) + let str = BatString.replace ~str:x ~sub:"^" ~by:"^^" |> snd in + BatString.replace ~str ~sub:"/" ~by:"^/" |> snd ) |> BatIO.to_string (BatList.print ~first:"/" ~last:"" ~sep:"/" BatString.print) module Error = struct open Concepts.Condition - let path_not_found path = condition "path-not-found" "A given path was not found under the specified object" - ("path" |=| Concepts.Value.String (to_string path)) + let path_not_found path = + condition "path-not-found" "A given path was not found under the specified object" + ("path" |=| Concepts.Value.String (to_string path)) end let walking f g handle path = let rec walk handle = function | [] -> g handle - | x::xs -> - let open Utilities.Result in - let open Protocols in - let* dir = - Handle.require Directory.from handle - |> Result.map_error Concepts.Condition.(complement ("before-segment" |=| Concepts.Value.String x)) in - let* elem = Directory.find dir x in - match elem with - | None -> Error (Error.path_not_found path) - | Some elem -> f x handle (fun () -> walk elem xs) + | x :: xs -> ( + let open Utilities.Result in + let open Protocols in + let* dir = + Handle.require Directory.from handle + |> Result.map_error + Concepts.Condition.(complement ("before-segment" |=| Concepts.Value.String x)) + in + let* elem = Directory.find dir x in + match elem with + | None -> Error (Error.path_not_found path) + | Some elem -> f x handle (fun () -> walk elem xs) ) in walk handle path - |> Result.map_error Concepts.Condition.(complement ("path" |=| Concepts.Value.String (to_string path))) + |> Result.map_error + Concepts.Condition.(complement ("path" |=| Concepts.Value.String (to_string path))) let lookup = walking (fun _ _ f -> f ()) Result.ok diff --git a/lib/kernel/Path.mli b/lib/kernel/Path.mli index ece0615..198ef83 100644 --- a/lib/kernel/Path.mli +++ b/lib/kernel/Path.mli @@ -1,9 +1,20 @@ type t val this : t -val (@/) : string -> t -> t - +val ( @/ ) : string -> t -> t val lookup : Protocols.Handle.t -> t -> (Protocols.Handle.t, Concepts.Condition.condition) result -val update : Protocols.Handle.t -> t -> string -> Protocols.Handle.t option -> Protocols.Handle.t option -> (bool, Concepts.Condition.condition) result -val assoc : Protocols.Handle.t -> t -> string -> Protocols.Handle.t option -> (Protocols.Handle.t, Concepts.Condition.condition) result +val update : + Protocols.Handle.t -> + t -> + string -> + Protocols.Handle.t option -> + Protocols.Handle.t option -> + (bool, Concepts.Condition.condition) result + +val assoc : + Protocols.Handle.t -> + t -> + string -> + Protocols.Handle.t option -> + (Protocols.Handle.t, Concepts.Condition.condition) result diff --git a/lib/kernel/Prototype.ml b/lib/kernel/Prototype.ml index b159e00..4c96bc3 100644 --- a/lib/kernel/Prototype.ml +++ b/lib/kernel/Prototype.ml @@ -1,24 +1,24 @@ -let mixture ps = Protocols.Handle.make @@ - object - inherit Lifecycle.null - inherit Identity.of_id (* Should we allow the user to override this? *) +let mixture ps = + Protocols.Handle.make + @@ object + inherit Lifecycle.null + inherit Identity.of_id (* Should we allow the user to override this? *) + method protocols = ps + method to_string = "mixture" + end - method protocols = ps - - method to_string = "mixture" - end - -let rec mixture_of value f = - mixture (f (fun value' -> mixture_of value' f) value) +let rec mixture_of value f = mixture (f (fun value' -> mixture_of value' f) value) module Error = struct open Concepts.Condition - let invalid_property key = condition "invalid-property" "The specified key does not correspond to any property of the object" - ("key" |=| Concepts.Value.String key) + let invalid_property key = + condition "invalid-property" + "The specified key does not correspond to any property of the object" + ("key" |=| Concepts.Value.String key) - let deletion_not_supported () = condition "deletion-not-supported" "Attempting to delete an object property" - empty + let deletion_not_supported () = + condition "deletion-not-supported" "Attempting to delete an object property" empty end module Addressable = struct @@ -26,75 +26,79 @@ module Addressable = struct module Tree = Merkle.Make (S) (K) let make ~node = - Protocols.Addressable.make @@ - object - method address = Tree.hash_of node - end + Protocols.Addressable.make + @@ object + method address = Tree.hash_of node + end end end module Associative = struct let of_properties props = - Protocols.Associative.make @@ - object - val props = BatList.to_seq props |> BatMap.of_seq + Protocols.Associative.make + @@ object + val props = BatList.to_seq props |> BatMap.of_seq - method update key value = - match BatMap.find_opt key props with - | None -> Error (Error.invalid_property key) - | Some f -> f value - end + method update key value = + match BatMap.find_opt key props with + | None -> Error (Error.invalid_property key) + | Some f -> f value + end - let update_only f = function - | None -> Error (Error.deletion_not_supported ()) - | Some x -> f x + let update_only f = function None -> Error (Error.deletion_not_supported ()) | Some x -> f x module OfTree (S : Abstract.Storage.STORAGE) (K : Merkle.KEY with type t = string) = struct module Tree = Merkle.Make (S) (K) module SI = Storage.Make (S) let make ~storage ~constructor ~node = - Protocols.Associative.make @@ - object - method update key value = - (* TODO: read-only transactions *) - SI.with_transaction storage (fun tx -> - let open Utilities.Result in - let open Protocols in - let* node' = match value with - | None -> Tree.remove tx key node - | Some h -> - let* addressable = Handle.require Addressable.from h in - let addr = Addressable.address addressable in - Tree.insert tx key addr node - in - constructor node') - end + Protocols.Associative.make + @@ object + method update key value = + (* TODO: read-only transactions *) + SI.with_transaction storage (fun tx -> + let open Utilities.Result in + let open Protocols in + let* node' = + match value with + | None -> Tree.remove tx key node + | Some h -> + let* addressable = Handle.require Addressable.from h in + let addr = Addressable.address addressable in + Tree.insert tx key addr node + in + constructor node' ) + end end end module Directory = struct let of_properties props = - Protocols.Directory.make @@ - object - val props = BatList.to_seq props |> BatMap.of_seq - - method list = Ok (BatMap.keys props |> BatFingerTree.of_enum) - method find k = Ok (BatMap.find_opt k props) - end - - module OfTree (S : Abstract.Storage.STORAGE) (K : Merkle.KEY with type t = string) (V : Merkle.VALUE) = struct + Protocols.Directory.make + @@ object + val props = BatList.to_seq props |> BatMap.of_seq + method list = Ok (BatMap.keys props |> BatFingerTree.of_enum) + method find k = Ok (BatMap.find_opt k props) + end + + module OfTree + (S : Abstract.Storage.STORAGE) + (K : Merkle.KEY with type t = string) + (V : Merkle.VALUE) = + struct module Tree = Merkle.Interface (S) (K) (V) module SI = Storage.Make (S) let make ~storage ~constructor ~node = - Protocols.Directory.make @@ - object - method list = SI.with_transaction storage (Fun.flip Tree.keys node) - method find k = SI.with_transaction storage (fun tx -> Tree.lookup tx k node) - |> Utilities.Result.fmap (function - | None -> Ok None - | Some x -> constructor x |> Result.map (Option.some)) - end + Protocols.Directory.make + @@ object + method list = SI.with_transaction storage (Fun.flip Tree.keys node) + + method find k = + SI.with_transaction storage (fun tx -> Tree.lookup tx k node) + |> Utilities.Result.fmap (function + | None -> Ok None + | Some x -> constructor x |> Result.map Option.some ) + end end end diff --git a/lib/kernel/Prototype.mli b/lib/kernel/Prototype.mli index 919f5d3..db22b63 100644 --- a/lib/kernel/Prototype.mli +++ b/lib/kernel/Prototype.mli @@ -1,29 +1,52 @@ -val mixture_of : 'a -> (('a -> Protocols.Handle.t) -> 'a -> Protocols.Handle.protocol list) -> Protocols.Handle.t +val mixture_of : + 'a -> (('a -> Protocols.Handle.t) -> 'a -> Protocols.Handle.protocol list) -> Protocols.Handle.t + val mixture : Protocols.Handle.protocol list -> Protocols.Handle.t module Directory : sig val of_properties : (string * Protocols.Handle.t) list -> Protocols.Handle.protocol - module OfTree (S : Abstract.Storage.STORAGE) (K : Merkle.KEY with type t = string) (V : Merkle.VALUE) : sig + module OfTree + (S : Abstract.Storage.STORAGE) + (K : Merkle.KEY with type t = string) + (V : Merkle.VALUE) : sig module Tree : module type of Merkle.Interface (S) (K) (V) - val make : storage:S.connection -> constructor:(V.t -> (Protocols.Handle.t, Concepts.Condition.condition) result) -> node:Tree.node -> Protocols.Handle.protocol + + val make : + storage:S.connection -> + constructor:(V.t -> (Protocols.Handle.t, Concepts.Condition.condition) result) -> + node:Tree.node -> + Protocols.Handle.protocol end end module Associative : sig - val of_properties : (string * (Protocols.Handle.t option -> (Protocols.Handle.t, Concepts.Condition.condition) result)) list -> Protocols.Handle.protocol + val of_properties : + ( string + * (Protocols.Handle.t option -> (Protocols.Handle.t, Concepts.Condition.condition) result) ) + list -> + Protocols.Handle.protocol - val update_only : (Protocols.Handle.t -> (Protocols.Handle.t, Concepts.Condition.condition) result) -> (Protocols.Handle.t option -> (Protocols.Handle.t, Concepts.Condition.condition) result) + val update_only : + (Protocols.Handle.t -> (Protocols.Handle.t, Concepts.Condition.condition) result) -> + Protocols.Handle.t option -> + (Protocols.Handle.t, Concepts.Condition.condition) result module OfTree (S : Abstract.Storage.STORAGE) (K : Merkle.KEY with type t = string) : sig module Tree : module type of Merkle.Make (S) (K) - val make : storage:S.connection -> constructor:(Tree.node -> (Protocols.Handle.t, Concepts.Condition.condition) result) -> node:Tree.node -> Protocols.Handle.protocol + + val make : + storage:S.connection -> + constructor:(Tree.node -> (Protocols.Handle.t, Concepts.Condition.condition) result) -> + node:Tree.node -> + Protocols.Handle.protocol end end module Addressable : sig module OfTree (S : Abstract.Storage.STORAGE) (K : Merkle.KEY) : sig module Tree : module type of Merkle.Make (S) (K) + val make : node:Tree.node -> Protocols.Handle.protocol end end diff --git a/lib/kernel/Storage.ml b/lib/kernel/Storage.ml index d50735c..da438d2 100644 --- a/lib/kernel/Storage.ml +++ b/lib/kernel/Storage.ml @@ -1,14 +1,13 @@ module Make (S : Abstract.Storage.STORAGE) = struct module Pointer = struct - type 'a t = { - addr : S.address; - loader : S.transaction -> S.address -> ('a, Concepts.Condition.condition) result - } - - let make loader addr = { addr; loader } - let address_of { addr; _ } = addr - let swap { loader; _ } addr = make loader addr - let deref tx { addr; loader } = loader tx addr + type 'a t = + { addr: S.address; + loader: S.transaction -> S.address -> ('a, Concepts.Condition.condition) result } + + let make loader addr = {addr; loader} + let address_of {addr; _} = addr + let swap {loader; _} addr = make loader addr + let deref tx {addr; loader} = loader tx addr end let as_hash = function @@ -16,25 +15,26 @@ module Make (S : Abstract.Storage.STORAGE) = struct | _ -> failwith "A label was provided where a hash was expected." let to_hum_string = function - | S.Hash h -> "Hash " ^ (Concepts.Hash.to_hum_string h) + | S.Hash h -> "Hash " ^ Concepts.Hash.to_hum_string h | S.Label l -> "Label " ^ l module Error = struct open Concepts.Condition let missing_data addr = - condition "missing-data" "An expected value was not found on the underlying storage. Is your database corrupted?" + condition "missing-data" + "An expected value was not found on the underlying storage. Is your database corrupted?" ("address" |=| Concepts.Value.String (to_hum_string addr)) end let finish tx = function | Ok value -> - let open Utilities.Result in - let* () = S.commit tx in - Ok value + let open Utilities.Result in + let* () = S.commit tx in + Ok value | Error condition -> - let _ = S.abort tx in - Error condition + let _ = S.abort tx in + Error condition let within start connection body = let open Utilities.Result in @@ -51,7 +51,5 @@ module Make (S : Abstract.Storage.STORAGE) = struct Ok address let get_req tx addr = - S.get tx addr - |> Utilities.Result.fmap (Option.to_result ~none:(Error.missing_data addr)) - + S.get tx addr |> Utilities.Result.fmap (Option.to_result ~none:(Error.missing_data addr)) end diff --git a/lib/kernel/Storage.mli b/lib/kernel/Storage.mli index 53bb666..92f602d 100644 --- a/lib/kernel/Storage.mli +++ b/lib/kernel/Storage.mli @@ -2,7 +2,9 @@ module Make : functor (S : Abstract.Storage.STORAGE) -> sig module Pointer : sig type 'a t - val make : (S.transaction -> S.address -> ('a, Concepts.Condition.condition) result) -> S.address -> 'a t + val make : + (S.transaction -> S.address -> ('a, Concepts.Condition.condition) result) -> S.address -> 'a t + val address_of : 'a t -> S.address val swap : 'a t -> S.address -> 'a t val deref : S.transaction -> 'a t -> ('a, Concepts.Condition.condition) result @@ -10,9 +12,23 @@ module Make : functor (S : Abstract.Storage.STORAGE) -> sig val as_hash : S.address -> Concepts.Hash.hash - val finish : S.transaction -> ('a, Concepts.Condition.condition) result -> ('a, Concepts.Condition.condition) result - val with_transaction : S.connection -> (S.transaction -> ('a, Concepts.Condition.condition) result) -> ('a, Concepts.Condition.condition) result - val with_read : S.connection -> (S.transaction -> ('a, Concepts.Condition.condition) result) -> ('a, Concepts.Condition.condition) result - val store_blob : S.transaction -> Concepts.Blob.t -> (Concepts.Hash.hash, Concepts.Condition.condition) result - val get_req: S.transaction -> S.address -> (Concepts.Blob.t, Concepts.Condition.condition) result + val finish : + S.transaction -> + ('a, Concepts.Condition.condition) result -> + ('a, Concepts.Condition.condition) result + + val with_transaction : + S.connection -> + (S.transaction -> ('a, Concepts.Condition.condition) result) -> + ('a, Concepts.Condition.condition) result + + val with_read : + S.connection -> + (S.transaction -> ('a, Concepts.Condition.condition) result) -> + ('a, Concepts.Condition.condition) result + + val store_blob : + S.transaction -> Concepts.Blob.t -> (Concepts.Hash.hash, Concepts.Condition.condition) result + + val get_req : S.transaction -> S.address -> (Concepts.Blob.t, Concepts.Condition.condition) result end diff --git a/lib/kernel/SubstantialRelation.ml b/lib/kernel/SubstantialRelation.ml index 52ce83c..f90ddff 100644 --- a/lib/kernel/SubstantialRelation.ml +++ b/lib/kernel/SubstantialRelation.ml @@ -87,7 +87,6 @@ module Make (S : Abstract.Storage.STORAGE) = struct let encode = Representation.to_blob let decode = Representation.of_blob - let schematics {schematics; _} = schematics let predicate {predicate; _} = predicate let local_constraints {local_constraints; _} = local_constraints @@ -119,9 +118,8 @@ module Make (S : Abstract.Storage.STORAGE) = struct let* kvs = Concepts.Encoding.Bencode.as_dict fields in kvs |> List.map (fun (name, domain) -> - Concepts.Encoding.Bencode.as_string domain - |> Result.map (fun domain -> - (name, {Protocols.Schematics.domain; provenance= []}) ) ) + Concepts.Encoding.Bencode.as_string domain + |> Result.map (fun domain -> name, {Protocols.Schematics.domain; provenance= []}) ) |> Utilities.List.sequence |> Result.map BatMap.String.of_list @@ -150,9 +148,7 @@ module Make (S : Abstract.Storage.STORAGE) = struct class relation storage value description = object (self) inherit Lifecycle.null - method to_string = "relation" - val storage : S.connection = storage val relation : t = value val declaration = modes_of description @@ -172,15 +168,15 @@ module Make (S : Abstract.Storage.STORAGE) = struct unused here: this enumeration reads through its own cursor-lifetime transaction and needs no name resolution, but cancellation should eventually be checked between tuples. *) method enumerate = enumerate storage relation - method modes : (Concepts.Mode.t, Concepts.Condition.condition) result = Ok declaration method generate binding = generate storage relation binding method protocols : Protocols.Handle.protocol list = - [ Protocols.Relation.make self - ; Protocols.Enumerable.make self - ; Protocols.Generative.make self - ; Protocols.Schematics.make self ] + [ Protocols.Relation.make self; + Protocols.Enumerable.make self; + Protocols.Generative.make self; + Protocols.Schematics.make self ] + method hash = hash relation end @@ -188,7 +184,8 @@ module Make (S : Abstract.Storage.STORAGE) = struct the description and modes are served from it on every request. *) let instantiate tx conn relation = schema_of tx relation - |> Result.map (fun description -> new relation conn relation description |> Protocols.Handle.make) + |> Result.map (fun description -> + new relation conn relation description |> Protocols.Handle.make ) let make conn ~schematics ?predicate ?local_constraints ?indexes () = let open Utilities.Result in @@ -203,9 +200,7 @@ module Make (S : Abstract.Storage.STORAGE) = struct Representation.of_blob data let wrap conn relation = SI.with_read conn (fun tx -> instantiate tx conn relation) - - let load tx conn addr = - load_value tx addr |> Utilities.Result.fmap (instantiate tx conn) + let load tx conn addr = load_value tx addr |> Utilities.Result.fmap (instantiate tx conn) let assert_tuple tx relation tuple = let open Utilities.Result in diff --git a/lib/kernel/SubstantialRelation.mli b/lib/kernel/SubstantialRelation.mli index a36c802..98f1e8f 100644 --- a/lib/kernel/SubstantialRelation.mli +++ b/lib/kernel/SubstantialRelation.mli @@ -25,7 +25,6 @@ module Make (S : Abstract.Storage.STORAGE) : sig (Protocols.Handle.t, Concepts.Condition.condition) result val load_value : S.transaction -> Concepts.Hash.hash -> (t, Concepts.Condition.condition) result - val wrap : S.connection -> t -> (Protocols.Handle.t, Concepts.Condition.condition) result val load : diff --git a/lib/kernel/Tuple.ml b/lib/kernel/Tuple.ml index bbc20ab..9dbbc17 100644 --- a/lib/kernel/Tuple.ml +++ b/lib/kernel/Tuple.ml @@ -7,9 +7,10 @@ module Make (S : Abstract.Storage.STORAGE) = struct let unknown_attribute name = condition "unknown-attribute" "No such attribute on this tuple" ("attribute" |=| Concepts.Value.String name) + let malformed_value () = - condition "malformed-tuple-value" - "A tuple field did not conform to what was expected" empty + condition "malformed-tuple-value" "A tuple field did not conform to what was expected" empty + let incomplete_tuple addr = condition "incomplete-tuple" "A stored tuple is missing part of its expected structure. Is your storage corrupted?" @@ -24,9 +25,9 @@ module Make (S : Abstract.Storage.STORAGE) = struct let encode value = let open Concepts.Encoding in Bencode.to_blob - (match value with - | Concepts.Value.String s -> Bencode.Tagged ('s', Bencode.String s) - | Concepts.Value.Integer n -> Bencode.Tagged ('i', Bencode.Int n)) + ( match value with + | Concepts.Value.String s -> Bencode.Tagged ('s', Bencode.String s) + | Concepts.Value.Integer n -> Bencode.Tagged ('i', Bencode.Int n) ) let decode blob = let open Utilities.Result in @@ -48,7 +49,7 @@ module Make (S : Abstract.Storage.STORAGE) = struct over an in-memory storage. Consider later splitting [t] into resident (an address) and ephemeral (an in-memory attribute map) forms instead. *) - type t = { type_ : string; attributes : AttributeM.address } + type t = {type_: string; attributes: AttributeM.address} module rec Representation : (Concepts.Encoding.Record.S with type t = t) = Concepts.Encoding.Record.Make (Body) @@ -59,26 +60,24 @@ module Make (S : Abstract.Storage.STORAGE) = struct let tag = 'T' let malformed = Error.malformed_value - let fields { type_; attributes } = + let fields {type_; attributes} = let open Concepts.Encoding in - [ "type", Bencode.String type_; - "attributes", Value.bencode_of_hash attributes ] + ["type", Bencode.String type_; "attributes", Value.bencode_of_hash attributes] let of_fields data = let open Utilities.Result in let open Concepts.Encoding in let* type_ = Bencode.field "type" data |> fmap Bencode.as_string in let* attributes = Bencode.field "attributes" data |> fmap Value.hash_of_bencode in - Ok { type_; attributes } + Ok {type_; attributes} end let encode = Representation.to_blob let decode = Representation.of_blob let hash tuple = Representation.to_blob tuple |> Concepts.Hash.hash_of_blob + let type_of {type_; _} = type_ - let type_of { type_; _ } = type_ - - let node tx { attributes; _ } = + let node tx {attributes; _} = let open Utilities.Result in AttributeM.find tx attributes |> fmap (Option.to_result ~none:(Error.incomplete_tuple attributes)) @@ -86,7 +85,7 @@ module Make (S : Abstract.Storage.STORAGE) = struct let empty tx ~type_ () = let open Utilities.Result in let* attributes = AttributeM.empty_under tx in - Ok { type_; attributes } + Ok {type_; attributes} let make tx ~type_ attributes = let open Utilities.Result in @@ -96,10 +95,10 @@ module Make (S : Abstract.Storage.STORAGE) = struct |> BatEnum.fold (fun node (name, value) -> let* node = node in - AttributeM.insert tx name value node) - (Ok AttributeM.empty)) + AttributeM.insert tx name value node ) + (Ok AttributeM.empty) ) in - Ok { type_; attributes = AttributeM.hash_of node } + Ok {type_; attributes= AttributeM.hash_of node} let attribute tx tuple name = let open Utilities.Result in @@ -114,30 +113,27 @@ module Make (S : Abstract.Storage.STORAGE) = struct (fun acc name value -> BatMap.String.add name value acc) BatMap.String.empty node - class tuple ~relation conn value node = object (self) - inherit Lifecycle.null - - method to_string = "tuple" - - val tuple = value - val storage = conn - val node = node - - method describe () = - let open Utilities.Result in - let* attributes = - SI.with_transaction storage (fun tx -> - AttributeM.fold_left tx - (fun acc name value -> BatMap.String.add name (Attribute.domain value) acc) - BatMap.String.empty node) - in - Ok (Protocols.Schematics.Tuple { Protocols.Schematics.relation; attributes }) - - method protocols : Protocols.Handle.protocol list = - [Protocols.Schematics.make self] - - method hash = hash tuple - end + class tuple ~relation conn value node = + object (self) + inherit Lifecycle.null + method to_string = "tuple" + val tuple = value + val storage = conn + val node = node + + method describe () = + let open Utilities.Result in + let* attributes = + SI.with_transaction storage (fun tx -> + AttributeM.fold_left tx + (fun acc name value -> BatMap.String.add name (Attribute.domain value) acc) + BatMap.String.empty node ) + in + Ok (Protocols.Schematics.Tuple {Protocols.Schematics.relation; attributes}) + + method protocols : Protocols.Handle.protocol list = [Protocols.Schematics.make self] + method hash = hash tuple + end let wrap ~relation conn value = let open Utilities.Result in diff --git a/lib/protocols/Addressable.ml b/lib/protocols/Addressable.ml index 7e97f08..e4ba5b5 100644 --- a/lib/protocols/Addressable.ml +++ b/lib/protocols/Addressable.ml @@ -3,11 +3,8 @@ class type implementation = object end type Handle.protocol += Addressable of implementation - type t = implementation let make impl = Addressable (impl :> implementation) - let from handle = Handle.into handle (function Addressable impl -> Some impl | _ -> None) - let address i = Handle.invoke i (fun o -> o#address) diff --git a/lib/protocols/Addressable.mli b/lib/protocols/Addressable.mli index 2d9c14d..0301361 100644 --- a/lib/protocols/Addressable.mli +++ b/lib/protocols/Addressable.mli @@ -5,7 +5,5 @@ class type implementation = object end val make : #implementation -> Handle.protocol - val from : Handle.t -> t Handle.interface option - val address : t Handle.interface -> Concepts.Hash.hash diff --git a/lib/protocols/Associative.ml b/lib/protocols/Associative.ml index 66de5ed..16fdcc8 100644 --- a/lib/protocols/Associative.ml +++ b/lib/protocols/Associative.ml @@ -3,14 +3,13 @@ class type implementation = object end type Handle.protocol += Associative of implementation - type t = implementation let make impl = Associative (impl :> implementation) - let from handle = Handle.into handle (function Associative impl -> Some impl | _ -> None) -let update i key value = Handle.invoke i (fun o -> - let open Utilities.Result in - let* h = o#update key value in - Handle.require from h) +let update i key value = + Handle.invoke i (fun o -> + let open Utilities.Result in + let* h = o#update key value in + Handle.require from h ) diff --git a/lib/protocols/Associative.mli b/lib/protocols/Associative.mli index 066cfe4..5886303 100644 --- a/lib/protocols/Associative.mli +++ b/lib/protocols/Associative.mli @@ -5,7 +5,10 @@ class type implementation = object end val make : #implementation -> Handle.protocol - val from : Handle.t -> t Handle.interface option -val update : t Handle.interface -> string -> Handle.t option -> (t Handle.interface, Concepts.Condition.condition) result +val update : + t Handle.interface -> + string -> + Handle.t option -> + (t Handle.interface, Concepts.Condition.condition) result diff --git a/lib/protocols/Cursor.ml b/lib/protocols/Cursor.ml index 75dc77d..f9bd697 100644 --- a/lib/protocols/Cursor.ml +++ b/lib/protocols/Cursor.ml @@ -29,9 +29,7 @@ let rec next i = let rec exists i p = let open Utilities.Result in let* found = next i in - match found with - | None -> Ok false - | Some tuple -> if p tuple then Ok true else exists i p + match found with None -> Ok false | Some tuple -> if p tuple then Ok true else exists i p let drain i ?(limit = 256) () = let open Utilities.Result in diff --git a/lib/protocols/Cursor.mli b/lib/protocols/Cursor.mli index c977fec..ff6c027 100644 --- a/lib/protocols/Cursor.mli +++ b/lib/protocols/Cursor.mli @@ -1,6 +1,4 @@ -type batch = - {tuples: Concepts.Tuple.t BatFingerTree.t; exhausted: bool} - +type batch = {tuples: Concepts.Tuple.t BatFingerTree.t; exhausted: bool} type t class type implementation = object @@ -11,13 +9,10 @@ val make : #implementation -> Handle.protocol val from : Handle.t -> t Handle.interface option val require : Handle.t -> (t Handle.interface, Concepts.Condition.condition) result val fetch : t Handle.interface -> int -> (batch, Concepts.Condition.condition) result - val next : t Handle.interface -> (Concepts.Tuple.t option, Concepts.Condition.condition) result val exists : - t Handle.interface -> - (Concepts.Tuple.t -> bool) -> - (bool, Concepts.Condition.condition) result + t Handle.interface -> (Concepts.Tuple.t -> bool) -> (bool, Concepts.Condition.condition) result val drain : t Handle.interface -> diff --git a/lib/protocols/Directory.ml b/lib/protocols/Directory.ml index 0d2507e..232a47e 100644 --- a/lib/protocols/Directory.ml +++ b/lib/protocols/Directory.ml @@ -4,13 +4,9 @@ class type implementation = object end type Handle.protocol += Directory of implementation - type t = implementation let make impl = Directory (impl :> implementation) - let from handle = Handle.into handle (function Directory impl -> Some impl | _ -> None) - let list i = Handle.invoke i (fun o -> o#list) - let find i name = Handle.invoke i (fun o -> o#find name) diff --git a/lib/protocols/Directory.mli b/lib/protocols/Directory.mli index 9033235..0d78887 100644 --- a/lib/protocols/Directory.mli +++ b/lib/protocols/Directory.mli @@ -6,8 +6,6 @@ class type implementation = object end val make : #implementation -> Handle.protocol - val from : Handle.t -> t Handle.interface option - val list : t Handle.interface -> (string BatFingerTree.t, Concepts.Condition.condition) result val find : t Handle.interface -> string -> (Handle.t option, Concepts.Condition.condition) result diff --git a/lib/protocols/Enumerable.mli b/lib/protocols/Enumerable.mli index d2ab882..2c0ee69 100644 --- a/lib/protocols/Enumerable.mli +++ b/lib/protocols/Enumerable.mli @@ -6,7 +6,5 @@ end val make : #implementation -> Handle.protocol val from : Handle.t -> t Handle.interface option - val require : Handle.t -> (t Handle.interface, Concepts.Condition.condition) result - val enumerate : t Handle.interface -> (Handle.t, Concepts.Condition.condition) result diff --git a/lib/protocols/Generative.ml b/lib/protocols/Generative.ml index bd89e21..6846e43 100644 --- a/lib/protocols/Generative.ml +++ b/lib/protocols/Generative.ml @@ -68,7 +68,8 @@ class virtual membership = else let* declaration = self#modes in let* () = - if Concepts.Mode.decision declaration bound then Ok () else Error (Error.undecidable bound) + if Concepts.Mode.decision declaration bound then Ok () + else Error (Error.undecidable bound) in let* cursor = self#generate binding in let expected = Concepts.Tuple.hash tuple in diff --git a/lib/protocols/Handle.ml b/lib/protocols/Handle.ml index 41c88dd..cdadd4a 100644 --- a/lib/protocols/Handle.ml +++ b/lib/protocols/Handle.ml @@ -4,7 +4,8 @@ module Error = struct open Concepts.Condition let unimplemented_protocol obj_name = - condition "unimplemented-protocol" "A required protocol was not implemented by the specified object" + condition "unimplemented-protocol" + "A required protocol was not implemented by the specified object" ("object" |=| Concepts.Value.String obj_name) end @@ -16,46 +17,32 @@ class type obj = object method protocols : protocol list end -type t = { valid : bool ref; refers_to : obj } +type t = {valid: bool ref; refers_to: obj} +type 'a interface = {handle: t; interface: 'a} -type 'a interface = { handle : t; interface : 'a } +let object_of {valid; refers_to} = + if !valid then refers_to else failwith "Attempt to dereference an invalid handle!" -let object_of { valid; refers_to } = - if !valid then - refers_to - else - failwith "Attempt to dereference an invalid handle!" +let interface_of handle interface = {handle; interface} +let make o = {valid= ref true; refers_to= (o :> obj)} +let into handle f = List.find_map f (object_of handle)#protocols |> Option.map (interface_of handle) -let interface_of handle interface = { handle; interface } - -let make o = { valid = ref true; refers_to = (o :> obj) } - -let into handle f = - List.find_map f (object_of handle)#protocols - |> Option.map (interface_of handle) - -let invoke { handle; interface } f = +let invoke {handle; interface} f = let _ = object_of handle in f interface -let from { handle; _ } = handle +let from {handle; _} = handle let copy handle = let o = object_of handle in - if o#reference then - Some (make o) - else - None - -let equal h1 h2 = - Concepts.Hash.hash_equals (object_of h1)#hash (object_of h2)#hash + if o#reference then Some (make o) else None +let equal h1 h2 = Concepts.Hash.hash_equals (object_of h1)#hash (object_of h2)#hash let hash h = (object_of h)#hash let protocols h = (object_of h)#protocols - let to_string h = (object_of h)#to_string -let release ({ valid; _ } as handle) = +let release ({valid; _} as handle) = let o = object_of handle in valid := false; o#release diff --git a/lib/protocols/Handle.mli b/lib/protocols/Handle.mli index 40a78ff..a354257 100644 --- a/lib/protocols/Handle.mli +++ b/lib/protocols/Handle.mli @@ -1,7 +1,5 @@ type t - type 'a interface - type protocol = .. class type obj = object @@ -13,18 +11,13 @@ class type obj = object end val make : #obj -> t - val into : t -> (protocol -> 'a option) -> 'a interface option val from : 'a interface -> t - val invoke : 'a interface -> ('a -> 'b) -> 'b - val copy : t -> t option val equal : t -> t -> bool val release : t -> unit - val hash : t -> Concepts.Hash.hash val protocols : t -> protocol list val to_string : t -> string - val require : (t -> 'a interface option) -> t -> ('a interface, Concepts.Condition.condition) result diff --git a/lib/protocols/Program.ml b/lib/protocols/Program.ml index 5b618e6..e50f07d 100644 --- a/lib/protocols/Program.ml +++ b/lib/protocols/Program.ml @@ -8,7 +8,6 @@ module Make (P : PROGRAM) = struct end type Handle.protocol += Program of implementation - type t = implementation let make impl = Program (impl :> implementation) diff --git a/lib/protocols/Program.mli b/lib/protocols/Program.mli index 9cf4455..6cdffd8 100644 --- a/lib/protocols/Program.mli +++ b/lib/protocols/Program.mli @@ -11,6 +11,5 @@ module Make (P : PROGRAM) : sig val make : #implementation -> Handle.protocol val from : Handle.t -> t Handle.interface option - val invoke : t Handle.interface -> P.t -> (Handle.t, Concepts.Condition.condition) result end diff --git a/lib/protocols/Registry.ml b/lib/protocols/Registry.ml index f01f06b..d7c4480 100644 --- a/lib/protocols/Registry.ml +++ b/lib/protocols/Registry.ml @@ -1,13 +1,11 @@ class type implementation = object - method update : string -> Handle.t option -> Handle.t option -> (bool, Concepts.Condition.condition) result + method update : + string -> Handle.t option -> Handle.t option -> (bool, Concepts.Condition.condition) result end type Handle.protocol += Registry of implementation - type t = implementation let make impl = Registry (impl :> implementation) - let from handle = Handle.into handle (function Registry impl -> Some impl | _ -> None) - let update i key reference value = Handle.invoke i (fun o -> o#update key reference value) diff --git a/lib/protocols/Registry.mli b/lib/protocols/Registry.mli index 3390167..627a60f 100644 --- a/lib/protocols/Registry.mli +++ b/lib/protocols/Registry.mli @@ -1,11 +1,16 @@ type t class type implementation = object - method update : string -> Handle.t option -> Handle.t option -> (bool, Concepts.Condition.condition) result + method update : + string -> Handle.t option -> Handle.t option -> (bool, Concepts.Condition.condition) result end val make : #implementation -> Handle.protocol - val from : Handle.t -> t Handle.interface option -val update : t Handle.interface -> string -> Handle.t option -> Handle.t option -> (bool, Concepts.Condition.condition) result +val update : + t Handle.interface -> + string -> + Handle.t option -> + Handle.t option -> + (bool, Concepts.Condition.condition) result diff --git a/lib/protocols/Relation.mli b/lib/protocols/Relation.mli index 384877e..b4a11ec 100644 --- a/lib/protocols/Relation.mli +++ b/lib/protocols/Relation.mli @@ -16,5 +16,4 @@ val predicate : val local_constraints : t Handle.interface -> (Concepts.Hash.hash option, Concepts.Condition.condition) result -val contains : - t Handle.interface -> Concepts.Tuple.t -> (bool, Concepts.Condition.condition) result +val contains : t Handle.interface -> Concepts.Tuple.t -> (bool, Concepts.Condition.condition) result diff --git a/lib/protocols/Schematics.ml b/lib/protocols/Schematics.ml index 49d8586..238fa99 100644 --- a/lib/protocols/Schematics.ml +++ b/lib/protocols/Schematics.ml @@ -17,10 +17,8 @@ class type implementation = object end type Handle.protocol += Schematics of implementation - type t = implementation let make impl = Schematics (impl :> implementation) -let from handle = - Handle.into handle (function Schematics impl -> Some impl | _ -> None) +let from handle = Handle.into handle (function Schematics impl -> Some impl | _ -> None) let describe impl = Handle.invoke impl (fun o -> o#describe ()) diff --git a/test/Helpers.ml b/test/Helpers.ml index e859932..42cf8a5 100644 --- a/test/Helpers.ml +++ b/test/Helpers.ml @@ -34,17 +34,17 @@ module Storage = struct module SI = Kernel.Storage.Make (S) let store_schema tx attributes = - Concepts.Encoding.Bencode.(Dict (List.map (fun a -> (a, String "string")) attributes) |> to_blob) + Concepts.Encoding.Bencode.(Dict (List.map (fun a -> a, String "string") attributes) |> to_blob) |> SI.store_blob tx let with_connection f dir () = with_temporary_directory dir begin fun dir -> - begin - let open Utilities.Result in - let* conn = S.connect (C.configure dir) in - Ok (Fun.protect ~finally:(fun () -> S.disconnect conn) (fun () -> f conn)) - end - |> condition_as_failure + begin + let open Utilities.Result in + let* conn = S.connect (C.configure dir) in + Ok (Fun.protect ~finally:(fun () -> S.disconnect conn) (fun () -> f conn)) + end + |> condition_as_failure end end end diff --git a/test/integration/Registration.ml b/test/integration/Registration.ml index daecc22..9ac26f4 100644 --- a/test/integration/Registration.ml +++ b/test/integration/Registration.ml @@ -2,7 +2,6 @@ open Rnt module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = struct open Alcotest - module H = Helpers.Storage.Make (S) (C) module I = Kernel.Initialization.Make (S) module B = Kernel.Branch.Make (S) @@ -14,13 +13,18 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let* root = I.initialize ~evaluators:["fol", Evaluators.FOL.make ()] conn in let* multigroup = M.make conn in let* branch = B.make conn in - let* branch' = Kernel.Path.(assoc branch ("multigroup" @/ this) "library" (Some multigroup)) in + let* branch' = + Kernel.Path.(assoc branch ("multigroup" @/ this) "library" (Some multigroup)) + in Kernel.Path.(update root ("branch" @/ this) "master" None (Some branch')) end - |> Helpers.condition_as_failure |> ignore; + |> Helpers.condition_as_failure + |> ignore; begin let* root = I.initialize ~evaluators:["fol", Evaluators.FOL.make ()] conn in - let* _ = Kernel.Path.(lookup root ("branch" @/ "master" @/ "multigroup" @/ "library" @/ this)) in + let* _ = + Kernel.Path.(lookup root ("branch" @/ "master" @/ "multigroup" @/ "library" @/ this)) + in let* _ = Kernel.Path.(lookup root ("evaluator" @/ "fol" @/ this)) in Ok () end @@ -28,7 +32,7 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let suite prefix = ( "registration/" ^ prefix, - [test_case "registration tests" `Quick (H.with_connection run "registration-test")]) + [test_case "registration tests" `Quick (H.with_connection run "registration-test")] ) end module LMDB = Make (Rnt.Backend.Storage.LMDB) (Helpers.Storage.LMDB_Configurator) diff --git a/test/unit/backend/Storage.ml b/test/unit/backend/Storage.ml index a6765bf..b7a5a65 100644 --- a/test/unit/backend/Storage.ml +++ b/test/unit/backend/Storage.ml @@ -2,11 +2,12 @@ open Rnt module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = struct open Alcotest - module H = Helpers.Storage.Make (S) (C) let storage_and_retrieval conn = - let key = Concepts.Value.String "value" |> Concepts.Encoding.blob_of_value |> Concepts.Hash.hash_of_blob in + let key = + Concepts.Value.String "value" |> Concepts.Encoding.blob_of_value |> Concepts.Hash.hash_of_blob + in let value = Concepts.Value.Integer 42 in let blob = Concepts.Encoding.blob_of_value value in let v, v' = @@ -26,7 +27,8 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let suite prefix = ( "storage/" ^ prefix, - [test_case "storage-and-retrieval" `Quick (H.with_connection storage_and_retrieval "storage-test")] ) + [ test_case "storage-and-retrieval" `Quick + (H.with_connection storage_and_retrieval "storage-test") ] ) end module LMDB = Make (Rnt.Backend.Storage.LMDB) (Helpers.Storage.LMDB_Configurator) diff --git a/test/unit/concepts/Cardinality.ml b/test/unit/concepts/Cardinality.ml index a60c472..b77e12c 100644 --- a/test/unit/concepts/Cardinality.ml +++ b/test/unit/concepts/Cardinality.ml @@ -1,5 +1,4 @@ open Alcotest - module C = Rnt.Concepts.Cardinality let klass = testable (fun ppf c -> Format.pp_print_string ppf (C.to_string c)) C.equal diff --git a/test/unit/evaluators/FOL.ml b/test/unit/evaluators/FOL.ml index 9cfeb84..404e7a4 100644 --- a/test/unit/evaluators/FOL.ml +++ b/test/unit/evaluators/FOL.ml @@ -2,15 +2,13 @@ open Rnt module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = struct open Alcotest - module H = Helpers.Storage.Make (S) (C) module SR = Rnt.Kernel.SubstantialRelation.Make (S) let alaric = - { Concepts.Tuple.type_ = "employee"; - attributes = - BatMap.String.empty - |> BatMap.String.add "name" (Concepts.Value.String "Alaric") } + { Concepts.Tuple.type_= "employee"; + attributes= BatMap.String.empty |> BatMap.String.add "name" (Concepts.Value.String "Alaric") + } let not_a_directory () = Concepts.Condition.condition "not-a-directory" @@ -41,8 +39,7 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let* found = Protocols.Directory.find directory "fol" in let* evaluator = Option.to_result ~none:(not_a_program ()) found in let* interpreter = - Rnt.Evaluators.FOL.Program.from evaluator - |> Option.to_result ~none:(not_a_program ()) + Rnt.Evaluators.FOL.Program.from evaluator |> Option.to_result ~none:(not_a_program ()) in let* cursor = Rnt.Evaluators.FOL.Program.invoke interpreter (Rnt.Evaluators.FOL.Base employee) @@ -58,8 +55,8 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = check bool "the tuple that was asserted" true (List.for_all (fun tuple -> - Concepts.Hash.hash_equals (Concepts.Tuple.hash tuple) (Concepts.Tuple.hash alaric)) - scanned) + Concepts.Hash.hash_equals (Concepts.Tuple.hash tuple) (Concepts.Tuple.hash alaric) ) + scanned ) let suite prefix = ( "fol/" ^ prefix, diff --git a/test/unit/evaluators/Lambda.ml b/test/unit/evaluators/Lambda.ml index 5866411..ee15c16 100644 --- a/test/unit/evaluators/Lambda.ml +++ b/test/unit/evaluators/Lambda.ml @@ -2,21 +2,18 @@ open Rnt module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = struct open Alcotest - module H = Helpers.Storage.Make (S) (C) module SR = Rnt.Kernel.SubstantialRelation.Make (S) let datum = - { Concepts.Tuple.type_ = "noun"; - attributes = - BatMap.String.empty - |> BatMap.String.add "lemma" (Concepts.Value.String "datum") } + { Concepts.Tuple.type_= "noun"; + attributes= BatMap.String.empty |> BatMap.String.add "lemma" (Concepts.Value.String "datum") + } let reticulare = - { Concepts.Tuple.type_ = "verb"; - attributes = - BatMap.String.empty - |> BatMap.String.add "lemma" (Concepts.Value.String "rēticulāre") } + { Concepts.Tuple.type_= "verb"; + attributes= + BatMap.String.empty |> BatMap.String.add "lemma" (Concepts.Value.String "rēticulāre") } let not_a_directory () = Concepts.Condition.condition "not-a-directory" @@ -48,18 +45,13 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = [ Kernel.Prototype.Directory.of_properties ["noun", noun; "verb", verb; "lambda", Rnt.Evaluators.Lambda.make ()] ] in - let* directory = - Protocols.Directory.from root |> Option.to_result ~none:(not_a_directory ()) - in + let* directory = Protocols.Directory.from root |> Option.to_result ~none:(not_a_directory ()) in let* found = Protocols.Directory.find directory "lambda" in let* evaluator = Option.to_result ~none:(not_a_program ()) found in let* interpreter = - Rnt.Evaluators.Lambda.Program.from evaluator - |> Option.to_result ~none:(not_a_program ()) - in - let* cursor = - Rnt.Evaluators.Lambda.(Program.invoke interpreter (Program (term, directory))) + Rnt.Evaluators.Lambda.Program.from evaluator |> Option.to_result ~none:(not_a_program ()) in + let* cursor = Rnt.Evaluators.Lambda.(Program.invoke interpreter (Program (term, directory))) in let* scan = Protocols.Cursor.require cursor in let* tuples = Protocols.Cursor.drain scan () in Protocols.Handle.release cursor; @@ -81,8 +73,7 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let identity_applied_to_a_relation conn = let open Rnt.Evaluators.Lambda in let scanned = - evaluate conn (Apply (Abstract ("x", Name "x"), Name "noun")) - |> Helpers.condition_as_failure + evaluate conn (Apply (Abstract ("x", Name "x"), Name "noun")) |> Helpers.condition_as_failure in check int "one tuple scanned" 1 (List.length scanned); check bool "the tuple that was asserted" true (List.for_all (is datum) scanned) @@ -94,8 +85,8 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let scanned = evaluate conn (Apply - ( Apply (Abstract ("x", Abstract ("y", Name "x")), Name "noun"), - Abstract ("z", Name "z") )) + (Apply (Abstract ("x", Abstract ("y", Name "x")), Name "noun"), Abstract ("z", Name "z")) + ) |> Helpers.condition_as_failure in check int "one tuple scanned" 1 (List.length scanned); @@ -124,9 +115,9 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let open Rnt.Evaluators.Lambda in match evaluate conn (Abstract ("x", Name "x")) with | Error condition -> - check bool "unapplied abstraction" true - (String.starts_with ~prefix:"unapplied-abstraction" - (Concepts.Condition.to_string_hum condition)) + check bool "unapplied abstraction" true + (String.starts_with ~prefix:"unapplied-abstraction" + (Concepts.Condition.to_string_hum condition) ) | Ok _ -> fail "an abstraction was enumerated" let suite prefix = diff --git a/test/unit/kernel/EphemeralRelation.ml b/test/unit/kernel/EphemeralRelation.ml index a72409b..f75fd0d 100644 --- a/test/unit/kernel/EphemeralRelation.ml +++ b/test/unit/kernel/EphemeralRelation.ml @@ -1,5 +1,4 @@ open Alcotest - module Concepts = Rnt.Concepts module Protocols = Rnt.Protocols @@ -14,8 +13,8 @@ module Derivation = struct let describe _ = Ok (BatMap.String.singleton "value" - { Protocols.Schematics.domain = "integer"; - provenance = [{Protocols.Schematics.source = ["example"]; attribute = "value"}] } ) + { Protocols.Schematics.domain= "integer"; + provenance= [{Protocols.Schematics.source= ["example"]; attribute= "value"}] } ) let modes {declared; _} = Ok declared @@ -31,13 +30,13 @@ end module Derived = Rnt.Kernel.EphemeralRelation.Make (Derivation) let member n = - { Concepts.Tuple.type_ = "example"; - attributes = BatMap.String.singleton "value" (Concepts.Value.Integer n) } + { Concepts.Tuple.type_= "example"; + attributes= BatMap.String.singleton "value" (Concepts.Value.Integer n) } let plan_over cardinality = - { Derivation.name = "the-derivation"; - members = [member 1; member 2; member 3]; - declared = + { Derivation.name= "the-derivation"; + members= [member 1; member 2; member 3]; + declared= Concepts.Mode.of_list [Concepts.Mode.enumerable cardinality; Concepts.Mode.decides_when ["value"]] } @@ -46,9 +45,9 @@ let derive plan = Derived.derive plan |> Helpers.condition_as_failure let values tuples = BatFingerTree.to_list tuples |> List.filter_map (fun tuple -> - match BatMap.String.find_opt "value" tuple.Concepts.Tuple.attributes with - | Some (Concepts.Value.Integer n) -> Some n - | _ -> None ) + match BatMap.String.find_opt "value" tuple.Concepts.Tuple.attributes with + | Some (Concepts.Value.Integer n) -> Some n + | _ -> None ) |> List.sort compare let commit = Concepts.Hash.hash_of_bytes (Bytes.of_string "a-commit") @@ -92,8 +91,7 @@ let a_countable_derivation_decides_only () = end |> Helpers.condition_as_failure in - check bool "no enumeration is offered" false - (Option.is_some (Protocols.Enumerable.from derived)); + check bool "no enumeration is offered" false (Option.is_some (Protocols.Enumerable.from derived)); check bool "membership is still decided" true holds; check bool "and still refused" false rejects @@ -115,10 +113,11 @@ let a_derivation_describes_itself () = ( BatMap.String.values description |> BatList.of_enum |> List.concat_map (fun attribute -> - attribute.Protocols.Schematics.provenance - |> List.map (fun origin -> - String.concat "/" origin.Protocols.Schematics.source - ^ "/" ^ origin.Protocols.Schematics.attribute ) ) ) + attribute.Protocols.Schematics.provenance + |> List.map (fun origin -> + String.concat "/" origin.Protocols.Schematics.source + ^ "/" + ^ origin.Protocols.Schematics.attribute ) ) ) | _ -> fail "a derived relation describes itself as a relation" let releasing_a_derivation_releases_its_inputs () = @@ -143,8 +142,7 @@ let releasing_a_derivation_releases_its_inputs () = let suites () = [ ( "kernel/ephemeral-relation", [ test_case "identity-is-the-derivation" `Quick identity_is_the_derivation; - test_case "an-exhaustible-derivation-enumerates" `Quick - an_exhaustible_derivation_enumerates; + test_case "an-exhaustible-derivation-enumerates" `Quick an_exhaustible_derivation_enumerates; test_case "a-countable-derivation-decides-only" `Quick a_countable_derivation_decides_only; test_case "a-derivation-describes-itself" `Quick a_derivation_describes_itself; test_case "releasing-a-derivation-releases-its-inputs" `Quick diff --git a/test/unit/kernel/Merkle.ml b/test/unit/kernel/Merkle.ml index 85c756c..eaff92d 100644 --- a/test/unit/kernel/Merkle.ml +++ b/test/unit/kernel/Merkle.ml @@ -2,9 +2,10 @@ open Rnt module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = struct open Alcotest - module H = Helpers.Storage.Make (S) (C) - module T = Rnt.Kernel.Merkle.Interface (S) (Rnt.Kernel.Merkle.StringKey) (Rnt.Kernel.Merkle.StringKey) + + module T = + Rnt.Kernel.Merkle.Interface (S) (Rnt.Kernel.Merkle.StringKey) (Rnt.Kernel.Merkle.StringKey) (* TODO: be a bit more comprehensive (ideally, we want to test splits as well) *) let insert_and_lookup conn = @@ -12,10 +13,11 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = begin let open Utilities.Result in let* tx = S.start conn in - let* node = T.empty - |> T.insert tx "k1" "v1" - |> fmap (T.insert tx "k2" "v2") - |> fmap (T.insert tx "k3" "v3") + let* node = + T.empty + |> T.insert tx "k1" "v1" + |> fmap (T.insert tx "k2" "v2") + |> fmap (T.insert tx "k3" "v3") in let* node' = T.insert tx "k3" "toodles" node in let* v1 = T.lookup tx "k1" node in @@ -31,7 +33,8 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = check (option string) "that in-memory reads from the first write work properly" (Some "v1") v1; check (option string) "that in-memory reads from the second write work properly" (Some "v2") v2; check (option string) "that in-memory reads from the third write work properly" (Some "v3") v3; - check (option string) "that in-memory reads from a value replacement work properly" (Some "toodles") v3'; + check (option string) "that in-memory reads from a value replacement work properly" + (Some "toodles") v3'; check (option string) "that in-memory reads from a non-existent key returns nothing" None bogus let batching conn = @@ -40,10 +43,12 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let open Utilities.Result in let* tx = S.start conn in let intermediate = ref None in - let* final = T.with_batch tx (fun () -> - let* i = T.empty |> T.insert tx "tree" "maple" in - intermediate := Some (T.hash_of i); - T.insert tx "tree" "spruce" i) in + let* final = + T.with_batch tx (fun () -> + let* i = T.empty |> T.insert tx "tree" "maple" in + intermediate := Some (T.hash_of i); + T.insert tx "tree" "spruce" i ) + in let* () = S.commit tx in Ok (Option.get !intermediate, T.hash_of final) end @@ -62,16 +67,16 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = check bool "that the intermediate node does not get persisted" true (Option.is_none i_node); check bool "that the final node does get persisted" true (Option.is_some f_node) - let persistence conn = let addr = begin let open Utilities.Result in let* tx = S.start conn in - let* node = T.empty - |> T.insert tx "k1" "v1" - |> fmap (T.insert tx "k2" "v2") - |> fmap (T.insert tx "k3" "v3") + let* node = + T.empty + |> T.insert tx "k1" "v1" + |> fmap (T.insert tx "k2" "v2") + |> fmap (T.insert tx "k3" "v3") in let* () = S.commit tx in Ok (T.hash_of node) @@ -99,10 +104,11 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = begin let open Utilities.Result in let* tx = S.start conn in - let* node = T.empty - |> T.insert tx "k1" "v1" - |> fmap (T.insert tx "k2" "v2") - |> fmap (T.insert tx "k3" "v3") + let* node = + T.empty + |> T.insert tx "k1" "v1" + |> fmap (T.insert tx "k2" "v2") + |> fmap (T.insert tx "k3" "v3") in let* keys = T.fold_left tx (fun acc k _ -> k :: acc) [] node |> Result.map List.rev in let* values = T.fold_left tx (fun acc _ v -> v :: acc) [] node |> Result.map List.rev in @@ -111,8 +117,10 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = end |> Helpers.condition_as_failure in - check (list string) "that keys are properly enumerated from left to right" ["k1"; "k2"; "k3"] keys; - check (list string) "that values are properly enumerated from left to right" ["v1"; "v2"; "v3"] values + check (list string) "that keys are properly enumerated from left to right" ["k1"; "k2"; "k3"] + keys; + check (list string) "that values are properly enumerated from left to right" ["v1"; "v2"; "v3"] + values (* TODO: this will need `remove` *) (* let determinism _conn = *) @@ -120,10 +128,10 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = let suite prefix = ( "merkle/" ^ prefix, - [test_case "insert-and-lookup" `Quick (H.with_connection insert_and_lookup "merkle-test"); - test_case "batching" `Quick (H.with_connection batching "merkle-test"); - test_case "persistence" `Quick (H.with_connection persistence "merkle-test"); - test_case "iteration" `Quick (H.with_connection iteration "merkle-test")]) + [ test_case "insert-and-lookup" `Quick (H.with_connection insert_and_lookup "merkle-test"); + test_case "batching" `Quick (H.with_connection batching "merkle-test"); + test_case "persistence" `Quick (H.with_connection persistence "merkle-test"); + test_case "iteration" `Quick (H.with_connection iteration "merkle-test") ] ) end module LMDB = Make (Rnt.Backend.Storage.LMDB) (Helpers.Storage.LMDB_Configurator) diff --git a/test/unit/kernel/SubstantialRelation.ml b/test/unit/kernel/SubstantialRelation.ml index f639599..db13026 100644 --- a/test/unit/kernel/SubstantialRelation.ml +++ b/test/unit/kernel/SubstantialRelation.ml @@ -2,16 +2,14 @@ open Rnt module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = struct open Alcotest - module H = Helpers.Storage.Make (S) (C) module SR = Rnt.Kernel.SubstantialRelation.Make (S) - let hash s = - Concepts.Blob.blob_of_bytes (Bytes.of_string s) |> Concepts.Hash.hash_of_blob + let hash s = Concepts.Blob.blob_of_bytes (Bytes.of_string s) |> Concepts.Hash.hash_of_blob let alaric = - { Concepts.Tuple.type_ = "employee"; - attributes = + { Concepts.Tuple.type_= "employee"; + attributes= BatMap.String.empty |> BatMap.String.add "name" (Concepts.Value.String "Alaric") |> BatMap.String.add "age" (Concepts.Value.Integer 42) } @@ -40,8 +38,8 @@ module Make (S : Abstract.Storage.STORAGE) (C : Helpers.Storage.CONFIGURATOR) = check bool "the tuple that was asserted" true (List.for_all (fun tuple -> - Concepts.Hash.hash_equals (Concepts.Tuple.hash tuple) (Concepts.Tuple.hash alaric)) - enumerated) + Concepts.Hash.hash_equals (Concepts.Tuple.hash tuple) (Concepts.Tuple.hash alaric) ) + enumerated ) let suite prefix = ( "substantial-relation/" ^ prefix, |
