package wire

  1. Overview
  2. Docs

Module Wire.CodecSource

Sourcetype 'r t

Sealed codec for record values of type 'r.

Sourcetype ('a, 'r) field

A field bound to a record projection. The binding retains the identity of its source Field.t: an accessor may use another binding of that same source field, but not a newly declared field that merely has the same name. One source field may still be shared by multiple codecs.

Sourcetype ('f, 'r) fields =
  1. | [] : ('r, 'r) fields
  2. | :: : ('a, 'r) field * ('f, 'r) fields -> ('a -> 'f, 'r) fields
Sourceval ($) : 'a Field.t -> ('r -> 'a) -> ('a, 'r) field

f $ proj binds a Field.t to a record projection.

Sourceval v : string -> ?where:bool expr -> ?doc:string -> 'f -> ('f, 'r) fields -> 'r t

v name constructor fields seals a codec. ?doc attaches a free-text note (e.g. an RFC citation) that the documentation projection renders as a /*++ ... --*/ comment on the codec's 3D typedef; see Everparse.project.

?where is a whole-codec constraint. Mentioning only Param.input parameters, it projects to 3D's where clause, which EverParse checks before reading any field. 3D's where sees parameters only, so an expression that also refers to fields projects as a refinement on the last field it mentions, the earliest point at which 3D can evaluate it.

let codec =
  Codec.v "Packet"
    (fun version length -> { version; length })
    Codec.
      [ (f_version $ fun p -> p.version); (f_length $ fun p -> p.length) ]
Sourceval rename : string -> 'r t -> 'r t

rename n c is c with its name set to n. The name only determines the generated 3D struct name, not the wire encoding, so renaming leaves encode/decode and all field constraints unchanged. Use it to give a generically built codec a unique, meaningful name for projection or code generation.

Sourceval doc : 'r t -> string option

doc c is the note attached via v's ?doc, if any.

Sourceval wire_size_opt : 'r t -> int option

Fixed wire size of the codec, or None if it is variable-size.

Sourceval wire_size : 'r t -> int

Fixed wire size of the codec.

Raises Invalid_argument if the codec is variable-size.

Sourceval min_wire_size : 'r t -> int

Minimum wire size of the codec.

Sourceval wire_size_at : ?env:Param.env -> 'r t -> bytes -> int -> int

Computes the actual wire size from a buffer at the given base offset. A codec whose field sizes are driven by an input param needs ?env to resolve them, and raises Invalid_argument without it, the same as decode: an unbound param reads 0, which would silently measure a param-sized field as empty and report an extent shorter than the record.

Sourceval size_of_value : ?env:Param.env -> 'r t -> 'r -> int

size_of_value c v returns the number of bytes that encode c v will write for value v. For fixed-size codecs, this is the same as wire_size; for dynamic-size codecs, the result depends on v. Raises Invalid_argument for a value encode would refuse, such as a casetype value no case projects.

Sourceval env : 'r t -> Param.env

env c creates a fresh parameter environment for codec c.

Sourceval decode : ?consume:consumption -> ?env:Param.env -> 'r t -> bytes -> int -> ('r, parse_error) result

decode ?env c buf off decodes one record value at the given base offset. consume defaults to `Prefix, accepting one record followed by more bytes. `All requires the record to end at Bytes.length buf and returns a Trailing_bytes error otherwise.

If ?env is supplied, input params are read from it and output params are written back to it on success.

Raises Invalid_argument when ?env was created for a different codec, or when the codec has input params and the env is missing or leaves one unbound, the same precondition encode enforces: an unbound input param would resolve a parametric field size to 0 and silently truncate the field.

Sourceval decode_exn : ?consume:consumption -> ?env:Param.env -> 'r t -> bytes -> int -> 'r

Like decode but raises Parse_error on failure.

Sourceval encode : ?env:Param.env -> 'r t -> 'r -> bytes -> int -> unit

encode ?env c r buf off encodes one record value into a buffer at the given base offset.

For codecs with input parameters (e.g. byte_array ~size:(Param.expr p)), the caller picks each parametric field's width and tells the encoder via ?env (built with Codec.env c |> Param.bind p N). The bound widths must match the field values in r; the encoder cross-checks them.

Raises Invalid_argument when ?env was created for a different codec, when the codec has parameters and no env is supplied, when the env left any input param unbound (the error names it), when the destination buffer is too short, or when a parametric byte field's value length does not match its env-bound size.

Also raises Invalid_argument on a record decode would reject: a closed enum field carrying an unlisted value, an all_zeros field carrying a non-zero byte, a byte_array_where byte failing its refinement, or a where clause or field ~constraint_ that does not hold for the values given. Encode never emits bytes its own decoder refuses. Field ~actions are not run by encode.

Encode is not all-or-nothing: it writes the record field by field and checks the result, so after any of those raises the bytes from off on hold a partial record and must be treated as scrap. Use to_bytes or to_string when no destination buffer should escape on failure. Only the single-field set rolls its write back.

Sourceval to_bytes : ?env:Param.env -> 'r t -> 'r -> bytes

to_bytes ?env c r encodes r into freshly allocated bytes, then runs the same validation pass as validate. Field ~actions therefore fire, and a rejecting action raises Invalid_argument instead of allowing bytes that decode would reject to escape. Action assignments are not written back to ?env. Because the buffer is fresh, no partially encoded buffer is returned when either pass raises.

