BinBin is a small library for encoding and decoding information from a buffer (like a bytes or a bigstring). Unlike a parser combinator, Bin cannot decode a stream.
Bin can be used to project values coming from a pre-allocated buffer such as a "framebuffer" (video, ethernet, etc.) or to inject values into it. Bin can be seen as a library for describing (fairly basic) "C-like" types of values that can be injected/projected into/from a particular memory area:
#define PROPTAG_GET_COMMAND_LINE 0x00050001
#define VALUE_LENGTH_RESPONSE (1 << 31)
struct __attribute__((packed)) cmdline {
uint32_t id;
uint32_t value_len;
uint32_t param_len;
uint8 str[2048];
};
struct __attribute__((packed)) property_tag {
uint32_t id;
uint32_t value_len;
uint32_t param_len;
};
extern char _tags;
char *get_cmdline() {
struct cmdline p;
p.id = PROPTAG_GET_COMMAND_LINE;
p.value_len = len - sizeof(struct property_tag);
p.param_len = 2048 & ~VALUE_LENGTH_RESPONSE;
memcpy(&_tags, &p, sizeof(struct cmdline)); // inject
...
}Bin therefore allows you to describe a representation of a serialized value in bytes and to associate with it a function that allows you to obtain an OCaml value such as a record or a variant.
open Bin
type cmdline = {
id: int32
; value_len: int32
; param_len: int32
; cmdline: string
}
let cmdline =
record (fun id value_len param_len -> { id; value_len; param_len })
|+ field neint32 (Fun.const 0x00050001l)
|+ field neint32 (fun t -> t.value_len)
|+ field neint32 (fun t -> t.param_len)
|+ field cstring (fun t -> t.cmdline)
|> sealr
let encode_into tags ?(off = 0) value =
let off = ref off in
Bin.encode_bstr cmdline value tags off (* inject *)Of course, it's not as fast as what we can do in C, but Bin has the advantage of offering a small DSL that allows us to describe these types and go directly to OCaml values, which is generally more pleasant to manipulate with OCaml than to make C stubs.
val char : char tchar is a representation of the character type.
val uint8 : int tuint8 is a representation of unsigned 8-bit integers.
val int8 : int tint8 is a representation of 8-bit integers.
val beuint16 : int tbeint16 is a representation of big-endian unsigned 16-bit integers.
val leuint16 : int tleint16 is a representation of little-endian unsigned 16-bit integers.
val neuint16 : int tneint16 is a representation of native-endian unsigned 16-bit integers.
val beint16 : int tbeint16 is a representation of big-endian 16-bit integers.
val leint16 : int tleint16 is a representation of little-endian 16-bit integers.
val neint16 : int tneint16 is a representation of native-endian 16-bit integers.
val beint32 : int32 tbeint32 is a representation of big-endian 32-bit integers.
val leint32 : int32 tleint32 is a representation of little-endian 32-bit integers.
val neint32 : int32 tneint32 is a representation of native-endian 32-bit integers.
val beint64 : int64 tbeint64 is a representation of big-endian 64-bit integers.
val leint64 : int64 tleint64 is a representation of little-endian 64-bit integers.
val neint64 : int64 tneint64 is a representation of native-endian 64-bit integers.
val varint : int tval bytes : int -> string tbytes n is a representation of a bytes sequence of n byte(s).
val cstring : string tval until : char -> string tval const : 'a -> 'a tconst v is v without a serialization mechanism.
seq ~len v is a representation of fixed-length arrays of values of type v.
This combinator allows defining a representative of one type in terms of another by supplying coercions between them.
val record : 'b -> ('a, 'b, 'b) open_recordThe type for fields holding values of type 'b and belonging to a record of type 'a.
field n t g is the representation of the field called n of type t with getter g. For instance:
type t = { foo: string }
let foo = field cstring (fun t -> t.foo)val (|+) :
('a, 'b, 'c -> 'd) open_record ->
('a, 'c) field ->
('a, 'b, 'd) open_recordr |+ f is the open record r augmented with the field f.
val sealr : ('a, 'b, 'a) open_record -> 'a tsealr r seals the open record r.
type t = Foo | Bar of string
let t =
variant (fun foo bar -> function Foo -> foo | Bar s -> bar s)
|~ case0 Foo
|~ case1 cstring (fun x -> Bar x)
|> sealvval variant : 'b -> ('a, 'b, 'b) open_variantcase0 v is a representation of a variant constructor v with no arguments. For instance:
type t = Foo
let foo = case0 Foocase1 n t c is a representation of a variant constructor c with an argument of type t. For instances:
type t = Foo of string
let foo = case1 cstring (fun s -> Foo s)val (|~) :
('a, 'b, 'c -> 'd) open_variant ->
('a, 'c) case ->
('a, 'b, 'd) open_variantv |~ c is the open variant v augmented with the case c.
val sealv : ('a, 'b, 'a -> 'a case_p) open_variant -> 'a tsealv v seals the open variant v.
decode_bstr repr is the binary decoder for values of type repr.
val to_string : 'a t -> 'a -> stringmodule Size : sig ... endval size_of_value : 'a t -> 'a -> int optionsize_of_value encoding value attempts to calculate the number of bytes needed to encode the given value according to the given encoding.
size_of_encoding ?off encoding bstr attempts to calculate the number of bytes required to decode a value according to the given encoding and according to what can be decoded in the given byte sequence bstr (at the given offset off, defaults to 0).