Unify output of `atdgen -bs` and `atdgen -j`
bbenne10 opened this issue · comments
I'm currently writing a fullstack Reason application: Native code as the server (using Opium) and JS via Melange on the frontend.
Right now, the bucklescript output and json output do not have the same api. Notably, the _of_string
and _to_string
functions are missing from the bucklescript output, which makes transparent usage between the frontend and backend code impossible (or at least...much more verbose in the specific and impossible in the generic).
However, I think this could be done pretty trivially in the atdgen emitters. For instance, assuming the following saved as thing.atd
:
type thing= {
~id <ocaml default="0">: int;
foo: string;
bar: int;
}
atdgen -j
spits out these types (actual output modified for brevity):
type thing = Thing_t.thing = { id: int; foo: string; bar: int }
val write_thing : Buffer.t -> thing -> unit
val string_of_thing : ?len:int -> thing -> string
val read_thing : Yojson.Safe.lexer_state -> Lexing.lexbuf -> thing
val thing_of_string : string -> thing
while atdgen -bs
gives us the following:
type thing = Thing_t.thing = { id: int; foo: string; bar: int }
val read_thing : thing Atdgen_codec_runtime.Decode.t
val write_thing : thing Atdgen_codec_runtime.Encode.t
The string_of_thing
and thing_of_string
functions are extremely helpful, in that I can map over then in module entrypoint Thing.re
to unify my interaction and abstract away usage of either YoJson.Safe.t
or Atdgen_runtime.{Decode,Encode}.t
entirely.
The generated function would be pretty trivial (note that it accepts len
for parity with the atdgen -j
output, but discards it):
let thing_of_string (~len=1024, input) =
let json = Js.Json.parseExn input in
let thing: Thing_t.t = Atdgen_codec_runtime.Decode.decode Thing_bs.read_thing json in
thing
There are certainly things I'm overlooking here (Maybe the source of the underlying Js.Json
type is a problem? since it will come from either ReScript or Melange? Maybe the tooling is a problem because we can't guarantee that Js.Json
is available all the time in the runtime (since the rescript tooling is no longer ocaml native?)
what will be the unified signatures of _of_string
and _to_string
for type 'a foo = { bar : 'a }
?
I'm genuinely unsure. I hadn't considered that the type abstraction would mean you'd need a lexer to define what 'a
would be... If it isn't obvious, my use case is not particularly generic (though that doesn't mean it shouldn't be taken into account).
Can we mirror the _j
example and accept two lexers? Or just...not emit the functions in the ambiguous cases (maybe after emitting a warning to stdout)? I see the difficulty here, but I do think that there's benefit in the simple case to be able to hide the complexity a bit.