Sourceval to_string : ?env:Param.env -> 'r t -> 'r -> string

String counterpart of to_bytes. The result is backed by the fresh encoding buffer; no mutable alias to that buffer escapes.

Sourceval validate : ?env:Param.env -> 'r t -> bytes -> int -> unit

validate ?env c buf off checks field ~constraint_ and ~where clauses without constructing a record. Field ~actions do fire, so a rejecting action fails validation, but assigned output parameters are not written back to ?env. ?env supplies bindings for any Param.input referenced in those clauses.

Raises Invalid_argument when ?env belongs to another codec or leaves an input parameter unbound, and Parse_error on failure.

Sourceval get : ?env:Param.env -> 'r t -> ('a, 'r) field -> (bytes -> int -> 'a) Staged.t

Staged field reader. If the field has an ~action, the action fires on every read. Pass ~env to sync output parameters after each action and to resolve a dependent layout's parameters; omit it for parameter-free accessors. Raises Invalid_argument when the codec has input params and ~env is omitted, when it was created for another codec, or when the field binding does not share its source Field.t with the field in the codec: an unbound param reads 0, which would stage the reader onto the bytes in front of the field, while a same-named lookalike could interpret those bytes with a different wire type.

Does not check ~where clauses or other fields' constraints -- call validate first on untrusted input.

Sourceval set : ?env:Param.env -> 'r t -> ('a, 'r) field -> (bytes -> int -> 'a -> unit) Staged.t

Staged field writer. ~env supplies the input params a dependent field layout is measured from; omit it for parameter-free codecs. Raises Invalid_argument on the same terms as get: an unbound param reads 0, which would put the write on a field the caller never named and leave the one it did name unchanged.

Does not check constraints or fire actions -- call validate after a batch of writes to verify constraints still hold.

Sourceval field_ref : ('a, 'r) field -> int expr

Field reference expression from a bound field handle.

Sourceval field_readers : 'r t -> (string * (bytes -> int -> int)) list

field_readers c is the decoder's own reader for every named int-valued field of c, keyed by field name: read buf base is the value decode makes of that field's bytes, converted to int (a Map reports the raw value it was decoded from, which is what the wire carries). Composite fields read as 0.

Unlike get it needs no field handle, so a caller holding only a type-erased codec can still read a field by name -- which is how the differential fuzzer compares the OCaml decoder against a generated C validator field by field. Raises Parse_error when the field's bytes are out of the buffer, or when the value does not fit an OCaml int.

Slice navigation

Zero-copy access to the offset/length of a byte_slice field. The naive nesting Slice.first (Codec.get c f buf base) forces Codec.get to allocate a fresh Bytesrw.Bytes.Slice.t -- 4 words -- only for Slice.first to extract one int and discard the rest. slice_offset skips the make and returns the int directly.

Sourceval slice_offset : 'r t -> (Bytesrw.Bytes.Slice.t, 'r) field -> (bytes -> int -> int) Staged.t

slice_offset c f is a staged reader returning the absolute byte offset of slice field f within the buffer. Stage once with Codec.slice_offset c f |> Staged.unstage, then call the resulting buf -> base -> int reader on the hot path -- 0 allocations versus Slice.first (Codec.get c f buf base)'s 4 words.

Type-restricted to Slice.t fields, so passing a non-slice field is a compile-time error. Raises Invalid_argument if f was not bound from the source Field.t used in c.

Sourceval slice_length : 'r t -> (Bytesrw.Bytes.Slice.t, 'r) field -> (bytes -> int -> int) Staged.t

slice_length c f is a staged reader returning the byte length of slice field f. Raises Invalid_argument if f was not bound from the source Field.t used in c.

Bitfield batch access

For multiple bitfield fields sharing the same base word, load_word reads the word once and extract retrieves individual fields with pure shift+mask -- no redundant memory loads.

Sourcetype bitfield

A bitfield accessor -- shift and mask for one field in a packed word.

Sourceval bitfield : 'r t -> (int, 'r) field -> bitfield

bitfield codec field returns a bitfield accessor. Raises Invalid_argument if field was not bound from the source Field.t used in codec.

Sourceval load_word : bitfield -> (bytes -> int -> Optint.t) Staged.t

Staged word reader. Force once, reuse for every read. Fields in the same base word share the same underlying reader -- call once and use extract on the result for each field. The word is an Optint.t so a 32-bit base survives a platform whose int is narrower: an unboxed native int on a 64-bit host.

Sourceval extract : bitfield -> Optint.t -> int

extract bf word extracts the field from a pre-loaded word. Pure shift+mask, no memory access.

Struct validator

For a Types.struct_ (e.g. from EverParse 3D), build a validator directly without going through v's record-constructor machinery. The same int-array kernel that backs validate on a Codec.t.

Sourcetype validator

A struct validator without a constructor.

Sourceval validator_of_struct : Wire__.Types.struct_ -> validator

validator_of_struct s compiles s into a validator.

Sourceval validate_struct : validator -> bytes -> int -> unit

Run the validator. Raises Parse_error on failure.

Sourceval struct_size_of : validator -> bytes -> int -> int

Byte size of the struct starting at off.

Sourceval struct_min_size : validator -> int

Minimum byte size accepted.

Sourceval wire_size_info_of_validator : validator -> [ `Fixed of int | `Variable of bytes -> int -> int ]

Wire-size info for the validator.