package wire

  1. Overview
  2. Docs
Binary wire format DSL with EverParse 3D output

Install

dune-project
 Dependency

Authors

Maintainers

Sources

wire-1.2.0.tbz
sha256=510ae8a38087e02113c83766fc11d223e5de446a536cd8785d672393d3d3b575
sha512=6cf3feabb1bb0a7bd25219ebbd82a733960f484a3e5ef05b8901dbf3634e9040a92921b0ceb71ec999b52ce148276c57cb1797ea95ca903558df994861bfd357

doc/src/wire/param.ml.html

Source file param.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
type input = Types.param_input
type output = Types.param_output
type ('a, 'k) t = ('a, 'k) Types.param_handle

let pp ppf (p : (_, _) t) = Fmt.string ppf p.Types.name

(* Reading a bound value as the [int] an environment slot holds. The other
   direction is [Types.of_int], shared with every other integer view of a type;
   this one stays separate because a parameter that does not fit the native int
   is a caller error [bind] reports as [Invalid_argument], not the malformed
   input the decode-path conversion raises a parse error on. *)
exception Unfittable_native_int

let id_counter = Atomic.make 0

let optint_to_int to_int value =
  match to_int value with
  | value -> value
  | exception (Failure _ | Invalid_argument _) -> raise Unfittable_native_int

let rec to_int : type a. a Types.typ -> a -> int =
 fun typ v ->
  match typ with
  | Uint8 -> UInt8.to_int v
  | Uint16 _ -> UInt16.to_int v
  | Uint_var _ -> optint_to_int UInt63.to_int v
  | Uint32 _ -> optint_to_int UInt32.to_int v
  | Uint64 _ -> UInt64.to_int_opt v |> Option.value ~default:max_int
  | Int8 -> SInt8.to_int v
  | Int16 _ -> SInt16.to_int v
  | Int32 _ -> SInt32.to_int v
  | Int64 _ -> Int64.to_int v
  | Float32 _ -> invalid_arg "Param: floats are not integer-representable"
  | Float64 _ -> invalid_arg "Param: floats are not integer-representable"
  | Bits _ -> v
  | Enum { base; _ } -> to_int base v
  | Where { inner; _ } -> to_int inner v
  | Single_elem { elem; _ } -> to_int elem v
  | Map { inner; encode; _ } -> to_int inner (encode v)
  | Apply { typ; _ } -> to_int typ v
  | Unit | All_bytes | All_zeros | Zeroterm | Zeroterm_at_most _ | Array _
  | Byte_array _ | Byte_array_where _ | Byte_slice _ | Casetype _ | Struct _
  | Type_ref _ | Qualified_ref _ | Codec _ | Optional _ | Optional_or _
  | Repeat _ ->
      invalid_arg "Param: unsupported parameter type"

let of_int = Types.of_int

let check_typ name typ =
  if not (Types.is_int_representable typ) then
    Fmt.invalid_arg "Param.%s: only integer-representable types are supported"
      name

let input name typ =
  check_typ "input" typ;
  let id = Atomic.fetch_and_add id_counter 1 in
  { Types.id; name; typ; packed_typ = Types.Pack_typ typ; mutable_ = false }

let output name typ =
  check_typ "output" typ;
  let id = Atomic.fetch_and_add id_counter 1 in
  { Types.id; name; typ; packed_typ = Types.Pack_typ typ; mutable_ = true }

let decl (t : ('a, 'k) t) : Types.param =
  { param_name = t.name; param_typ = t.packed_typ; mutable_ = t.mutable_ }

let name (t : (_, _) t) = t.Types.name
let expr t : int Types.expr = Types.Param_ref t

(* -- Param.env -- *)

type env = Types.param_env

(* Slot of a handle within an env, by name. [-1] when the env's codec does not
   reference the param (e.g. binding a param the codec does not use). *)
let env_idx (env : env) name =
  let rec find i =
    if i >= Array.length env.Types.names then -1
    else if env.names.(i) = name then i
    else find (i + 1)
  in
  find 0

let bind (p : ('a, input) t) (v : 'a) (env : env) : env =
  let iv =
    match to_int p.Types.typ v with
    | value -> value
    | exception Unfittable_native_int ->
        Fmt.invalid_arg
          "Param.bind %S: value does not fit this platform's native int"
          p.Types.name
  in
  let slots = Array.copy env.slots in
  let bound = Array.copy env.bound in
  let i = env_idx env p.Types.name in
  if i >= 0 then begin
    slots.(i) <- iv;
    bound.(i) <- true
  end;
  { env with Types.slots; bound }

let bind_by_name name (iv : int) (env : env) : env =
  let i = env_idx env name in
  if i < 0 then env
  else begin
    let slots = Array.copy env.Types.slots in
    let bound = Array.copy env.bound in
    slots.(i) <- iv;
    bound.(i) <- true;
    { env with Types.slots; bound }
  end

let get (env : env) (p : ('a, 'k) t) : 'a =
  let i = env_idx env p.Types.name in
  if i < 0 then
    Fmt.invalid_arg
      "Param.get: parameter %S does not belong to this environment" p.Types.name
  else of_int p.typ env.slots.(i)

type packed = Pack : ('a, 'k) t -> packed