package plebeia
Source file info.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104(*****************************************************************************) (* *) (* Open Source License *) (* Copyright (c) 2020 DaiLambda, Inc. <contact@dailambda.jp> *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) (* to deal in the Software without restriction, including without limitation *) (* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) (* and/or sell copies of the Software, and to permit persons to whom the *) (* Software is furnished to do so, subject to the following conditions: *) (* *) (* The above copyright notice and this permission notice shall be included *) (* in all copies or substantial portions of the Software. *) (* *) (* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) (* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) (* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) (* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) (* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) (* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) (* Info stored in Cursor.t *) open Utils type t = { copies : Path.t list (* invariant: Segment.list is never empty *) } let empty = { copies = [] } let equal t1 t2 = if List.length t1.copies <> List.length t2.copies then false else (* not tail recursive... *) List.for_all2 (fun segs1 segs2 -> Path.equal segs1 segs2) t1.copies t2.copies let encode t = if t = empty then "" else (* for future extensibility, info is saved as (tag*content) list ended with 0 *) let copies = if t.copies = [] then [] else "\001" :: List.map Segment.Serialization.encode_list (List.map Path.to_segments t.copies @ [[]]) in String.concat "" @@ copies @ [ "\000" ] let decode_copies (s, off) = let rec g rev_copies off = match Segment.Serialization.decode_list_slice (s, off) with | None -> None (* error *) | Some ([], off) -> (* end *) Some (List.rev rev_copies, off) | Some (copy, off) -> g (Path.of_segments copy :: rev_copies) off in g [] off let decode s = if s = "" then Some empty else let slen = String.length s in let rec f copies off = match String.unsafe_get s off with | '\000' when off + 1 = slen -> (* EOS *) Some { copies = begin match copies with | None -> [] | Some copies -> copies end } | '\000' -> None (* garbage at the end *) | '\001' when copies <> None -> None (* copies cannot appear more than once *) | '\001' -> begin match decode_copies (s, off+1) with | None -> None | Some (copies, off) -> f (Some copies) off end | _c -> None (* unknown kind *) in f None 0 let write storage info = Storage.Chunk.write storage (encode info) type Error.t += Invalid let () = Error.register_printer @@ function | Invalid -> Some "Invalid commit info" | _ -> None let read storage i = if i = Index.zero then Ok empty else match decode (Storage.Chunk.read storage i) with | None -> Error Invalid | Some v -> Ok v