Data_encoding: proper handling of kind in Dynamic_size

This commit is contained in:
Grégoire Henry 2018-05-31 13:12:33 +02:00 committed by Benjamin Canou
parent 6922a793fe
commit 499377bcc4
3 changed files with 58 additions and 38 deletions

View File

@ -72,9 +72,7 @@ let fixup_references uf =
Named_field (name, kind, fixup_layout layout) Named_field (name, kind, fixup_layout layout)
| Anonymous_field (kind, layout) -> | Anonymous_field (kind, layout) ->
Anonymous_field (kind, fixup_layout layout) Anonymous_field (kind, fixup_layout layout)
| Dynamic_field i -> | (Dynamic_size_field _ | Optional_field _) as field -> field in
Dynamic_field i
| (Option_indicator_field _) as field -> field in
function function
| Obj { fields } -> Obj { fields = List.map field fields } | Obj { fields } -> Obj { fields = List.map field fields }
| Cases ({ cases } as x) -> | Cases ({ cases } as x) ->
@ -141,31 +139,33 @@ let describe (type x) ?toplevel_name (encoding : x Encoding.t) =
uf_add_name name ; uf_add_name name ;
name in name in
let rec extract_dynamic : let rec extract_dynamic :
type x. string option -> x Encoding.desc -> bool * string option * pdesc = type x. string option -> x Encoding.desc -> Binary_size.unsigned_integer option * string option * pdesc =
fun ref_name -> function fun ref_name -> function
| Conv { encoding } -> extract_dynamic ref_name encoding.encoding | Conv { encoding } -> extract_dynamic ref_name encoding.encoding
| Describe { id = ref_name ; encoding } -> extract_dynamic (Some ref_name) encoding.encoding | Describe { id = ref_name ; encoding } -> extract_dynamic (Some ref_name) encoding.encoding
| Splitted { encoding } -> extract_dynamic ref_name encoding.encoding | Splitted { encoding } -> extract_dynamic ref_name encoding.encoding
| Delayed f -> extract_dynamic ref_name (f ()).encoding | Delayed f -> extract_dynamic ref_name (f ()).encoding
| Dynamic_size { encoding } -> (true, ref_name, P encoding.encoding) | Dynamic_size { kind ; encoding } -> (Some kind, ref_name, P encoding.encoding)
| enc -> (false, ref_name, P enc) in | enc -> (None, ref_name, P enc) in
let rec field_descr : let rec field_descr :
type a. recursives -> references -> type a. recursives -> references ->
a Encoding.field -> Binary_schema.field_descr list * references = a Encoding.field -> Binary_schema.field_descr list * references =
fun recursives references -> function fun recursives references -> function
| Req { name ; encoding = { encoding } } | Req { name ; encoding = { encoding } }
| Dft { name ; encoding = { encoding } } -> | Dft { name ; encoding = { encoding } } -> begin
let (dynamics, ref_name, P field) = extract_dynamic None encoding in let (dynamics, ref_name, P field) = extract_dynamic None encoding in
let (layout, references) = layout ref_name recursives references field in let (layout, references) = layout ref_name recursives references field in
if layout = Zero_width && dynamics then if layout = Zero_width then
([], references) (* FIXME what if (dynamic_size empty) ?? *) ([], references)
else else
let field_descr = let field_descr =
Binary_schema.Named_field (name, classify_desc field, layout) in Binary_schema.Named_field (name, classify_desc field, layout) in
if dynamics then match dynamics with
([ Dynamic_field 1 ; field_descr ], references) | Some kind ->
else ([ Dynamic_size_field (ref_name, 1, kind) ; field_descr ], references)
| None ->
([ field_descr], references) ([ field_descr], references)
end
| Opt { kind = `Variable ; name ; encoding = { encoding } } -> | Opt { kind = `Variable ; name ; encoding = { encoding } } ->
let (layout, references) = let (layout, references) =
layout None recursives references encoding in layout None recursives references encoding in
@ -173,7 +173,7 @@ let describe (type x) ?toplevel_name (encoding : x Encoding.t) =
| Opt { kind = `Dynamic ; name ; encoding = { encoding } } -> | Opt { kind = `Dynamic ; name ; encoding = { encoding } } ->
let (layout, references) = let (layout, references) =
layout None recursives references encoding in layout None recursives references encoding in
([Binary_schema.Option_indicator_field name ; Named_field (name, classify_desc encoding, layout) ], references) ([Binary_schema.Optional_field name ; Named_field (name, classify_desc encoding, layout) ], references)
and obj fields = and obj fields =
Binary_schema.Obj { fields } Binary_schema.Obj { fields }
and union : and union :
@ -241,10 +241,10 @@ let describe (type x) ?toplevel_name (encoding : x Encoding.t) =
| Empty -> ([ Anonymous_field (`Fixed 0, Zero_width) ], references) | Empty -> ([ Anonymous_field (`Fixed 0, Zero_width) ], references)
| Ignore -> ([ Anonymous_field (`Fixed 0, Zero_width) ], references) | Ignore -> ([ Anonymous_field (`Fixed 0, Zero_width) ], references)
| Constant _ -> ([ Anonymous_field (`Fixed 0, Zero_width) ], references) | Constant _ -> ([ Anonymous_field (`Fixed 0, Zero_width) ], references)
| Dynamic_size { encoding } -> | Dynamic_size { kind ; encoding } ->
let (fields, refs) = let (fields, refs) =
fields None recursives references encoding.encoding in fields None recursives references encoding.encoding in
(Dynamic_field (List.length fields) :: fields, refs) (Dynamic_size_field (None, List.length fields, kind) :: fields, refs)
| Check_size { encoding } -> | Check_size { encoding } ->
fields ref_name recursives references encoding.encoding fields ref_name recursives references encoding.encoding
| Conv { encoding } -> | Conv { encoding } ->

