Code Monkey home page Code Monkey logo

ppx_version's Introduction

ppx_version

ppx_version contains OCaml extension points (ppxs) meant to assure the stability of types and their Bin_prot serializations. With such stability, data can be persisted and restored, or communicated over networks reliably, even as software evolves.

To define a stable type:

[%%versioned
  module Stable = struct
    module V1 = struct
	  type t = int * string

      let to_latest (n,s) = (n,s)
    end
  end]

The use of %%versioned generates a Bin_prot typeclass instance in the same way that annotating the type with [@@deriving bin_io] would do. A module alias Latest is also generated; it alias the highest-numbered versioned module (in this example, V1). Whenever a new versioned module is created, the to_latest functions for earlier modules need to be updated. For a module Vn, the to_latest function has type Vn.t -> Latest.t.

The Stable module contains the generated function

val bin_read_to_latest_opt : Bin_prot.Common.buf -> pos_ref:(int ref) -> Stable.Latest.t option

Given a buffer containing a serialization of a type from any of the versioned modules, this function will return an instance of Stable.Latest.t. The return type is an option, because the serialization may be from an unknown version.

The variant %%versioned_asserted can be used when the types used in the definition are not themselves versioned, as when they're from some external library. In that case, you're required to provide a Tests module, where you should provide tests that verify that serializations of the types for each versioned module don't change. The library provides a function check_serialization for that purpose:

let%test "V1 serialization test" =
  let value : M.Stable.V1.t = ... in
  let known_good_digest : string = ... in
  check_serialization (module M.Stable.V1) value known_good_digest

The variant %%versioned_binable can be used when the functor Binable.Of_binable (or Of_binable1, Of_binable2, Of_binable3), or Binable.Of_stringable are used to provide serialization.

A stable type in a signature:

[%%versioned:
  module Stable : sig
    module V1 : sig
	  type t
    end
  end]

A val declaration for bin_read_to_latest_opt and the Latest module alias are generated for the signature.

Another place you may want stable types is in the definition of Jane Street async_rpc_kernel versioned RPC calls. The idiom is:

module V1 = struct
  module T = struct
    type query = int [@@deriving bin_io, version {rpc}]

    type response = string [@@deriving bin_io, version {rpc}]

    let query_of_caller_model = ...

    let callee_model_of_query = ...

    let response_of_callee_model = ...

    let caller_model_of_response = ...
  end

  include T
  include Register (T)
  end

See Jane Street's Async library for details on how to define and use versioned RPC calls.

For both ordinary versioned modules, and versioned RPC modules, the linter in ppx_version checks that all the types used in these definitions are themselves versioned types, or OCaml builtin types, such as int and string. Therefore, these types are versioned all-the-way-down.

The linter also enforces a number of other rules.

One linter rule is that stable-versioned modules cannot be contained in the result of a functor application. The reason is that the types might depend on the functor arguments, so that distinct functor applications yield different types with different serializations. Functors that take no module arguments are allowed to return stable-versioned modules.

Another rule is that types from stable-versioned modules with a specific version can only be used to define other types in stable-versioned modules. In other settings, use Stable.Latest.t. Similarly, modules passed as arguments to functions cannot be a specific-versioned module; use Stable.Latest instead.

The linter does not examine code in tests that use the let%test, let%test_unit or let%test_module forms used with the Jane Street ppx_inline_tests package. Anything goes in tests.

By default, linter violations are errors. Use the flag -lint-version-syntax-warnings to issue warnings instead.

A serializable type may not need to be versioned, because the serialization is neither persisted nor shared with different software. In that case, annotate the type with [@@deriving bin_io_unversioned].

Printing versioned types

To assure that stable-versioned types are stable, in fact, it's useful detect changes to them. For that purpose, the library offers the ability to print out versioned types. You can use that facility in your build system to detect changes to types.

Run the program print_versioned_types.exe on an OCaml source file. For each versioned type in the file, the program prints to the console module_path:type_definition, all on one line. Example output:

M.Stable.V1:type t = { x: N.Stable.V1.t; y: W.Stable.V2.t }

Printing binable functors

Stable-versioned types can use functors like Binable.Of_binable to provide serialization code. If the arguments to such functors change, serializations may change.

Run the program print_binable_functors.exe on source files to print each use of these functors, so you can detect changes. Example output:

M.Stable.V1:Binable.Of_binable (X.Stable.V1) (Y)

The relevant functors are:

  • Binable.Of_binable
  • Binable.Of_binable1
  • Binable.Of_binable2
  • Binable.Of_binable3
  • Binable.Of_sexpable
  • Binable.Of_stringable
  • Bin_prot.Utils.Make_binable

building

Bazel

See docs/BAZEL.md

Legacy

First remove Bazel leftovers: $ bazel clean.

To build ppx_version.cmxa: $ dune build src/ppx_version.cmxa. Result will be in _build.

Tests: $ cd test && make

ppx_version's People

Contributors

psteckler avatar mobileink avatar mrmr1993 avatar imeckler avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.