diff --git a/CHANGES.md b/CHANGES.md index f1bd828..f6e6bdc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,7 @@ +### Unreleased + +- Add `Pidign.Pris` for bi-directional definition (by [mspwn](https://github.com/mspwn) and [xvw](https://github.com/xvw)) + ### v1.0.0 #### Pidgin diff --git a/lib/pidgin.ml b/lib/pidgin.ml index 27b5f0b..bd21cd0 100644 --- a/lib/pidgin.ml +++ b/lib/pidgin.ml @@ -6,6 +6,7 @@ module Repr = Repr module Kind = Kind module Check = Check +module Prism = Prism module Driver = Driver module Sexp = Sexp module Csexp = Csexp diff --git a/lib/pidgin.mli b/lib/pidgin.mli index 3912fa8..e51c75d 100644 --- a/lib/pidgin.mli +++ b/lib/pidgin.mli @@ -11,9 +11,10 @@ to that of JSON) and to provide: - a DSL for describing arbitrary data structures in this language - (see {!module:Repr}) + (see {!module:Repr}). - Validation functions that operate on data described using this - DSL (see {!module:Check}) + DSL (see {!module:Check}). + - [Repr] and [Check] can be combined using {!module:Prism}. - A bidirectional conversion approach (see {!module:Driver}), imposing a cost due to the indirect nature of the generic format (though it is viable in many scenarios). @@ -48,4 +49,5 @@ module Csexp = Csexp (** {1 Misc} *) +module Prism = Prism module Misc = Misc diff --git a/lib/prism.ml b/lib/prism.ml new file mode 100644 index 0000000..300e6ea --- /dev/null +++ b/lib/prism.ml @@ -0,0 +1,25 @@ +(* Copyright (c) 2026, Cargocut and the Pidgin developers. + All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause *) + +type 'a t = + { conv : 'a Repr.conv + ; check : 'a Check.t + } + +let make ~conv ~check = { conv; check } +let conv { conv; _ } = conv +let check { check; _ } = check + +let invmap f g { conv; check } = + { check = (fun x -> x |> check |> Result.map f) + ; conv = (fun x -> x |> g |> conv) + } +;; + +let refine f g { conv; check } = + { check = (fun x -> Result.bind (check x) f) + ; conv = (fun x -> x |> g |> conv) + } +;; diff --git a/lib/prism.mli b/lib/prism.mli new file mode 100644 index 0000000..926cc51 --- /dev/null +++ b/lib/prism.mli @@ -0,0 +1,38 @@ +(* Copyright (c) 2026, Cargocut and the Pidgin developers. + All rights reserved. + + SPDX-License-Identifier: BSD-3-Clause *) + +(** A [Prism] is used to describe a codec that enables serialization + and deserialization (it consists of a {!type:Repr.conv} and a + {!type:Check.t} pair). *) + +(** {1 Types} *) + +(** The type that describes the pair of converter and validator. *) +type 'a t + +(** {1 Building prisms} *) + +(** [make ~conv ~check] constructs a prism for type ['a]. *) +val make : conv:'a Repr.conv -> check:'a Check.t -> 'a t + +(** {1 Running prisms} *) + +(** [conv prism] extract the prism conversion function. *) +val conv : 'a t -> 'a Repr.conv + +(** [check prism] extract the prism validation function. *) +val check : 'a t -> 'a Check.t + +(** {1 Helpers} + + A few additional tools for working with prisms. *) + +(** [invmap f g prism] map both [f] and [g] on, respectively, [check] + and [conv]. *) +val invmap : ('a -> 'b) -> ('b -> 'a) -> 'a t -> 'b t + +(** [refine f g prism] bind [f] and map [g] on, respectively, [check] + and [conv]. *) +val refine : ('a, 'b) Check.fn -> ('b -> 'a) -> 'a t -> 'b t