blob: ea1083b809c304a542ae4f60c375d0b8b48f114f (
plain) (
tree)
|
|
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
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 deletion_not_supported () =
condition "deletion-not-supported" "Attempting to delete an object property" empty
end
module Addressable = struct
module OfTree (S : Abstract.Storage.STORAGE) (K : Merkle.KEY) = struct
module Tree = Merkle.Make (S) (K)
let make ~node =
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
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
type 'tx admission = 'tx -> (Concepts.Hash.hash, Concepts.Condition.condition) result
(* A value with no address yet is [admit]ted: it is read here, before
the write begins, since reading it may itself need storage, and
stored by the write. *)
let admission admit key h =
match Protocols.Addressable.from h with
| Some a ->
let addr = Protocols.Addressable.address a in
Ok (fun _ -> Ok addr)
| None -> admit key h
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 ~admit ~storage ~constructor ~node =
Protocols.Associative.make
@@ object
method update key value =
let open Utilities.Result in
let* store =
match value with
| None -> Ok None
| Some h -> admission admit key h |> Result.map Option.some
in
SI.with_transaction storage (fun tx ->
let* node' =
match store with
| None -> Tree.remove tx key node
| Some store ->
let* addr = store tx 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
let children directory =
let open Utilities.Result in
let* listing = Protocols.Handle.require Protocols.Directory.from directory in
let* names = Protocols.Directory.list listing in
BatFingerTree.to_list names
|> List.map (fun name ->
let* found = Protocols.Directory.find listing name in
Ok (Option.map (fun child -> name, child) found) )
|> Utilities.List.sequence
|> Result.map (List.filter_map Fun.id)
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_read storage (Fun.flip Tree.keys node)
method find k =
SI.with_read 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
|