package wire
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
Binary wire format DSL with EverParse 3D output
Install
dune-project
Dependency
Authors
Maintainers
Sources
wire-1.0.0.tbz
sha256=323f48e6cb897fe48aac558b09bb25134d3b19fec37b20d7930eec15f387c238
sha512=00c77f8672396ab15d993602db9bab95d2478ace1f569606f0140ed25d7ff852525e53436d95e5061442a6ea8b5650549239c68ef861b4b921b4a53faac97eb7
doc/src/wire/field.ml.html
Source file field.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 166type 'a t = { name : string; typ : 'a Types.typ; constraint_ : bool Types.expr option; action : Types.action option; doc : string option; } type 'a anon = { anon_typ : 'a Types.typ } let pp ppf f = Fmt.pf ppf "%s" f.name let combine a b = match (a, b) with | None, c | c, None -> c | Some a, Some b -> Some (Types.And (a, b)) let rec has_int64_slot : type a. a Types.typ -> bool = fun typ -> let open Types in match typ with | Uint64 _ | Int64 _ -> true | Where { inner; _ } -> has_int64_slot inner | Optional { inner; _ } -> has_int64_slot inner | Optional_or { inner; _ } -> has_int64_slot inner | _ -> false let reject_no_int64_slot ~combinator name typ = if not (has_int64_slot typ) then Fmt.invalid_arg "Wire.Field.%s: field %S does not have a full-width int64 validation slot" combinator name let v name ?constraint_ ?self_constraint ?self_int64 ?action ?doc typ = if Option.is_some self_int64 then reject_no_int64_slot ~combinator:"v ?self_int64" name typ; let constraint_ = constraint_ |> combine (Option.map (fun f -> f (Types.Ref (Types.I, name))) self_constraint) |> combine (Option.map (fun f -> f (Types.Ref (Types.I64, name))) self_int64) in { name; typ; constraint_; action; doc } (* Field decorations: produce a field directly from a typ + optional/ repeat metadata. Exposing these only at the field level keeps [Wire.optional]/[Wire.repeat] off the typ-level surface so the resulting decoration cannot be nested inside [array]/[where]/etc. where 3D has no projection for it. *) let optional name ?constraint_ ?self_constraint ?self_int64 ?action ~present typ = v name ?constraint_ ?self_constraint ?self_int64 ?action (Types.optional present typ) let optional_or name ?constraint_ ?self_constraint ?self_int64 ?action ~present ~default typ = v name ?constraint_ ?self_constraint ?self_int64 ?action (Types.optional_or present ~default typ) (* A sub-codec ending in a greedy field ([all_bytes] / [all_zeros]) reads "the rest of the buffer" as its tail, so it cannot be iterated as a repeat element (the first element would consume everything). *) let codec_ends_greedy (s : Types.struct_) = match List.rev s.fields with | Types.Field f :: _ -> Types.is_greedy f.field_typ | [] -> false (* Types decodable as a casetype case body inside a repeat: exactly the set [Codec.read_elem] handles. Unlike a bare repeat element, a lone [bits] field and a bounded [zeroterm_at_most] are allowed here, because the enclosing casetype packs them after the tag with a fixed footprint. A nested [array] / [nested] region or an [optional] has no fixed footprint and is rejected. *) let rec is_repeat_case_body : type a. a Types.typ -> bool = fun typ -> let open Types in match typ with | Uint8 | Uint16 _ | Uint32 _ | Uint63 _ | Uint64 _ | Int8 | Int16 _ | Int32 _ | Int64 _ | Float32 _ | Float64 _ | Unit | Zeroterm | Bits _ -> true | Uint_var { size = Int _; _ } -> true | Byte_array { size = Int _ } | Byte_slice { size = Int _ } -> true | Zeroterm_at_most { size = Int _ } -> true | Codec { codec_struct; _ } -> not (codec_ends_greedy codec_struct) | Casetype { cases; _ } -> List.for_all (fun (Case_branch { cb_inner; _ }) -> is_repeat_case_body cb_inner) cases | Map { inner; _ } -> is_repeat_case_body inner | Where { inner; _ } -> is_repeat_case_body inner | Enum { base; _ } -> is_repeat_case_body base | _ -> false (* An element [repeat]/[repeat_seq] can both project to 3D and decode one element at a time: a fixed-width scalar / byte span, a NUL-terminated string, or a self-bounded sub-codec / casetype. [Map] / [Where] / [Enum] are transparent wrappers, so look through them. A casetype is repeatable only when every case body is itself decodable as a repeat element ([is_repeat_case_body]). A sub-codec must also be [nz] (have a fixed-size field): EverParse projects [repeat] as a byte-budget list of the codec's named struct, and a list over a possibly-empty element does not extract. Everything else (a sub-byte [bits] field, a refined or at-most byte span whose per-element validation the byte-budget loop does not run, greedy [all_zeros], a nested [array] / [nested]) has no clean per-element 3D projection. *) let rec is_repeat_element : type a. a Types.typ -> bool = fun typ -> let open Types in match typ with | Uint8 | Uint16 _ | Uint32 _ | Uint63 _ | Uint64 _ | Int8 | Int16 _ | Int32 _ | Int64 _ | Float32 _ | Float64 _ | Uint_var _ | Zeroterm -> true (* [Unit] is 0-width: a byte-budget list of it carries no bytes and projects to a zero-size element EverParse refuses to extract, like the [array] case. *) | Byte_array { size = Int _ } | Byte_slice { size = Int _ } -> true | Codec { codec_struct; _ } -> (not (codec_ends_greedy codec_struct)) && Types.struct_nz codec_struct | Casetype { cases; _ } -> List.for_all (fun (Case_branch { cb_inner; _ }) -> is_repeat_case_body cb_inner) cases | Map { inner; _ } -> is_repeat_element inner | Where { inner; _ } -> is_repeat_element inner | Enum { base; _ } -> is_repeat_element base | _ -> false let reject_unprojectable_repeat ~combinator typ = if not (is_repeat_element typ) then Fmt.invalid_arg "Wire.%s: element type does not project to 3D as a repeat element -- the \ byte-budget loop only supports fixed-width scalars and byte spans, \ NUL-terminated strings, sub-codecs, and casetypes." combinator let repeat name ?constraint_ ?self_constraint ?self_int64 ?action ~size typ = reject_unprojectable_repeat ~combinator:"repeat" typ; v name ?constraint_ ?self_constraint ?self_int64 ?action (Types.repeat ~size typ) let repeat_seq name ?constraint_ ?self_constraint ?self_int64 ?action ~seq ~size typ = reject_unprojectable_repeat ~combinator:"repeat_seq" typ; v name ?constraint_ ?self_constraint ?self_int64 ?action (Types.repeat_seq seq ~size typ) let anon typ = { anon_typ = typ } let ref f = Types.Ref (Types.I, f.name) let int f = Types.Ref (Types.I, f.name) let int64 f = reject_no_int64_slot ~combinator:"int64" f.name f.typ; Types.Ref (Types.I64, f.name) let name f = f.name let typ f = f.typ let constraint_ f = f.constraint_ let action f = f.action let doc f = f.doc type packed = Named : 'a t -> packed | Anon : 'a anon -> packed let decl_of_packed = function | Named f -> Types.field f.name ?constraint_:f.constraint_ ?action:f.action ?doc:f.doc f.typ | Anon a -> Types.anon_field a.anon_typ
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>