Source

meta_conv /

Filename Size Date modified Message
example/json
json
lib
pa
56 B
243 B
20.4 KB
6.2 KB

Meta_conv

Using Meta_conv

with conv(...) extension

For example:

type t = {
     foo: int;
     bar: float;
  } with conv(json, Json.t, Json_conv)

conv takes comma separated arguments to specify the encoder and decoder.

conv(<name>, <target_type>, <converter_module>)

name

The name of the converter. Meta_conv creates the following funcitons:

<name>_of_<host_type>

The encoder from the OCaml host type to the target type.

<host_type>_of_<name>

<host_type>_of_<name>_exn

The decoders from the target type to the OCaml host type.

<host_type>_of_<name> is monadic style, whose return type is [`Ok of host_type | `Error of ...] .

<host_type>_of_<name>_exn is non monadic style, whose return type is simple host_type and raises an exception at decoding error.

target_type

The target type.

converter_module

The module of conversion functions between the host and target types. The converter module must provide basic encoders and decoders in the signature of Meta_conv.Conv.S. It should also provide encoders and decoders for the basic OCaml primitive types like <name>_of_int. See Json_conv module for an example.

conv(<name>, <target_type>)

The converter module name is deduced from the <target_type>.

If <target_type> is A.B.C.name then the convert module is A.B.C_conv.

If <target_type> has no module part, the convert module is Conv.

conv(<name>)

The target type name is deduced from the <name>. If <name> is json then the target type name is Json.t. The converter module is deduced from the the target type name.

For example, conv(json) is equivalent with conv(json, Json.t, Json_conv).

Limitations

Polymorphic variants, classes and GADTs are not supported.

Modules and values to be accessible

For actual example, see an example in meta_conv/json directory.

Meta_conv

Meta_conv packed module library must be linked with programs which use meta_conv.

Conversion module

The conversion module for the basic encoders and decoders must be accessible in the name given at with conv(...) in the context. For example, if you write with conv(json, Json.t, Json_conv), Json_conv of the following signature must exist:

sig
  type t = Json.t

  module Encode : sig
    val tuple : t list -> t
    val variant : string -> t list -> t
    val record : (string * t) list -> t
  end

  module Decode : sig
    (* Address.t = Meta_conv.Conv.Address.t *)
    val tuple   : (t * Address.t) -> (t * Address.t) list
    val variant : (t * Address.t) -> string * (t * Address.t) list
    val record  : (t * Address.t) -> (string * (t * Address.t)) list
  end
end

An exception for decoding error:

exception Error of <target_type> error

Encoder and decoder functions for primitive types

The encoder and decoder functions for primitive types (int, int32, int64, nativeint, char, string, float, list, array, bool, lazy_t, option) must be accessible in the context. For example, for conv(json), those have names like int_of_json and json_of_int.

Meta_conv annotations

Meta_conv annotations (annots) are to control data conversion between OCaml data types and encoded data. Annots can be written at several places in type definitions. Their form is:

(: <annot>, <annot>, .. :)

Remember the syntax by "Colon for Conv".

Annots at Data type name

Ignore_unknown_fields

Ignore excess record fields at decoding:

type t (: Ignore_unknown_fields :) = {
     foo: int;
     bar: float;
  } with conv(json)

Without Ignore_unknown_fields, t_of_json fails if it takes a json with extra fields other than foo or bar. With Ignore_uknown_fields, the extra fields are just discarded.

Ignore_unknown_fields can be overridden by following field_check = <e>.

field_check = <e>

Use a custom field check <e> at decoding:

type t (: field_check = my_custom_field_checker :) = {
     foo: int;
     bar: float;
  } with conv(json)

The expression <e> must have the same type as Meta_conv.Conv.record_unknown_field_check. <e> is syntactically embeded in the decoder code and executed at each call of decoder function.

field_check = <e> can be overridden by following field_check = <e> or Ignore_unknown_fields.

Annots at Variant tags

"name"

Use name for tag encoding instead of the constructor name itself. Usually it is used to have lowercased tag names:

type t = Hg (: "hg" :) | Git (: "git" :) with conv(json)

type t = Name (: "name" ") of string with conv(json)

Annots at Record fields

"name"

Use name for tag encoding instead of the field name itself. Usually it is used to have uppercased tag names or tag names same as OCaml keywords:

type t = { name (: "Name" :) of string } with conv(json)

type t = { type_ (: "type" :) of string } with conv(json)

Rest_in_raw

At decoding, the field with Rest_in_raw takes the target record fields which are not listed in the other OCaml record fields, in undecoded format.

  • The type of the field must be (string * <target_type>) list.
  • To fix the raw type to one target type, you cannot specify more than one conv(...).
  • Rest_in_raw record field can exist at most one for an OCaml record type.
  • You cannot specify with Ignore_unknown_fields type name annotation.
  • Encoding of Rest_in_raw field uses its raw record value ''as is''. The field name of the OCaml record does not appear as a tag in the encoded data. You cannot specify "name" target tag.