umarshal.ml (16632B)
1 (* Unison file synchronizer: src/ubase/umarshal.ml *) 2 (* Copyright 2020, Stéphane Glondu 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. 16 *) 17 18 exception Error of string 19 20 type 'a t = { 21 read : (bytes -> int -> int -> unit) -> 'a; 22 write : (bytes -> int -> int -> unit) -> 'a -> unit; 23 } 24 25 external id : 'a -> 'a = "%identity" 26 27 let header_size = 8 28 29 let max_int_int64 = Int64.of_int max_int 30 let min_int_int64 = Int64.of_int min_int 31 32 let data_size header offset = 33 if offset + header_size <= Bytes.length header then 34 let n = Bytes.get_int64_be header offset in 35 if n < 0L then 36 raise (Error "data_size: negative size") 37 else if n <= max_int_int64 then 38 Int64.to_int n 39 else 40 raise (Error "data_size: payload too large") 41 else 42 raise (Error "data_size: header too short") 43 44 let to_string m x = 45 let buffer = Buffer.create 1024 in 46 m.write (Buffer.add_subbytes buffer) x; 47 let header = Bytes.create header_size in 48 Bytes.set_int64_be header 0 (Int64.of_int (Buffer.length buffer)); 49 Bytes.to_string header ^ Buffer.contents buffer 50 51 let from_bytes m buffer offset = 52 let length = Bytes.length buffer in 53 let offset = ref (offset + header_size) in 54 m.read (fun buffer' offset' n -> 55 let i = !offset in 56 if i + n <= length then ( 57 offset := i + n; 58 Bytes.blit buffer i buffer' offset' n 59 ) else ( 60 raise (Error "from_bytes: end of input") 61 ) 62 ) 63 64 let from_string m buffer offset = 65 from_bytes m (Bytes.of_string buffer) offset 66 67 let from_channel m ic = 68 let header = Bytes.create header_size in 69 really_input ic header 0 header_size; 70 m.read (really_input ic) 71 72 let to_channel m oc x = 73 let header = Bytes.create header_size in 74 let header_pos = pos_out oc in 75 output oc header 0 header_size; 76 m.write (output oc) x; 77 let end_pos = pos_out oc in 78 let data_size = end_pos - header_pos - header_size in 79 Bytes.set_int64_be header 0 (Int64.of_int data_size); 80 seek_out oc header_pos; 81 output oc header 0 header_size; 82 seek_out oc end_pos 83 84 let rec1 a = 85 let rec fa = 86 { 87 read = (fun recv -> (a fa).read recv); 88 write = (fun send x -> (a fa).write send x); 89 } 90 in 91 fa 92 93 let rec2 a b = 94 let rec fa = 95 { 96 read = (fun recv -> (a fb).read recv); 97 write = (fun send x -> (a fb).write send x); 98 } 99 and fb = 100 { 101 read = (fun recv -> (b fa).read recv); 102 write = (fun send x -> (b fa).write send x); 103 } 104 in 105 (fb, fa) 106 107 let unit = 108 { 109 read = (fun _ -> ()); 110 write = (fun _ () -> ()); 111 } 112 113 let char = 114 { 115 read = 116 (fun recv -> 117 let buffer = Bytes.create 1 in 118 recv buffer 0 1; 119 Bytes.unsafe_get buffer 0 120 ); 121 write = 122 (fun send x -> 123 let res = Bytes.create 1 in 124 Bytes.unsafe_set res 0 x; 125 send res 0 1 126 ); 127 } 128 129 let bool = 130 { 131 read = 132 (fun recv -> 133 match char.read recv with 134 | '\000' -> false 135 | '\001' -> true 136 | _ -> raise (Error "bool: invalid value") 137 ); 138 write = 139 (fun send x -> 140 char.write send (if x then '\001' else '\000') 141 ); 142 } 143 144 let int32 = 145 { 146 read = 147 (fun recv -> 148 let buffer = Bytes.create 4 in 149 recv buffer 0 4; 150 Bytes.get_int32_be buffer 0 151 ); 152 write = 153 (fun send x -> 154 let res = Bytes.create 4 in 155 Bytes.set_int32_be res 0 x; 156 send res 0 4 157 ); 158 } 159 160 let int64 = 161 { 162 read = 163 (fun recv -> 164 let realize n get of_int = 165 let buffer = Bytes.create n in 166 recv buffer 0 n; 167 of_int (get buffer 0) 168 in 169 match int_of_char (char.read recv) with 170 | 0 -> 0L 171 | 1 -> realize 1 Bytes.get_int8 Int64.of_int 172 | 2 -> realize 2 Bytes.get_int16_be Int64.of_int 173 | 4 -> realize 4 Bytes.get_int32_be Int64.of_int32 174 | 8 -> realize 8 Bytes.get_int64_be id 175 | n -> raise (Error (Printf.sprintf "int64.read: unexpected size (%d)" n)) 176 ); 177 write = 178 (fun send x -> 179 let realize n set to_int = 180 let buffer = Bytes.create (1 + n) in 181 Bytes.unsafe_set buffer 0 (char_of_int n); 182 set buffer 1 (to_int x); 183 send buffer 0 (1 + n) 184 in 185 if x = 0L then 186 char.write send '\000' 187 else if -0x80L <= x && x < 0x80L then 188 realize 1 Bytes.set_int8 Int64.to_int 189 else if -0x8000L <= x && x < 0x8000L then 190 realize 2 Bytes.set_int16_be Int64.to_int 191 else if -0x8000_0000L <= x && x < 0x8000_0000L then 192 realize 4 Bytes.set_int32_be Int64.to_int32 193 else 194 realize 8 Bytes.set_int64_be id 195 ); 196 } 197 198 let int = 199 { 200 read = 201 (fun recv -> 202 let r = int64.read recv in 203 if r < min_int_int64 || r > max_int_int64 then 204 raise (Error "int.read: too large") 205 else 206 Int64.to_int r 207 ); 208 write = 209 (fun send x -> 210 int64.write send (Int64.of_int x) 211 ); 212 } 213 214 let string = 215 { 216 read = 217 (fun recv -> 218 let length = int.read recv in 219 let buffer = Bytes.create length in 220 recv buffer 0 length; 221 Bytes.to_string buffer 222 ); 223 write = 224 (fun send x -> 225 let length = String.length x in 226 int.write send length; 227 send (Bytes.of_string x) 0 length 228 ); 229 } 230 231 type bytearray = 232 (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t 233 234 external unsafe_blit_from_bytes : bytes -> int -> bytearray -> int -> int -> unit 235 = "ml_blit_bytes_to_bigarray" [@@noalloc] 236 237 external unsafe_blit_to_bytes : bytearray -> int -> bytes -> int -> int -> unit 238 = "ml_blit_bigarray_to_bytes" [@@noalloc] 239 240 let bytearray = 241 { 242 read = 243 (fun recv -> 244 let length = int.read recv in 245 let res = Bigarray.(Array1.create char c_layout length) in 246 let rec loop offset length = 247 if length > 0 then ( 248 let sub_length = min length Sys.max_string_length in 249 let buffer = Bytes.create sub_length in 250 recv buffer 0 sub_length; 251 unsafe_blit_from_bytes buffer 0 res offset sub_length; 252 loop (offset + sub_length) (length - sub_length) 253 ) 254 in 255 loop 0 length; 256 res 257 ); 258 write = 259 (fun send x -> 260 let length = Bigarray.Array1.dim x in 261 int.write send length; 262 let buffer = Bytes.create (min length Sys.max_string_length) in 263 let rec loop offset length = 264 if length > 0 then ( 265 let sub_length = min length Sys.max_string_length in 266 unsafe_blit_to_bytes x offset buffer 0 sub_length; 267 send buffer 0 sub_length; 268 loop (offset + sub_length) (length - sub_length) 269 ) 270 in 271 loop 0 length 272 ); 273 } 274 275 let marshal_to_bytearray m x = 276 let data_size = ref 0 in 277 m.write (fun _ _ length -> data_size := !data_size + length) x; 278 let header = Bytes.create header_size in 279 Bytes.set_int64_be header 0 (Int64.of_int !data_size); 280 let total_size = header_size + !data_size in 281 let result = Bigarray.(Array1.create char c_layout total_size) in 282 unsafe_blit_from_bytes header 0 result 0 header_size; 283 let offset = ref header_size in 284 m.write (fun buffer offset' length -> 285 let i = !offset in 286 if i + length <= total_size then ( 287 unsafe_blit_from_bytes buffer offset' result i length; 288 offset := i + length 289 ) else ( 290 raise (Error "marshal_to_bytearray: length inconsistency") 291 ) 292 ) x; 293 if !offset <> total_size then 294 raise (Error "marshal_to_bytearray: universe inconsistency"); 295 result 296 297 let unmarshal_from_bytearray m x offset = 298 let length = Bigarray.Array1.dim x in 299 let offset = ref (offset + header_size) in 300 m.read (fun buffer' offset' n -> 301 let i = !offset in 302 if i + n <= length then ( 303 offset := i + n; 304 unsafe_blit_to_bytes x i buffer' offset' n 305 ) else ( 306 raise (Error "unmarshal_from_bytearray: end of input") 307 ) 308 ) 309 310 type int32bigarray = 311 (int32, Bigarray.int32_elt, Bigarray.c_layout) Bigarray.Array1.t 312 313 let int32bigarray = 314 { 315 read = 316 (fun recv -> 317 let length = int.read recv in 318 let res = Bigarray.(Array1.create int32 c_layout length) in 319 for i = 0 to length - 1 do 320 res.{i} <- int32.read recv 321 done; 322 res 323 ); 324 write = 325 (fun send x -> 326 let length = Bigarray.Array1.dim x in 327 int.write send length; 328 for i = 0 to length - 1 do 329 int32.write send x.{i} 330 done 331 ); 332 } 333 334 let float = 335 { 336 read = 337 (fun recv -> 338 Int64.float_of_bits (int64.read recv) 339 ); 340 write = 341 (fun send x -> 342 int64.write send (Int64.bits_of_float x) 343 ); 344 } 345 346 let list m = 347 { 348 read = 349 (fun recv -> 350 let length = int.read recv in 351 let result = ref [] in 352 for _ = 1 to length do 353 result := m.read recv :: !result 354 done; 355 List.rev !result 356 ); 357 write = 358 (fun send x -> 359 int.write send (List.length x); 360 List.iter (fun x -> m.write send x) x 361 ); 362 } 363 364 let prod2 ma mb f g = 365 { 366 read = 367 (fun recv -> 368 let a = ma.read recv in 369 let b = mb.read recv in 370 g (a, b) 371 ); 372 write = 373 (fun send x -> 374 let a, b = f x in 375 ma.write send a; 376 mb.write send b 377 ); 378 } 379 380 let prod3 ma mb mc f g = 381 { 382 read = 383 (fun recv -> 384 let a = ma.read recv in 385 let b = mb.read recv in 386 let c = mc.read recv in 387 g (a, b, c) 388 ); 389 write = 390 (fun send x -> 391 let a, b, c = f x in 392 ma.write send a; 393 mb.write send b; 394 mc.write send c 395 ); 396 } 397 398 let prod4 ma mb mc md f g = 399 { 400 read = 401 (fun recv -> 402 let a = ma.read recv in 403 let b = mb.read recv in 404 let c = mc.read recv in 405 let d = md.read recv in 406 g (a, b, c, d) 407 ); 408 write = 409 (fun send x -> 410 let a, b, c, d = f x in 411 ma.write send a; 412 mb.write send b; 413 mc.write send c; 414 md.write send d 415 ); 416 } 417 418 let prod5 ma mb mc md me f g = 419 { 420 read = 421 (fun recv -> 422 let a = ma.read recv in 423 let b = mb.read recv in 424 let c = mc.read recv in 425 let d = md.read recv in 426 let e = me.read recv in 427 g (a, b, c, d, e) 428 ); 429 write = 430 (fun send x -> 431 let a, b, c, d, e = f x in 432 ma.write send a; 433 mb.write send b; 434 mc.write send c; 435 md.write send d; 436 me.write send e 437 ); 438 } 439 440 let prod6 ma mb mc md me mf f g = 441 { 442 read = 443 (fun recv -> 444 let a = ma.read recv in 445 let b = mb.read recv in 446 let c = mc.read recv in 447 let d = md.read recv in 448 let e = me.read recv in 449 let f = mf.read recv in 450 g (a, b, c, d, e, f) 451 ); 452 write = 453 (fun send x -> 454 let a, b, c, d, e, f = f x in 455 ma.write send a; 456 mb.write send b; 457 mc.write send c; 458 md.write send d; 459 me.write send e; 460 mf.write send f 461 ); 462 } 463 464 let sum1 ma f g = 465 { 466 read = (fun recv -> g (ma.read recv)); 467 write = (fun send x -> ma.write send (f x)); 468 } 469 470 type ('a, 'b) sum2 = I21 of 'a | I22 of 'b 471 472 let sum2 ma mb f g = 473 { 474 read = 475 (fun recv -> 476 g (match char.read recv with 477 | '\000' -> I21 (ma.read recv) 478 | '\001' -> I22 (mb.read recv) 479 | _ -> raise (Error "sum2: invalid tag")) 480 ); 481 write = 482 (fun send x -> 483 match f x with 484 | I21 a -> char.write send '\000'; ma.write send a 485 | I22 a -> char.write send '\001'; mb.write send a 486 ); 487 } 488 489 let option m = 490 sum2 unit m 491 (function 492 | None -> I21 () 493 | Some a -> I22 a) 494 (function 495 | I21 () -> None 496 | I22 a -> Some a) 497 498 type ('a, 'b, 'c) sum3 = I31 of 'a | I32 of 'b | I33 of 'c 499 500 let sum3 ma mb mc f g = 501 { 502 read = 503 (fun recv -> 504 g (match char.read recv with 505 | '\000' -> I31 (ma.read recv) 506 | '\001' -> I32 (mb.read recv) 507 | '\002' -> I33 (mc.read recv) 508 | _ -> raise (Error "sum3: invalid tag")) 509 ); 510 write = 511 (fun send x -> 512 match f x with 513 | I31 a -> char.write send '\000'; ma.write send a 514 | I32 a -> char.write send '\001'; mb.write send a 515 | I33 a -> char.write send '\002'; mc.write send a 516 ); 517 } 518 519 type ('a, 'b, 'c, 'd) sum4 = I41 of 'a | I42 of 'b | I43 of 'c | I44 of 'd 520 521 let sum4 ma mb mc md f g = 522 { 523 read = 524 (fun recv -> 525 g (match char.read recv with 526 | '\000' -> I41 (ma.read recv) 527 | '\001' -> I42 (mb.read recv) 528 | '\002' -> I43 (mc.read recv) 529 | '\003' -> I44 (md.read recv) 530 | _ -> raise (Error "sum4: invalid tag")) 531 ); 532 write = 533 (fun send x -> 534 match f x with 535 | I41 a -> char.write send '\000'; ma.write send a 536 | I42 a -> char.write send '\001'; mb.write send a 537 | I43 a -> char.write send '\002'; mc.write send a 538 | I44 a -> char.write send '\003'; md.write send a 539 ); 540 } 541 542 type ('a, 'b, 'c, 'd, 'e) sum5 = I51 of 'a | I52 of 'b | I53 of 'c | I54 of 'd | I55 of 'e 543 544 let sum5 ma mb mc md me f g = 545 { 546 read = 547 (fun recv -> 548 g (match char.read recv with 549 | '\000' -> I51 (ma.read recv) 550 | '\001' -> I52 (mb.read recv) 551 | '\002' -> I53 (mc.read recv) 552 | '\003' -> I54 (md.read recv) 553 | '\004' -> I55 (me.read recv) 554 | _ -> raise (Error "sum5: invalid tag")) 555 ); 556 write = 557 (fun send x -> 558 match f x with 559 | I51 a -> char.write send '\000'; ma.write send a 560 | I52 a -> char.write send '\001'; mb.write send a 561 | I53 a -> char.write send '\002'; mc.write send a 562 | I54 a -> char.write send '\003'; md.write send a 563 | I55 a -> char.write send '\004'; me.write send a 564 ); 565 } 566 567 type ('a, 'b, 'c, 'd, 'e, 'f) sum6 = I61 of 'a | I62 of 'b | I63 of 'c | I64 of 'd | I65 of 'e | I66 of 'f 568 569 let sum6 ma mb mc md me mf f g = 570 { 571 read = 572 (fun recv -> 573 g (match char.read recv with 574 | '\000' -> I61 (ma.read recv) 575 | '\001' -> I62 (mb.read recv) 576 | '\002' -> I63 (mc.read recv) 577 | '\003' -> I64 (md.read recv) 578 | '\004' -> I65 (me.read recv) 579 | '\005' -> I66 (mf.read recv) 580 | _ -> raise (Error "sum6: invalid tag")) 581 ); 582 write = 583 (fun send x -> 584 match f x with 585 | I61 a -> char.write send '\000'; ma.write send a 586 | I62 a -> char.write send '\001'; mb.write send a 587 | I63 a -> char.write send '\002'; mc.write send a 588 | I64 a -> char.write send '\003'; md.write send a 589 | I65 a -> char.write send '\004'; me.write send a 590 | I66 a -> char.write send '\005'; mf.write send a 591 ); 592 } 593 594 let cond c d m = 595 { 596 read = 597 (fun recv -> 598 if c () then m.read recv else d 599 ); 600 write = 601 (fun send x -> 602 if c () then m.write send x else () 603 ); 604 } 605 606 module type PROPLIST_S = sig 607 type key = string 608 type value = Obj.t 609 type map 610 val cardinal : map -> int 611 val empty : map 612 val add : key -> value -> map -> map 613 val iter : (key -> value -> unit) -> map -> unit 614 val find_m : key -> value t 615 end 616 617 module Proplist (S : PROPLIST_S) = struct 618 let m = 619 { 620 read = 621 (fun recv -> 622 let length = int.read recv in 623 let res = ref S.empty in 624 for _ = 1 to length do 625 let key = string.read recv in 626 let value = (S.find_m key).read recv in 627 res := S.add key value !res 628 done; 629 !res 630 ); 631 write = 632 (fun send x -> 633 let length = S.cardinal x in 634 int.write send length; 635 S.iter (fun key value -> 636 string.write send key; 637 (S.find_m key).write send value 638 ) x 639 ); 640 } 641 end