package highway

  1. Overview
  2. Docs

Source file hole.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
(* Copyright (c) 2026, Cargocut and the Highway developers.
   All rights reserved.

   SPDX-License-Identifier: BSD-3-Clause *)

type 'a t =
  { to_string : 'a -> string
  ; from_string : string -> 'a option
  }

let invmap f g { to_string; from_string } =
  { to_string = (fun x -> to_string (f x))
  ; from_string = (fun x -> x |> from_string |> Option.map g)
  }
;;

let make ~to_string ~from_string = { to_string; from_string }
let to_string { to_string; _ } x = to_string x
let from_string { from_string; _ } x = from_string x
let string = make ~to_string:Fun.id ~from_string:Option.some
let int = make ~to_string:string_of_int ~from_string:int_of_string_opt
let float = make ~to_string:string_of_float ~from_string:float_of_string_opt

let char =
  make ~to_string:(String.make 1) ~from_string:(fun x ->
    if String.length x = 1 then Some x.[0] else None)
;;

let bool =
  make
    ~to_string:(function
      | true -> "true"
      | false -> "false")
    ~from_string:(fun x ->
      match String.lowercase_ascii x with
      | "true" -> Some true
      | "false" -> Some false
      | _ -> None)
;;

let opt ?(empty = "") { to_string; from_string } () =
  { to_string =
      (function
        | None -> empty
        | Some x -> to_string x)
  ; from_string =
      (fun x ->
        if String.equal x empty
        then Some None
        else Option.map (fun x -> Some x) (from_string x))
  }
;;