package data-encoding
Source file v1.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 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306(*****************************************************************************) (* *) (* Open Source License *) (* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *) (* Copyright (c) 2022 Nomadic Labs <contact@nomadic-labs.com> *) (* *) (* 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. *) (* *) (*****************************************************************************) module Encoding = struct include Encoding type 'a matching_function = 'a -> match_result let splitted ~json ~binary = raw_splitted ~json:(Json.convert json) ~binary let uint_like_n ?max_value () = let max_value = match max_value with | None -> Binary_size.max_int `Uint30 | Some max_value -> if Binary_size.max_int `Uint30 < max_value then invalid_arg "Data_encoding.uint_like_n" ; max_value in let binary = uint_like_n ~max_value in let json = ranged_int 0 max_value in splitted ~json ~binary let int_like_z ?min_value ?max_value () = let max_value = match max_value with | None -> Binary_size.max_int `Int31 | Some max_value -> if Binary_size.max_int `Int31 < max_value then invalid_arg "Data_encoding.int_like_z" ; max_value in let min_value = match min_value with | None -> Binary_size.min_int `Int31 | Some min_value -> if min_value < Binary_size.min_int `Int31 then invalid_arg "Data_encoding.int_like_z" ; min_value in let binary = int_like_z ~min_value ~max_value in let json = ranged_int min_value max_value in splitted ~json ~binary let assoc enc = let json = Json_encoding.assoc (Json.convert enc) in let binary = list (tup2 string enc) in raw_splitted ~json ~binary module Bounded = struct let string' ?length_kind json_repr length = let max_length = match length_kind with | None -> Binary_size.max_int `Uint30 (* biggest that's allowed *) | Some kind -> Binary_size.max_int kind in if length > max_length then raise (Invalid_argument "Data_encoding.Encoding.Bounded.string': length bound is greater \ than maximum length allowed in size header.") ; if length <= 0 then raise (Invalid_argument "Data_encoding.Encoding.Bounded.string': negative length.") ; raw_splitted ~binary: (let kind = match length_kind with | None -> (Binary_size.unsigned_range_to_size length :> Binary_size.length) | Some kind -> kind in dynamic_size ~kind (check_size length Variable.string)) ~json: (let open Json_encoding in conv (fun s -> if String.length s > length then invalid_arg "oversized string" ; s) (fun s -> if String.length s > length then raise (Cannot_destruct ([], Invalid_argument "oversized string")) ; s) (Json.string json_repr)) let string length = string' Plain length let bytes' ?length_kind json_repr length = let max_length = match length_kind with | None -> Binary_size.max_int `Uint30 (* biggest that's allowed *) | Some kind -> Binary_size.max_int kind in if length > max_length then raise (Invalid_argument "Data_encoding.Encoding.Bounded.string': length bound is greater \ than maximum length allowed in size header.") ; if length <= 0 then raise (Invalid_argument "Data_encoding.Encoding.Bounded.string': negative length.") ; raw_splitted ~binary: (let kind = match length_kind with | None -> (Binary_size.unsigned_range_to_size length :> Binary_size.length) | Some kind -> kind in dynamic_size ~kind (check_size length Variable.bytes)) ~json: (let open Json_encoding in conv (fun s -> if Bytes.length s > length then invalid_arg "oversized string" ; s) (fun s -> if Bytes.length s > length then raise (Cannot_destruct ([], Invalid_argument "oversized string")) ; s) (Json.bytes json_repr)) let bytes length = bytes' Hex length let bigstring ?length_kind ?(string_json_repr = Hex) length = let max_length = match length_kind with | None -> Binary_size.max_int `Uint30 (* biggest that's allowed *) | Some kind -> Binary_size.max_int kind in if length > max_length then raise (Invalid_argument "Data_encoding.Encoding.Bounded.bigstring': length bound is \ greater than maximum length allowed in size header.") ; if length <= 0 then raise (Invalid_argument "Data_encoding.Encoding.Bounded.bigstring: negative length.") ; raw_splitted ~binary: (let kind = match length_kind with | None -> (Binary_size.unsigned_range_to_size length :> Binary_size.length) | Some kind -> kind in dynamic_size ~kind (check_size length (Variable.bigstring ()))) ~json: (let open Json_encoding in conv (fun s -> if Bigstringaf.length s > length then invalid_arg "oversized string" ; Bigstringaf.to_string s) (fun s -> if String.length s > length then raise (Cannot_destruct ([], Invalid_argument "oversized string")) ; Bigstringaf.of_string ~off:0 ~len:(String.length s) s) (Json.string string_json_repr)) end type 'a lazy_state = Value of 'a | Bytes of Bytes.t | Both of Bytes.t * 'a type 'a lazy_t = {mutable state : 'a lazy_state; encoding : 'a t} let force_decode_internal le = match le.state with | Value value -> value | Both (_, value) -> value | Bytes bytes -> ( match Binary_reader.of_bytes_opt le.encoding bytes with | Some expr -> le.state <- Both (bytes, expr) ; expr | None -> raise (Json_encoding .Decoding_exception_whilst_conversion_of_lazy_encoding bytes)) let force_decode le = match force_decode_internal le with | exception Json_encoding.Decoding_exception_whilst_conversion_of_lazy_encoding _ -> None | v -> Some v let force_bytes le = match le.state with | Bytes bytes -> bytes | Both (bytes, _) -> bytes | Value value -> let bytes = Binary_writer.to_bytes_exn le.encoding value in le.state <- Both (bytes, value) ; bytes let lazy_encoding encoding = let binary = Encoding.conv force_bytes (fun bytes -> {state = Bytes bytes; encoding}) Encoding.bytes in let json = Encoding.union [ case ~title:"invalid_lazy_bytes" Json_only (raw_splitted ~json:Json_encoding.invalid_lazy_bytes ~binary:bytes) (fun _ -> None) (fun bytes -> {state = Bytes bytes; encoding}); case ~title:"valid_lazy_bytes" Json_only (Encoding.conv force_decode_internal (fun value -> {state = Value value; encoding}) encoding) (fun x -> Some x) (fun x -> x); ] in splitted ~json ~binary let make_lazy encoding value = {encoding; state = Value value} let apply_lazy ~fun_value ~fun_bytes ~fun_combine le = match le.state with | Value value -> fun_value value | Bytes bytes -> fun_bytes bytes | Both (bytes, value) -> fun_combine (fun_value value) (fun_bytes bytes) module With_field_name_duplicate_checks = SaferEncoding module With_JSON_discriminant = SaferEncoding module Compact = Compact type 'a compact = 'a Compact.t end include Encoding module With_version = With_version module Registration = Registration module Json = struct include Json include Json_stream end module Bson = Bson module Binary_schema = Binary_schema module Binary_stream = Binary_stream module Binary = struct include Binary_error_types include Binary_error include Binary_length include Binary_writer include Binary_reader include Binary_stream_reader module Slicer = Binary_slicer let describe = Binary_description.describe end type json = Json.t let json = Json.encoding type json_schema = Json.schema let json_schema = Json.schema_encoding type bson = Bson.t