Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove runtime dependency on Yojson #19

Merged
merged 5 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion ocaml-protoc-plugin.opam
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ depends: [
"odoc" {with-doc}
"conf-pkg-config" {build}
"dune-configurator" {with-test}
"yojson"
"yojson" {with-test}
"base64"
"ptime"
]
Expand All @@ -43,4 +43,8 @@ The types generated aims to create ocaml idiomatic types;
- all integer types are mapped to int by default (exact mapping is also possible)
- all floating point types are mapped to float.
- packages are mapped to nested modules

The package aims to be a 100% compliant protobuf implementation.
It also includes serializing to and from json (Yojson format) based on
protobuf json specification
"""
18 changes: 9 additions & 9 deletions src/ocaml_protoc_plugin/deserialize_json.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ open! StdLabels
open Spec

module FieldMap = Map.Make(String)
type fields = Yojson.Basic.t FieldMap.t
type fields = Json.t FieldMap.t

let value_error type_name json =
Result.raise (`Wrong_field_type (type_name, Yojson.Basic.to_string json))
Result.raise (`Wrong_field_type (type_name, Json.to_string json))

let to_int64 = function
| `String s -> Int64.of_string s
Expand All @@ -21,7 +21,7 @@ let to_string = function
| `String s -> s
| json -> value_error "string" json
let to_bytes json = to_string json |> Base64.decode_exn |> Bytes.of_string
let to_enum: type a. (module Spec.Enum with type t = a) -> Yojson.Basic.t -> a = fun (module Enum) -> function
let to_enum: type a. (module Spec.Enum with type t = a) -> Json.t -> a = fun (module Enum) -> function
| `String enum -> Enum.from_string_exn enum
| `Int enum -> Enum.from_int_exn enum
| json -> value_error "enum" json
Expand All @@ -42,7 +42,7 @@ let to_list = function
| `List l -> l
| json -> value_error "list" json

let read_map: type a b. read_key:(string -> a) -> read_value:(Yojson.Basic.t -> b) -> Yojson.Basic.t -> (a * b) list =
let read_map: type a b. read_key:(string -> a) -> read_value:(Json.t -> b) -> Json.t -> (a * b) list =
fun ~read_key ~read_value -> function
| `Assoc entries ->
List.map ~f:( fun (key, value) ->
Expand All @@ -61,7 +61,7 @@ let duration_of_json json =
(* must end with a 's' *)

try
let s = Yojson.Basic.Util.to_string json in
let s = to_string json in
assert (String.get s (String.length s - 1) = 's');
let sign, s = match String.get s 0 = '-' with
| true -> (-1), String.sub s ~pos:1 ~len:(String.length s - 2)
Expand Down Expand Up @@ -189,7 +189,7 @@ let value_to_json json =
`Assoc [value]


let map_enum_json: (module Enum) -> Yojson.Basic.t -> Yojson.Basic.t = fun (module Enum) ->
let map_enum_json: (module Enum) -> Json.t -> Json.t = fun (module Enum) ->
let name =
Enum.name ()
|> String.split_on_char ~sep:'.'
Expand All @@ -205,7 +205,7 @@ let map_enum_json: (module Enum) -> Yojson.Basic.t -> Yojson.Basic.t = fun (modu
map
| _ -> fun json -> json

let map_message_json: name:string -> Yojson.Basic.t -> Yojson.Basic.t = fun ~name ->
let map_message_json: name:string -> Json.t -> Json.t = fun ~name ->
match name with
| ".google.protobuf.Empty" (* Already mapped as it should I think *) ->
fun json -> json
Expand Down Expand Up @@ -272,7 +272,7 @@ let map_message_json: name:string -> Yojson.Basic.t -> Yojson.Basic.t = fun ~nam
convert
| _ -> fun json -> json

let read_value: type a b. (a, b) spec -> Yojson.Basic.t -> a = function
let read_value: type a b. (a, b) spec -> Json.t -> a = function
| Double -> to_float
| Float -> to_float
| Int32 -> to_int32
Expand Down Expand Up @@ -402,7 +402,7 @@ let rec deserialize: type constr a. (constr, a) compound_list -> constr -> field
cont (constr v) fields


let deserialize: type constr a. message_name:string -> (constr, a) compound_list -> constr -> Yojson.Basic.t -> a =
let deserialize: type constr a. message_name:string -> (constr, a) compound_list -> constr -> Json.t -> a =
fun ~message_name spec constr ->
let deserialize = deserialize spec constr in
let map_message = map_message_json ~name:message_name in
Expand Down
19 changes: 9 additions & 10 deletions src/ocaml_protoc_plugin/deserialize_json.mli
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
val deserialize: message_name:string -> ('constr, 'a) Spec.compound_list -> 'constr -> Yojson.Basic.t -> 'a
val deserialize: message_name:string -> ('constr, 'a) Spec.compound_list -> 'constr -> Json.t -> 'a

(**)
val to_int64: Yojson.Basic.t -> int64
val to_int32: Yojson.Basic.t -> int32
val to_int: Yojson.Basic.t -> int
val to_string: Yojson.Basic.t -> string
val to_bytes: Yojson.Basic.t -> bytes
val to_float: Yojson.Basic.t -> float
val to_bool: Yojson.Basic.t -> bool
val to_list: Yojson.Basic.t -> Yojson.Basic.t list

val to_int64: Json.t -> int64
val to_int32: Json.t -> int32
val to_int: Json.t -> int
val to_string: Json.t -> string
val to_bytes: Json.t -> bytes
val to_float: Json.t -> float
val to_bool: Json.t -> bool
val to_list: Json.t -> Json.t list
(**)
2 changes: 1 addition & 1 deletion src/ocaml_protoc_plugin/dune
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
(public_name ocaml-protoc-plugin)
(synopsis "Serialization and deserialization of protobuf types")
(inline_tests)
(libraries yojson base64 ptime)
(libraries base64 ptime)
(preprocess (pps ppx_expect))
(instrumentation (backend bisect_ppx))
)
25 changes: 25 additions & 0 deletions src/ocaml_protoc_plugin/json.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
open StdLabels

(** Json type. This is identical to Yojson.Basic.t *)
type t = [
| `Null
| `Bool of bool
| `Int of int
| `Float of float
| `String of string
| `Assoc of (string * t) list
| `List of t list
]

let rec to_string = function
| `Null -> "null"
| `Bool b -> string_of_bool b
| `Int i -> string_of_int i
| `Float f -> string_of_float f
| `String s -> Printf.sprintf "\"%s\"" s
| `Assoc l -> List.map ~f:(fun (key, value) -> Printf.sprintf "\"%s\": %s" key (to_string value)) l
|> String.concat ~sep:", "
|> Printf.sprintf "{ %s }"
| `List l -> List.map ~f:to_string l
|> String.concat ~sep:", "
|> Printf.sprintf "[ %s ]"
2 changes: 2 additions & 0 deletions src/ocaml_protoc_plugin/ocaml_protoc_plugin.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
(**/**)

module Serialize = Serialize
module Deserialize = Deserialize
module Serialize_json = Serialize_json
Expand All @@ -8,6 +9,7 @@ module Field = Field
module Merge = Merge
(**/**)

module Json = Json
module Reader = Reader
module Writer = Writer
module Service = Service
Expand Down
22 changes: 11 additions & 11 deletions src/ocaml_protoc_plugin/serialize_json.ml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ open Spec

(** Serialize to json as per https://protobuf.dev/programming-guides/proto3/#json-options *)
let value_error type_name json =
Result.raise (`Wrong_field_type (type_name, Yojson.Basic.show json))
Result.raise (`Wrong_field_type (type_name, Json.to_string json))

type field = string * Yojson.Basic.t
type field = string * Json.t

let int32_value v = `Int (Int32.to_int v)
let int32_int_value v = `Int v
Expand All @@ -26,7 +26,7 @@ let key_to_string = function
| `String s -> s
| `Bool b -> string_of_bool b
| `Int v -> string_of_int v
| json -> Result.raise (`Wrong_field_type ("map key", (Yojson.Basic.to_string json)))
| json -> Result.raise (`Wrong_field_type ("map key", (Json.to_string json)))

let key ~json_names (_, name, json_name) =
match json_names with
Expand Down Expand Up @@ -82,7 +82,7 @@ let duration_to_json json =
let%expect_test "duration_to_json" =
let test seconds nanos =
let json = `Assoc ["seconds", `Int seconds; "nanos", `Int nanos] in
Printf.printf "%d.%d -> %s\n" seconds nanos (Yojson.Basic.to_string (duration_to_json json))
Printf.printf "%d.%d -> %s\n" seconds nanos (Json.to_string (duration_to_json json))
in
test 100 0;
test (1000) (123456);
Expand Down Expand Up @@ -117,7 +117,7 @@ let timestamp_to_json json =
let%expect_test "timestamp_to_json" =
let test seconds nanos =
let json = `Assoc ["seconds", `Int seconds; "nanos", `Int nanos] in
Printf.printf "%d.%d -> %s\n" seconds nanos (Yojson.Basic.to_string (timestamp_to_json json))
Printf.printf "%d.%d -> %s\n" seconds nanos (Json.to_string (timestamp_to_json json))
in
test 1709931283 0;
test 1709931283 (1_000_000_002/2);
Expand All @@ -132,7 +132,7 @@ let%expect_test "timestamp_to_json" =

let wrapper_to_json json = get_key ~f:(fun id -> id) ~default:`Null "value" json

let map_enum_json: (module Enum) -> Yojson.Basic.t -> Yojson.Basic.t = fun (module Enum) ->
let map_enum_json: (module Enum) -> Json.t -> Json.t = fun (module Enum) ->
let name =
Enum.name ()
|> String.split_on_char ~sep:'.'
Expand All @@ -150,7 +150,7 @@ let map_enum_json: (module Enum) -> Yojson.Basic.t -> Yojson.Basic.t = fun (modu


(* Convert already emitted json based on json mappings *)
let map_message_json: name:string -> (Yojson.Basic.t -> Yojson.Basic.t) option = fun ~name ->
let map_message_json: name:string -> (Json.t -> Json.t) option = fun ~name ->
match name with
| ".google.protobuf.Empty" ->
Some (fun json -> json)
Expand Down Expand Up @@ -204,7 +204,7 @@ let map_message_json: name:string -> (Yojson.Basic.t -> Yojson.Basic.t) option =
Some map
| _ -> None

let rec json_of_spec: type a b. Json_options.t -> (a, b) spec -> a -> Yojson.Basic.t =
let rec json_of_spec: type a b. Json_options.t -> (a, b) spec -> a -> Json.t =
fun options -> function
| Double -> float_value
| Float -> float_value
Expand Down Expand Up @@ -315,13 +315,13 @@ and write: type a b. Json_options.t -> (a, b) compound -> a -> field list = fun
f v
end

let serialize: type a. message_name:string -> Json_options.t -> (a, Yojson.Basic.t) compound_list -> field list -> a = fun ~message_name options ->
let serialize: type a. message_name:string -> Json_options.t -> (a, Json.t) compound_list -> field list -> a = fun ~message_name options ->
let omit_default_values, map_result = match map_message_json ~name:message_name with
| Some mapping -> false, fun json -> `Assoc (List.rev json) |> mapping
| None -> options.omit_default_values, fun json -> `Assoc (List.rev json)
in
let options = { options with omit_default_values } in
let rec inner: type a. (a, Yojson.Basic.t) compound_list -> field list -> a =
let rec inner: type a. (a, Json.t) compound_list -> field list -> a =
function
| Nil -> map_result
| Nil_ext _extension_ranges -> fun json _extensions -> map_result json
Expand All @@ -334,7 +334,7 @@ let serialize: type a. message_name:string -> Json_options.t -> (a, Yojson.Basic
in
inner

let serialize: type a. message_name:string -> (a, Yojson.Basic.t) compound_list -> Json_options.t -> a =
let serialize: type a. message_name:string -> (a, Json.t) compound_list -> Json_options.t -> a =
fun ~message_name spec ->
let arr = Array.init (Json_options.max_int + 1) ~f:(fun i -> Lazy.from_fun (fun () -> serialize ~message_name (Json_options.of_int i) spec [])) in
fun options ->
Expand Down
2 changes: 1 addition & 1 deletion src/ocaml_protoc_plugin/serialize_json.mli
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@

val serialize: message_name:string -> ('a, Yojson.Basic.t) Spec.compound_list -> Json_options.t -> 'a
val serialize: message_name:string -> ('a, Json.t) Spec.compound_list -> Json_options.t -> 'a
6 changes: 3 additions & 3 deletions src/ocaml_protoc_plugin/spec.ml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ module type Message = sig
val to_proto: t -> Writer.t
val to_proto': Writer.t -> t -> unit
val merge: t -> t -> t
val to_json: Json_options.t -> t -> Yojson.Basic.t
val from_json_exn: Yojson.Basic.t -> t
val from_json: Yojson.Basic.t -> t Result.t
val to_json: Json_options.t -> t -> Json.t
val from_json_exn: Json.t -> t
val from_json: Json.t -> t Result.t
end

module Make(T : T) = struct
Expand Down
6 changes: 3 additions & 3 deletions src/plugin/emit.ml
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,9 @@ let rec emit_message ~params ~syntax ~scope
Code.emit signature `None "val to_proto: t -> Runtime'.Writer.t";
Code.emit signature `None "val from_proto: Runtime'.Reader.t -> (t, [> Runtime'.Result.error]) result";
Code.emit signature `None "val from_proto_exn: Runtime'.Reader.t -> t";
Code.emit signature `None "val to_json: Runtime'.Json_options.t -> t -> Yojson.Basic.t";
Code.emit signature `None "val from_json_exn: Yojson.Basic.t -> t";
Code.emit signature `None "val from_json: Yojson.Basic.t -> (t, [> Runtime'.Result.error]) result";
Code.emit signature `None "val to_json: Runtime'.Json_options.t -> t -> Runtime'.Json.t";
Code.emit signature `None "val from_json_exn: Runtime'.Json.t -> t";
Code.emit signature `None "val from_json: Runtime'.Json.t -> (t, [> Runtime'.Result.error]) result";

Code.emit implementation `None "let name () = \"%s\"" (Scope.get_proto_path scope);
Code.emit implementation `None "type t = %s%s" type' params.annot;
Expand Down
Loading
Loading