unison

Fork of Unison, a bi-directional file synchronization tool
git clone git://git.laack.co/unison.git
Log | Files | Refs | README | LICENSE

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