Persistent store with Git semantics: lazy reads, delayed writes, content-addressing
at inode 129 lines 3.8 kB view raw
1type algorithm = Sha1 | Sha256 2 3type _ t = 4 | Sha1_hash : string -> [ `Sha1 ] t 5 | Sha256_hash : string -> [ `Sha256 ] t 6 7type sha1 = [ `Sha1 ] t 8type sha256 = [ `Sha256 ] t 9 10let sha1 data = Sha1_hash Digestif.SHA1.(to_raw_string (digest_string data)) 11 12let sha256 data = 13 Sha256_hash Digestif.SHA256.(to_raw_string (digest_string data)) 14 15let sha1_of_bytes raw = 16 if String.length raw <> 20 then 17 invalid_arg "Hash.sha1_of_bytes: expected 20 bytes"; 18 Sha1_hash raw 19 20let sha256_of_bytes raw = 21 if String.length raw <> 32 then 22 invalid_arg "Hash.sha256_of_bytes: expected 32 bytes"; 23 Sha256_hash raw 24 25let to_bytes : type a. a t -> string = function 26 | Sha1_hash s -> s 27 | Sha256_hash s -> s 28 29let to_hex h = 30 let bytes = to_bytes h in 31 let buf = Buffer.create (String.length bytes * 2) in 32 String.iter 33 (fun c -> Buffer.add_string buf (Printf.sprintf "%02x" (Char.code c))) 34 bytes; 35 Buffer.contents buf 36 37let hex_to_bytes hex = 38 let len = String.length hex in 39 if len mod 2 <> 0 then Error (`Msg "hex string has odd length") 40 else 41 let bytes = Bytes.create (len / 2) in 42 let rec loop i = 43 if i >= len then Ok (Bytes.to_string bytes) 44 else 45 let hi = hex.[i] and lo = hex.[i + 1] in 46 let decode c = 47 match c with 48 | '0' .. '9' -> Some (Char.code c - Char.code '0') 49 | 'a' .. 'f' -> Some (Char.code c - Char.code 'a' + 10) 50 | 'A' .. 'F' -> Some (Char.code c - Char.code 'A' + 10) 51 | _ -> None 52 in 53 match (decode hi, decode lo) with 54 | Some h, Some l -> 55 Bytes.set bytes (i / 2) (Char.chr ((h lsl 4) lor l)); 56 loop (i + 2) 57 | _ -> 58 Error 59 (`Msg (Printf.sprintf "invalid hex character at position %d" i)) 60 in 61 loop 0 62 63let sha1_of_hex hex = 64 match hex_to_bytes hex with 65 | Error _ as e -> e 66 | Ok bytes -> 67 if String.length bytes <> 20 then 68 Error (`Msg "SHA-1 hex must be 40 characters") 69 else Ok (Sha1_hash bytes) 70 71let sha256_of_hex hex = 72 match hex_to_bytes hex with 73 | Error _ as e -> e 74 | Ok bytes -> 75 if String.length bytes <> 32 then 76 Error (`Msg "SHA-256 hex must be 64 characters") 77 else Ok (Sha256_hash bytes) 78 79type existential = Ex : _ t -> existential 80 81let of_hex algo hex : (existential, [> `Msg of string ]) result = 82 match algo with 83 | Sha1 -> Result.map (fun h -> Ex h) (sha1_of_hex hex) 84 | Sha256 -> Result.map (fun h -> Ex h) (sha256_of_hex hex) 85 86let equal : type a. a t -> a t -> bool = 87 fun h1 h2 -> String.equal (to_bytes h1) (to_bytes h2) 88 89let compare : type a. a t -> a t -> int = 90 fun h1 h2 -> String.compare (to_bytes h1) (to_bytes h2) 91 92let length : type a. a t -> int = function 93 | Sha1_hash _ -> 20 94 | Sha256_hash _ -> 32 95 96let algorithm_of : type a. a t -> algorithm = function 97 | Sha1_hash _ -> Sha1 98 | Sha256_hash _ -> Sha256 99 100let algorithm_length = function Sha1 -> 20 | Sha256 -> 32 101 102let mst_depth (Sha256_hash bytes) = 103 let rec count_zeros i acc = 104 if i >= 32 then acc 105 else 106 let byte = Char.code bytes.[i] in 107 let hi = (byte lsr 6) land 0x3 in 108 let mid_hi = (byte lsr 4) land 0x3 in 109 let mid_lo = (byte lsr 2) land 0x3 in 110 let lo = byte land 0x3 in 111 if hi <> 0 then acc 112 else if mid_hi <> 0 then acc + 1 113 else if mid_lo <> 0 then acc + 2 114 else if lo <> 0 then acc + 3 115 else count_zeros (i + 1) (acc + 4) 116 in 117 count_zeros 0 0 118 119type any = Any : _ t -> any 120 121let any_algorithm (Any h) = algorithm_of h 122let any_to_bytes (Any h) = to_bytes h 123let any_to_hex (Any h) = to_hex h 124let equal_any (Any h1) (Any h2) = any_to_bytes (Any h1) = any_to_bytes (Any h2) 125let pp fmt h = Format.fprintf fmt "%s" (to_hex h) 126 127let pp_short fmt h = 128 let hex = to_hex h in 129 Format.fprintf fmt "%s" (String.sub hex 0 (min 7 (String.length hex)))