ron-rs / ron

Rusty Object Notation
https://docs.rs/ron
Apache License 2.0
3.39k stars 125 forks source link

RON support in other languages #306

Open chriskilding opened 3 years ago

chriskilding commented 3 years ago

RON solves a number of pain points with JSON (e.g. it actually supports enums, actually supports types), and unlike most better-than-JSON attempts it's also managed to get some traction - at least within the Rust community.

As such RON is interesting to those of us who are working outside of Rust, who are working on projects where we find that JSON falls a little short of our needs.

Are there any plans for RON support in other languages? If so, what might that look like?

kvark commented 3 years ago

Good question! I develop everything in Rust these days, so personally I'll unlikely be able to contribute to bindings to other languages. Besides, it's unclear to me how these langs will deal with the strong enum semantics of RON. If there is such an effort, I'd be happy to endorse it :) Maybe other folks from RON users/community can chime in and help.

chriskilding commented 3 years ago

As a 'starter for ten' I'm toying with a prototype RON backend for Jackson:

https://github.com/chriskilding/jackson-dataformat-ron

The idea would be to allow users in the JVM world to read or write RON using the Jackson API they already know (ObjectMapper etc).

I don't yet know if Jackson can support everything RON would need as its APIs currently stand, but it's worth an investigation.

chriskilding commented 3 years ago

Some updates from building that prototype:

In the low level parser/generator APIs, all of RON can be supported.

In the high level ObjectMapper API, all RON concepts with Java equivalents can be supported. That means the only major RON concepts you can't use are:

There's still some questions outstanding about things like field ordering, which I didn't address in the prototype, but if field ordering is specified in a language-independent way within the RON specification I think it can be dealt with.

To speed up development of the parser side I wrote an ANTLR grammar for RON which can be seen here: https://github.com/chriskilding/jackson-dataformat-ron/blob/main/src/main/antlr4/com/fasterxml/jackson/dataformat/ron/antlr4/RON.g4. ANTLR isn't necessary to build a parser and other options are out there, but the main takeaway is that if the RON specification had a full grammar which could be used directly by parser generators, it would be helpful to ensure correctness.

Overall, it seems that RON would provide value to Java developers in cases where their data model exceeds the limits of JSON's grammar, such as encoding a list of heterogenous types. And if it can provide value in Java it can probably provide value in other languages too.

chriskilding commented 3 years ago

There are possibilities to allow support for the remaining RON concepts in the ObjectMapper, such as providing @RONFormat annotations which would let the user tell Jackson how to de/serialize enums with child fields or tuples.

Example...

@RONFormat(shape = Shape.Enum)
class Dog {
    int barks;
}

versus

// struct is the default shape for POJOs, no annotation is technically necessary
@RONFormat(shape = Shape.Struct)
class Dog {
  int barks;
}

They're slightly more fragile, in that they would require some runtime checks to ensure that a RON enum Dog(1) can only be deserialised to the class Dog if it has a Shape.Enum annotation. But they're possible if required.

chriskilding commented 3 years ago

I didn't address Optionals in the prototype, although they can be used in the low-level parser and generator 'for free' since Some(...) is just another case of an enum.

In JSON there is an expectation that if an optional field "b" is absent you omit it in the JSON, if it's present it is simply included as-is within the JSON:

{
  "a": "foo"
}
{
  "a": "foo",
  "b": "bar"
}

In RON we'd expect the equivalent to be:

(a: "foo")
(
  a: "foo",
  b: "bar",
)

But currently the reference RON parser does not allow the second form. If present an optional value must be wrapped in Some:

(
  a: "foo",
  b: Some("bar"),
)

This seems... awkward.

FeldrinH commented 3 years ago

There is this extension: https://github.com/ron-rs/ron/blob/master/docs/extensions.md#implicit_some.

chriskilding commented 3 years ago

Awesome :) thanks for sharing that. It seems like 'explicit Some' is not a hard constraint of the RON format, I'll go add support for 'implicit Some' to the Jackson RON backend.

sdfgeoff commented 2 years ago

A prototype python exporter is available here: https://github.com/sdfgeoff/blender_bevy_toolkit/blob/master/blender_bevy_toolkit/rust_types/ron.py

It is intentionally very specific. You have to tell it "this is a ron struct, it contains a ron float" rather than giving it a python dict and letting it attempt to figure it out.

JakkuSakura commented 2 years ago

I'd prefer a ron2json cli tool. So that all other languages can use ron easily(with performance cost but not bottleneck)

chriskilding commented 2 years ago

A CLI converter tool could be a good idea, however it's an 'and' rather than an 'or' proposition. There is still very much a need for languages to have their own RON de/serializer libraries (so that they can work with RON at reasonable speed, or specify their own field mappings/transformations, and also because shelling out to an external process comes with security/portability issues).

juliancoffee commented 10 months ago

Speaking of ron2json cli, not every Ron is a valid Json (which was a surprise to me). I tried using serde_json for this, but as it says in its to_string docs, it will fail if it's a map with non-string keys, which is ok for Ron. Maybe there is some other widely supported format which allows that?

Ok, I tried serde_yaml, which allows for non-string keys, but it seems to completely erase enums. UPD: Oh wait, it's ron's Value doesn't have enums, hmm.

https://github.com/ron-rs/ron/issues/122