View File

@ -14,8 +14,8 @@ type integer_extended = [ Binary_size.integer | `Int32 | `Int64 ]
type field_descr = type field_descr =
| Named_field of string * Kind.t * layout | Named_field of string * Kind.t * layout
| Anonymous_field of Kind.t * layout | Anonymous_field of Kind.t * layout
| Dynamic_field of int | Dynamic_size_field of string option * int * Binary_size.unsigned_integer
| Option_indicator_field of string | Optional_field of string
and layout = and layout =
| Zero_width | Zero_width
@ -83,22 +83,22 @@ module Printer = struct
| Int integer -> | Int integer ->
Format.fprintf ppf "%a" pp_int integer Format.fprintf ppf "%a" pp_int integer
| Bool -> | Bool ->
Format.fprintf ppf "8 bit Signed Integer, with 0 for false and 255 for true" Format.fprintf ppf "8 bit unsigned integer: 0 for false and 255 for true"
| RangedInt (minimum, maximum) -> | RangedInt (minimum, maximum) ->
Format.fprintf ppf "%a in the range %d to %d" Format.fprintf ppf "%a in the range %d to %d"
pp_int ((Binary_size.range_to_size ~minimum ~maximum) :> integer_extended) minimum maximum pp_int ((Binary_size.range_to_size ~minimum ~maximum) :> integer_extended) minimum maximum
| RangedFloat (minimum, maximum) -> | RangedFloat (minimum, maximum) ->
Format.fprintf ppf Format.fprintf ppf
"Double precision (8 byte) floating point number in the range %f to %f" "Double precision (8 bytes) floating point number in the range %f to %f"
minimum maximum minimum maximum
| Float -> | Float ->
Format.fprintf ppf "Double precision (8 byte) floating point number" Format.fprintf ppf "Double precision (8 bytes) floating point number"
| Bytes -> | Bytes ->
Format.fprintf ppf "Bytes" Format.fprintf ppf "Bytes"
| String -> | String ->
Format.fprintf ppf "String" Format.fprintf ppf "String"
| Ref reference -> | Ref reference ->
Format.fprintf ppf "%s" reference Format.fprintf ppf "$%s" reference
| 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)
@ -107,7 +107,7 @@ module Printer = struct
| Seq data -> Format.fprintf ppf "Sequence of %a" pp_layout data | Seq data -> Format.fprintf ppf "Sequence of %a" pp_layout data
let binary_table_headers = [ "Name" ; "Kind" ; "Data" ] let binary_table_headers = [ "Name" ; "Size" ; "Contents" ]
let enum_headers = [ "Case number" ; "Encoded string" ] let enum_headers = [ "Case number" ; "Encoded string" ]
let pp_tag_size ppf tag = let pp_tag_size ppf tag =
@ -126,17 +126,29 @@ module Printer = struct
function function
| Named_field (name, kind, desc) -> | Named_field (name, kind, desc) ->
[ name ; Format.asprintf "%a" pp_kind kind ; string_of_layout desc ] [ name ; Format.asprintf "%a" pp_kind kind ; string_of_layout desc ]
| Dynamic_field i -> | Dynamic_size_field (Some name, 1, size) ->
[ Format.asprintf "Size of next %d fields" i ; [ Format.asprintf "# bytes in field \"%s\"" name ;
Format.asprintf "%a" pp_kind (`Fixed 4) ; string_of_layout (Int `Int32) ] Format.asprintf "%a"
pp_kind (`Fixed (Binary_size.integer_to_size size)) ;
string_of_layout (Int (size :> integer_extended)) ]
| Dynamic_size_field (None, 1, size) ->
[ Format.asprintf "# bytes in next field" ;
Format.asprintf "%a"
pp_kind (`Fixed (Binary_size.integer_to_size size)) ;
string_of_layout (Int (size :> integer_extended)) ]
| Dynamic_size_field (_, i, size) ->
[ Format.asprintf "# bytes in next %d fields" i ;
Format.asprintf "%a"
pp_kind (`Fixed (Binary_size.integer_to_size size)) ;
string_of_layout (Int (size :> integer_extended)) ]
| Anonymous_field (kind, desc) -> | Anonymous_field (kind, desc) ->
[ "Unnamed field " ^ anon_num () ; [ "Unnamed field " ^ anon_num () ;
Format.asprintf "%a" pp_kind kind ; Format.asprintf "%a" pp_kind kind ;
string_of_layout desc ] string_of_layout desc ]
| Option_indicator_field name -> | Optional_field name ->
[ "Presence of " ^ name ; [ Format.asprintf "? presence of field \"%s\"" name ;
Format.asprintf "%a" pp_kind (`Fixed 1) ; Format.asprintf "%a" pp_kind (`Fixed 1) ;
"0 if not present and 1 if present" ] string_of_layout Bool ]
let toplevel ({ name ; description }, encoding) = let toplevel ({ name ; description }, encoding) =
match encoding with match encoding with
@ -382,6 +394,12 @@ module Encoding = struct
| _ -> None) | _ -> None)
(fun (n, _) -> `Fixed n)) :: (kind_enum_cases ())) (fun (n, _) -> `Fixed n)) :: (kind_enum_cases ()))
let unsigned_integer_encoding =
string_enum
[("Uint30", `Uint30) ;
("Uint16", `Uint16) ;
("Uint8", `Uint8) ]
let field_descr_encoding = let field_descr_encoding =
let dynamic_layout_encoding = dynamic_size layout_encoding in let dynamic_layout_encoding = dynamic_size layout_encoding in
def "schema.field" @@ def "schema.field" @@
@ -407,20 +425,22 @@ module Encoding = struct
(fun (kind, _, layout) -> Anonymous_field (layout, kind)) ; (fun (kind, _, layout) -> Anonymous_field (layout, kind)) ;
case ~name:"Dynamic_field" case ~name:"Dynamic_field"
(Tag 2) (Tag 2)
(obj2 (obj4
(req "kind" (constant "dyn")) (req "kind" (constant "dyn"))
(req "num_fields" int31)) (opt "name" string)
(function Dynamic_field i -> Some ((), i) (req "num_fields" int31)
(req "size" unsigned_integer_encoding))
(function Dynamic_size_field (name, i, size) -> Some ((), name, i, size)
| _ -> None) | _ -> None)
(fun ((), i) -> Dynamic_field i) ; (fun ((), name, i, size) -> Dynamic_size_field (name, i, size)) ;
case ~name:"Option_indicator_field" case ~name:"Optional_field"
(Tag 3) (Tag 3)
(obj2 (obj2
(req "kind" (constant "option_indicator")) (req "kind" (constant "option_indicator"))
(req "name" string)) (req "name" string))
(function Option_indicator_field s -> Some ((), s) (function Optional_field s -> Some ((), s)
| _ -> None) | _ -> None)
(fun ((), s) -> Option_indicator_field s) (fun ((), s) -> Optional_field s)
] ]
let tag_size_encoding = let tag_size_encoding =

View File

@ -14,8 +14,8 @@ type integer_extended = [ Binary_size.integer | `Int32 | `Int64 ]
type field_descr = type field_descr =
| Named_field of string * Encoding.Kind.t * layout | Named_field of string * Encoding.Kind.t * layout
| Anonymous_field of Encoding.Kind.t * layout | Anonymous_field of Encoding.Kind.t * layout
| Dynamic_field of int | Dynamic_size_field of string option * int * Binary_size.unsigned_integer
| Option_indicator_field of string | Optional_field of string
and layout = and layout =
| Zero_width | Zero_width