Data_encoding: allow to add padding
This commit is contained in:
parent
c82b44e8f2
commit
9a43902f03
@ -66,7 +66,8 @@ let fixup_references uf =
|
|||||||
| RangedFloat (_, _)
|
| RangedFloat (_, _)
|
||||||
| Float
|
| Float
|
||||||
| Bytes
|
| Bytes
|
||||||
| String) as enc -> enc in
|
| String
|
||||||
|
| Padding) as enc -> enc in
|
||||||
let field = function
|
let field = function
|
||||||
| Named_field (name, kind, layout) ->
|
| Named_field (name, kind, layout) ->
|
||||||
Named_field (name, kind, fixup_layout layout)
|
Named_field (name, kind, fixup_layout layout)
|
||||||
@ -308,6 +309,9 @@ let describe (type x) (encoding : x Encoding.t) =
|
|||||||
([ Anonymous_field ((kind :> Kind.t), Bytes) ], references)
|
([ Anonymous_field ((kind :> Kind.t), Bytes) ], references)
|
||||||
| String kind ->
|
| String kind ->
|
||||||
([ Anonymous_field ((kind :> Kind.t), String) ], references)
|
([ Anonymous_field ((kind :> Kind.t), String) ], references)
|
||||||
|
| Padded ({ encoding = e }, n) ->
|
||||||
|
let fields, references = fields ref_name recursives references e in
|
||||||
|
(fields @ [ Named_field ("padding", `Fixed n, Padding) ], references)
|
||||||
| (String_enum (tbl, encoding_array) as encoding) ->
|
| (String_enum (tbl, encoding_array) as encoding) ->
|
||||||
let size, cases = enum tbl encoding_array in
|
let size, cases = enum tbl encoding_array in
|
||||||
let name = may_new_reference ref_name in
|
let name = may_new_reference ref_name in
|
||||||
@ -422,6 +426,11 @@ let describe (type x) (encoding : x Encoding.t) =
|
|||||||
(Bytes, references)
|
(Bytes, references)
|
||||||
| String _kind ->
|
| String _kind ->
|
||||||
(String, references)
|
(String, references)
|
||||||
|
| Padded _ as enc ->
|
||||||
|
let name = may_new_reference ref_name in
|
||||||
|
let fields, references = fields None recursives references enc in
|
||||||
|
let references = add_reference name (obj fields) references in
|
||||||
|
(Ref name, references)
|
||||||
| String_enum (tbl, encoding_array) ->
|
| String_enum (tbl, encoding_array) ->
|
||||||
let name = may_new_reference ref_name in
|
let name = may_new_reference ref_name in
|
||||||
let size, cases = enum tbl encoding_array in
|
let size, cases = enum tbl encoding_array in
|
||||||
|
@ -39,6 +39,7 @@ let rec length : type x. x Encoding.t -> x -> int =
|
|||||||
| RangedFloat _ -> Binary_size.float
|
| RangedFloat _ -> Binary_size.float
|
||||||
| Bytes `Fixed n -> n
|
| Bytes `Fixed n -> n
|
||||||
| String `Fixed n -> n
|
| String `Fixed n -> n
|
||||||
|
| Padded (e, n) -> length e value + n
|
||||||
| String_enum (_, arr) ->
|
| String_enum (_, arr) ->
|
||||||
Binary_size.integer_to_size @@ Binary_size.enum_size arr
|
Binary_size.integer_to_size @@ Binary_size.enum_size arr
|
||||||
| Objs { kind = `Fixed n } -> n
|
| Objs { kind = `Fixed n } -> n
|
||||||
|
@ -180,6 +180,10 @@ let rec read_rec : type ret. ret Encoding.t -> state -> ret
|
|||||||
| String (`Fixed n) -> Atom.fixed_length_string n state
|
| String (`Fixed n) -> Atom.fixed_length_string n state
|
||||||
| String `Variable ->
|
| String `Variable ->
|
||||||
Atom.fixed_length_string state.remaining_bytes state
|
Atom.fixed_length_string state.remaining_bytes state
|
||||||
|
| Padded (e, n) ->
|
||||||
|
let v = read_rec e state in
|
||||||
|
ignore (Atom.fixed_length_string n state : string) ;
|
||||||
|
v
|
||||||
| RangedInt { minimum ; maximum } ->
|
| RangedInt { minimum ; maximum } ->
|
||||||
Atom.ranged_int ~minimum ~maximum state
|
Atom.ranged_int ~minimum ~maximum state
|
||||||
| RangedFloat { minimum ; maximum } ->
|
| RangedFloat { minimum ; maximum } ->
|
||||||
|
@ -29,6 +29,7 @@ and layout =
|
|||||||
| Enum of Binary_size.integer * string
|
| Enum of Binary_size.integer * string
|
||||||
| Seq of layout (* For arrays and lists *)
|
| Seq of layout (* For arrays and lists *)
|
||||||
| Ref of string
|
| Ref of string
|
||||||
|
| Padding
|
||||||
|
|
||||||
and fields = field_descr list
|
and fields = field_descr list
|
||||||
|
|
||||||
@ -108,6 +109,8 @@ module Printer_ast = struct
|
|||||||
Format.fprintf ppf "bytes"
|
Format.fprintf ppf "bytes"
|
||||||
| Ref reference ->
|
| Ref reference ->
|
||||||
Format.fprintf ppf "$%s" reference
|
Format.fprintf ppf "$%s" reference
|
||||||
|
| Padding ->
|
||||||
|
Format.fprintf ppf "padding"
|
||||||
| Enum (size, reference) ->
|
| Enum (size, reference) ->
|
||||||
Format.fprintf ppf "%a encoding an enumeration (see %s)"
|
Format.fprintf ppf "%a encoding an enumeration (see %s)"
|
||||||
pp_int (size :> integer_extended)
|
pp_int (size :> integer_extended)
|
||||||
@ -395,11 +398,19 @@ module Encoding = struct
|
|||||||
(Tag 10)
|
(Tag 10)
|
||||||
(obj2
|
(obj2
|
||||||
(req "name" string)
|
(req "name" string)
|
||||||
(req "kind" (constant "Float")))
|
(req "kind" (constant "Ref")))
|
||||||
(function
|
(function
|
||||||
| Ref layout -> Some (layout, ())
|
| Ref layout -> Some (layout, ())
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
(fun (name, ()) -> Ref name)
|
(fun (name, ()) -> Ref name) ;
|
||||||
|
case ~title:"Padding"
|
||||||
|
(Tag 11)
|
||||||
|
(obj1
|
||||||
|
(req "kind" (constant "Padding")))
|
||||||
|
(function
|
||||||
|
| Padding -> Some ()
|
||||||
|
| _ -> None)
|
||||||
|
(fun () -> Padding) ;
|
||||||
])
|
])
|
||||||
|
|
||||||
let kind_enum_cases =
|
let kind_enum_cases =
|
||||||
|
@ -29,6 +29,7 @@ and layout =
|
|||||||
| Enum of Binary_size.integer * string
|
| Enum of Binary_size.integer * string
|
||||||
| Seq of layout (* For arrays and lists *)
|
| Seq of layout (* For arrays and lists *)
|
||||||
| Ref of string
|
| Ref of string
|
||||||
|
| Padding
|
||||||
|
|
||||||
and fields = field_descr list
|
and fields = field_descr list
|
||||||
|
|
||||||
|
@ -207,6 +207,14 @@ module Atom = struct
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let rec skip n state k =
|
||||||
|
let resume buffer =
|
||||||
|
let stream = Binary_stream.push buffer state.stream in
|
||||||
|
try skip n { state with stream } k
|
||||||
|
with Read_error err -> Error err in
|
||||||
|
Atom.fixed_length_string n resume state @@ fun (_, state : string * _) ->
|
||||||
|
k state
|
||||||
|
|
||||||
(** Main recursive reading function, in continuation passing style. *)
|
(** Main recursive reading function, in continuation passing style. *)
|
||||||
let rec read_rec
|
let rec read_rec
|
||||||
: type next ret.
|
: type next ret.
|
||||||
@ -242,6 +250,9 @@ let rec read_rec
|
|||||||
| String `Variable ->
|
| String `Variable ->
|
||||||
let size = remaining_bytes state in
|
let size = remaining_bytes state in
|
||||||
Atom.fixed_length_string size resume state k
|
Atom.fixed_length_string size resume state k
|
||||||
|
| Padded (e, n) ->
|
||||||
|
read_rec e state @@ fun (v, state) ->
|
||||||
|
skip n state @@ (fun state -> k (v, state))
|
||||||
| RangedInt { minimum ; maximum } ->
|
| RangedInt { minimum ; maximum } ->
|
||||||
Atom.ranged_int ~minimum ~maximum resume state k
|
Atom.ranged_int ~minimum ~maximum resume state k
|
||||||
| RangedFloat { minimum ; maximum } ->
|
| RangedFloat { minimum ; maximum } ->
|
||||||
|
@ -216,6 +216,9 @@ let rec write_rec : type a. a Encoding.t -> state -> a -> unit =
|
|||||||
| String `Variable ->
|
| String `Variable ->
|
||||||
let length = String.length value in
|
let length = String.length value in
|
||||||
Atom.fixed_kind_string length state value
|
Atom.fixed_kind_string length state value
|
||||||
|
| Padded (e, n) ->
|
||||||
|
write_rec e state value ;
|
||||||
|
Atom.fixed_kind_string n state (String.make n '\000')
|
||||||
| RangedInt { minimum ; maximum } ->
|
| RangedInt { minimum ; maximum } ->
|
||||||
Atom.ranged_int ~minimum ~maximum state value
|
Atom.ranged_int ~minimum ~maximum state value
|
||||||
| RangedFloat { minimum ; maximum } ->
|
| RangedFloat { minimum ; maximum } ->
|
||||||
|
@ -402,6 +402,7 @@ module Encoding: sig
|
|||||||
module Fixed : sig
|
module Fixed : sig
|
||||||
val string : int -> string encoding
|
val string : int -> string encoding
|
||||||
val bytes : int -> MBytes.t encoding
|
val bytes : int -> MBytes.t encoding
|
||||||
|
val add_padding : 'a encoding -> int -> 'a encoding
|
||||||
end
|
end
|
||||||
|
|
||||||
(** Create encodings that produce data of a variable length when binary encoded.
|
(** Create encodings that produce data of a variable length when binary encoded.
|
||||||
|
@ -83,6 +83,7 @@ type 'a desc =
|
|||||||
| Float : float desc
|
| Float : float desc
|
||||||
| Bytes : Kind.length -> MBytes.t desc
|
| Bytes : Kind.length -> MBytes.t desc
|
||||||
| String : Kind.length -> string desc
|
| String : Kind.length -> string desc
|
||||||
|
| Padded : 'a t * int -> 'a desc
|
||||||
| String_enum : ('a, string * int) Hashtbl.t * 'a array -> 'a desc
|
| String_enum : ('a, string * int) Hashtbl.t * 'a array -> 'a desc
|
||||||
| Array : 'a t -> 'a array desc
|
| Array : 'a t -> 'a array desc
|
||||||
| List : 'a t -> 'a list desc
|
| List : 'a t -> 'a list desc
|
||||||
@ -187,6 +188,11 @@ and classify_desc : type a. a desc -> Kind.t = fun e ->
|
|||||||
(* Tagged *)
|
(* Tagged *)
|
||||||
| Bytes kind -> (kind :> Kind.t)
|
| Bytes kind -> (kind :> Kind.t)
|
||||||
| String kind -> (kind :> Kind.t)
|
| String kind -> (kind :> Kind.t)
|
||||||
|
| Padded ({ encoding }, n) -> begin
|
||||||
|
match classify_desc encoding with
|
||||||
|
| `Fixed m -> `Fixed (n+m)
|
||||||
|
| _ -> assert false (* by construction (see [Fixed.padded]) *)
|
||||||
|
end
|
||||||
| String_enum (_, cases) ->
|
| String_enum (_, cases) ->
|
||||||
`Fixed Binary_size.(integer_to_size @@ enum_size cases)
|
`Fixed Binary_size.(integer_to_size @@ enum_size cases)
|
||||||
| Obj (Opt { kind }) -> (kind :> Kind.t)
|
| Obj (Opt { kind }) -> (kind :> Kind.t)
|
||||||
@ -214,14 +220,19 @@ let make ?json_encoding encoding = { encoding ; json_encoding }
|
|||||||
module Fixed = struct
|
module Fixed = struct
|
||||||
let string n =
|
let string n =
|
||||||
if n <= 0 then
|
if n <= 0 then
|
||||||
invalid_arg "Cannot create a string encoding fo negative or null fixed length."
|
invalid_arg "Cannot create a string encoding of negative or null fixed length." ;
|
||||||
else
|
make @@ String (`Fixed n)
|
||||||
make @@ String (`Fixed n)
|
|
||||||
let bytes n =
|
let bytes n =
|
||||||
if n <= 0 then
|
if n <= 0 then
|
||||||
invalid_arg "Cannot create a byte encoding fo negative or null fixed length."
|
invalid_arg "Cannot create a byte encoding of negative or null fixed length." ;
|
||||||
else
|
make @@ Bytes (`Fixed n)
|
||||||
make @@ Bytes (`Fixed n)
|
let add_padding e n =
|
||||||
|
if n <= 0 then
|
||||||
|
invalid_arg "Cannot create a padding of negative or null fixed length." ;
|
||||||
|
match classify e with
|
||||||
|
| `Fixed _ ->
|
||||||
|
make @@ Padded (e, n)
|
||||||
|
| _ -> invalid_arg "Cannot pad non-fixed size encoding"
|
||||||
end
|
end
|
||||||
|
|
||||||
let rec is_zeroable: type t. t encoding -> bool = fun e ->
|
let rec is_zeroable: type t. t encoding -> bool = fun e ->
|
||||||
@ -250,6 +261,7 @@ let rec is_zeroable: type t. t encoding -> bool = fun e ->
|
|||||||
| Float -> false
|
| Float -> false
|
||||||
| Bytes _ -> false
|
| Bytes _ -> false
|
||||||
| String _ -> false
|
| String _ -> false
|
||||||
|
| Padded _ -> false
|
||||||
| String_enum _ -> false
|
| String_enum _ -> false
|
||||||
(* true in some cases, but in practice always protected by Dynamic *)
|
(* true in some cases, but in practice always protected by Dynamic *)
|
||||||
| Array _ -> true (* 0-element array *)
|
| Array _ -> true (* 0-element array *)
|
||||||
@ -584,6 +596,7 @@ let rec is_nullable: type t. t encoding -> bool = fun e ->
|
|||||||
| Float -> false
|
| Float -> false
|
||||||
| Bytes _ -> false
|
| Bytes _ -> false
|
||||||
| String _ -> false
|
| String _ -> false
|
||||||
|
| Padded (e, _) -> is_nullable e
|
||||||
| String_enum _ -> false
|
| String_enum _ -> false
|
||||||
| Array _ -> false
|
| Array _ -> false
|
||||||
| List _ -> false
|
| List _ -> false
|
||||||
|
@ -41,6 +41,7 @@ type 'a desc =
|
|||||||
| Float : float desc
|
| Float : float desc
|
||||||
| Bytes : Kind.length -> MBytes.t desc
|
| Bytes : Kind.length -> MBytes.t desc
|
||||||
| String : Kind.length -> string desc
|
| String : Kind.length -> string desc
|
||||||
|
| Padded : 'a t * int -> 'a desc
|
||||||
| String_enum : ('a, string * int) Hashtbl.t * 'a array -> 'a desc
|
| String_enum : ('a, string * int) Hashtbl.t * 'a array -> 'a desc
|
||||||
| Array : 'a t -> 'a array desc
|
| Array : 'a t -> 'a array desc
|
||||||
| List : 'a t -> 'a list desc
|
| List : 'a t -> 'a list desc
|
||||||
@ -148,6 +149,7 @@ val is_tup : 'a encoding -> bool
|
|||||||
module Fixed : sig
|
module Fixed : sig
|
||||||
val string : int -> string encoding
|
val string : int -> string encoding
|
||||||
val bytes : int -> MBytes.t encoding
|
val bytes : int -> MBytes.t encoding
|
||||||
|
val add_padding : 'a encoding -> int -> 'a encoding
|
||||||
end
|
end
|
||||||
module Variable : sig
|
module Variable : sig
|
||||||
val string : string encoding
|
val string : string encoding
|
||||||
|
@ -186,6 +186,7 @@ let rec json : type a. a Encoding.desc -> a Json_encoding.encoding =
|
|||||||
s in
|
s in
|
||||||
conv check check string
|
conv check check string
|
||||||
| String _ -> string
|
| String _ -> string
|
||||||
|
| Padded (e, _) -> get_json e
|
||||||
| Bytes (`Fixed expected) ->
|
| Bytes (`Fixed expected) ->
|
||||||
let check s =
|
let check s =
|
||||||
let found = MBytes.length s in
|
let found = MBytes.length s in
|
||||||
|
@ -48,6 +48,7 @@ val string_enum : (string * 'a) list -> 'a encoding
|
|||||||
module Fixed : sig
|
module Fixed : sig
|
||||||
val string : int -> string encoding
|
val string : int -> string encoding
|
||||||
val bytes : int -> MBytes.t encoding
|
val bytes : int -> MBytes.t encoding
|
||||||
|
val add_padding : 'a encoding -> int -> 'a encoding
|
||||||
end
|
end
|
||||||
|
|
||||||
module Variable : sig
|
module Variable : sig
|
||||||
|
Loading…
Reference in New Issue
Block a user