Code Monkey home page Code Monkey logo

ron's Introduction

Rusty Object Notation

MSRV Crates.io Docs

CI Coverage Fuzzing

Matrix

RON is a simple readable data serialization format that looks similar to Rust syntax. It's designed to support all of Serde's data model, so structs, enums, tuples, arrays, generic maps, and primitive values.

Example

GameConfig( // optional struct name
    window_size: (800, 600),
    window_title: "PAC-MAN",
    fullscreen: false,

    mouse_sensitivity: 1.4,
    key_bindings: {
        "up": Up,
        "down": Down,
        "left": Left,
        "right": Right,

        // Uncomment to enable WASD controls
        /*
        "W": Up,
        "S": Down,
        "A": Left,
        "D": Right,
        */
    },

    difficulty_options: (
        start_difficulty: Easy,
        adaptive: false,
    ),
)

RON syntax overview

  • Numbers: 42, 3.14, 0xFF, 0b0110
  • Strings: "Hello", "with\\escapes\n", r#"raw string, great for regex\."#
  • Byte Strings: b"Hello", b"with \x65\x73\x63\x61\x70\x65\x73\n", br#"raw, too"#
  • Booleans: true, false
  • Chars: 'e', '\n'
  • Optionals: Some("string"), Some(Some(1.34)), None
  • Tuples: ("abc", 1.23, true), ()
  • Lists: ["abc", "def"]
  • Structs: ( foo: 1.0, bar: ( baz: "I'm nested" ) )
  • Maps: { "arbitrary": "keys", "are": "allowed" }

Note: Serde's data model represents fixed-size Rust arrays as tuple (instead of as list)

RON also supports several extensions, which are documented here.

Specification

RON's formal and complete grammar is available here.

There also is a very basic, work in progress specification available on the wiki page.

Why RON?

Example in JSON

{
   "materials": {
        "metal": {
            "reflectivity": 1.0
        },
        "plastic": {
            "reflectivity": 0.5
        }
   },
   "entities": [
        {
            "name": "hero",
            "material": "metal"
        },
        {
            "name": "monster",
            "material": "plastic"
        }
   ]
}

Same example in RON

Scene( // class name is optional
    materials: { // this is a map
        "metal": (
            reflectivity: 1.0,
        ),
        "plastic": (
            reflectivity: 0.5,
        ),
    },
    entities: [ // this is an array
        (
            name: "hero",
            material: "metal",
        ),
        (
            name: "monster",
            material: "plastic",
        ),
    ],
)

Note the following advantages of RON over JSON:

  • trailing commas allowed
  • single- and multi-line comments
  • field names aren't quoted, so it's less verbose
  • optional struct names improve readability
  • enums are supported (and less verbose than their JSON representation)

Quickstart

Cargo.toml

[dependencies]
ron = "0.8"
serde = { version = "1", features = ["derive"] }

main.rs

use serde::{Deserialize, Serialize};

#[derive(Debug, Deserialize, Serialize)]
struct MyStruct {
    boolean: bool,
    float: f32,
}

fn main() {
    let x: MyStruct = ron::from_str("(boolean: true, float: 1.23)").unwrap();

    println!("RON: {}", ron::to_string(&x).unwrap());

    println!("Pretty RON: {}", ron::ser::to_string_pretty(
        &x, ron::ser::PrettyConfig::default()).unwrap(),
    );
}

Tooling

Editor Plugin
IntelliJ intellij-ron
VS Code a5huynh/vscode-ron
Sublime Text RON
Atom language-ron
Vim ron-rs/ron.vim
EMACS emacs-ron

Limitations

RON is not designed to be a fully self-describing format (unlike JSON) and is thus not guaranteed to work when deserialize_any is used instead of its typed alternatives. In particular, the following Serde attributes only have limited support:

  • #[serde(tag = "tag")], i.e. internally tagged enums 1
  • #[serde(tag = "tag", content = "content")], i.e. adjacently tagged enums 1
  • #[serde(untagged)], i.e. untagged enums 1
  • #[serde(flatten)], i.e. flattening of structs into maps 2

While data structures with any of these attributes should generally roundtrip through RON, some restrictions apply 3 and their textual representation may not always match your expectation:

  • ron only supports string keys inside maps flattened into structs
  • internally (or adjacently) tagged or untagged enum variants or #[serde(flatten)]ed fields must not contain:
    • struct names, e.g. by enabling the #[enable(explicit_struct_names)] extension or the PrettyConfig::struct_names setting
    • newtypes
    • zero-length arrays / tuples / tuple structs / structs / tuple variants / struct variants
      • Options with #[enable(implicit_some)] must not contain any of these or a unit, unit struct, or an untagged unit variant
    • externally tagged tuple variants with just one field (that are not newtype variants)
    • tuples or arrays or tuple structs with just one element are not supported inside newtype variants with #[enable(unwrap_variant_newtypes)] (including Some)
    • a ron::value::RawValue
  • untagged tuple / struct variants with no fields are not supported
  • untagged tuple variants with just one field (that are not newtype variants) are not supported when the #![enable(unwrap_variant_newtypes)] extension is enabled
  • serializing a ron::value::RawValue using a PrettyConfig may add leading and trailing whitespace and comments, which the ron::value::RawValue absorbs upon deserialization

Furthermore, serde imposes the following restrictions for data to roundtrip:

  • structs or struct variants that contain a #[serde(flatten)]ed field:
    • are only serialised as maps and deserialised from maps
    • must not contain duplicate fields / keys, e.g. where an inner-struct field matches an outer-struct or inner-struct field
    • must not contain more than one (within the super-struct of all flattened structs) #[serde(flatten)]ed map field, which collects all unknown fields
    • if they contain a #[serde(flatten)]ed map, they must not contain:
      • a struct that is not flattened itself but contains some flattened fields and is flattened into the outer struct (variant)
      • an untagged struct variant that contains some flattened fields
      • a flattened externally tagged newtype, tuple, or struct variant, flattened internally tagged unit, newtype, or struct variant, or any flattened adjacently tagged variant
      • a flattened tagged struct
  • internally (or adjacently) tagged or untagged enum variants or #[serde(flatten)]ed fields must not contain:
    • i128 or u128 values
  • internally tagged newtype variants and #[serde(flatten)]ed fields must not contain:
    • a unit or a unit struct inside an untagged newtype variant
    • an untagged unit variant
  • internally tagged newtype variants, which are #[serde(flatten)]ed together with other fields, must not contain:
    • a unit or unit struct or an untagged unit variant

Please file a new issue if you come across a use case which is not listed among the above restrictions but still breaks.

While RON guarantees roundtrips like Rust -> RON -> Rust for Rust types using non-deserialize_any-based implementations, RON does not yet make any guarantees about roundtrips through ron::Value. For instance, even when RON -> Rust works, RON -> ron::Value -> Rust, or RON -> ron::Value -> RON -> Rust may not work. We plan on improving ron::Value in an upcoming version of RON, though this work is partially blocked on serde#1183.

License

RON is dual-licensed under Apache-2.0 and MIT.

Any contribution intentionally submitted for inclusion in the work must be provided under the same dual-license terms.

Footnotes

  1. Deserialising an internally, adjacently, or un-tagged enum requires detecting serde's internal serde::__private::de::content::Content content type so that RON can describe the deserialised data structure in serde's internal JSON-like format. This detection only works for the automatically-derived Deserialize impls on enums. See #451 for more details. 2 3

  2. Deserialising a flattened struct from a map requires that the struct's Visitor::expecting implementation formats a string starting with "struct ". This is the case for automatically-derived Deserialize impls on structs. See #455 for more details.

  3. Most of these restrictions are currently blocked on serde#1183, which limits non-self-describing formats from roundtripping format-specific information through internally (or adjacently) tagged or untagged enums or #[serde(flatten)]ed fields.

ron's People

Contributors

a1phyr avatar bors[bot] avatar bpfoley avatar cad97 avatar cmaher avatar cpud36 avatar cswinter avatar davidkorczynski avatar dependabot-preview[bot] avatar divinegod avatar ebkalderon avatar elrnv avatar fengalin avatar jakubvaltar avatar juntyr avatar kvark avatar lachlansneff avatar ludicast avatar michael-wit avatar nnethercote avatar nuc1eon avatar nvzqz avatar plecra avatar pyfisch avatar rhuagh avatar spenserblack avatar torkleyy avatar vessd avatar victorkoenders avatar xaeroxe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ron's Issues

Add single-line comments

My recommendation is to use the # character to begin a single-line comment.

These can be a killer feature in any human-readable data format.

Implement deserialize_any

It looks like RON is self-describing. It should be able to tell what type is in the data without relying on a Deserializer hint.

#[macro_use]
extern crate serde_derive;

extern crate ron;

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Untagged {
    U8(u8),
    Bool(bool),
}

fn main() {
    println!("{}", ron::de::from_str::<u8>("99").unwrap());
    println!("{}", ron::de::from_str::<bool>("true").unwrap());

    // unhelpful panic :(
    ron::de::from_str::<Untagged>("true");
}

new data format

So I've been tossing an idea for a data format around in my head for a while now, and this seems like a good application so I thought I would throw it out.

Basically the data format is roughly this: xml in json-syntax. The idea is to have a json/yaml-like syntax but with attributes. So you could write something like this:

foo @{x: 42, y: 72, z}:
    a: "this is a key: string"

@dec_attr: "This is a decorating bar"
bar: "this is bar"

The basic idea is that attribute maps denoted by @ can be placed either after a key or above a key. After a key they must be in the form @{ ... } and above the key they must be in the form @key = value.

The basic idea is to make it easy to have keys with attributes associated with them -- such as types, generics, compiler flags, etc. This kind of language could be used for writing type systems, as a new programming langauge, or almost anything! If you think about it, programming languages are pretty much just variable names with some attributes (as well as some logic handlers... which would not be included in this spec).

Maybe significant white-space is not desired, or requiring "" around keys is desired. You could still use much the same syntax:

{
  "foo" @{"x": 42, "y": 72, "z": true}: {
    "a": "this is a key: string",
  },
  @"dec_attr": "This is decorating bar",  # <-- note the `,` is necessary
  "bar": "this is bar",
}

Also note that {z} is interpreted {z: true} to make passing flags easier. That could also be removed.

One advantage of this system is a clear distinction between the user's logic and the compiler or type-system's logic. The compiler is pretty much only concerned with the attributes (which the user uses to communicate with the compiler). So everything in an attribute is a compiler/language directive, and everything outside an attribute is a user-defined name/value/type.

Anyway, just something I've been tossing around in my head, thought you might like it for some food for thought!

`to_string` produces text that `from_str` does not accept (with tuple variants)

# Cargo.toml
ron = "0.2.1"

Given the following type:

pub enum FileOrMem {
    File(String),
    Memory,
}

ser::to_string produces the following RON:

            data: Node (
                location: Location (
                    file_or_mem: File(
                        "foo/bar"
                    ),
                    column: 1,
                    line: 1
                ),
                key: "Player",
                value: None,
                comment: None
            )

Which fails deserialization with:

Parser(ExpectedString, Position { col: 39, line: 19 })

The fix, IME, is to change the text to be inline. But this should be fixed in parsing IMO (what I mean is that this syntax is reasonable and should be accepted).


For the sake of completeness this error is not restricted to string literals on a new line.

It also occurs if there is a space between the ( and ".

Parsing error locations

Current errors are not very helpful since they pin no location on where they occur. Would be nice to have something like "expected A, got B", or "expected A at line XXX col YYY".

Ergonomics of optional fields

If I have a struct like

#[derive(Debug, Clone, Deserialize)]
pub struct Settings {
    pub font: Option<PathBuf>, // <- optional field
    pub other_value: u8,
}

I can omit the field in .ron file to get None:

(
    other_value: 0,
)

But I'm forced to write Some() around the actual value which clutters up the config:

(
    font: Some("OpenSans-Regular.ttf"), // :(
    // font: "OpenSans-Regular.ttf", // I want this
    other_value: 0,
)

Seems like an ergonomic problem to me :(

See https://gitter.im/ron-rs/ron?at=59d228bd614889d47565733d

Unit types

There are two kinds of unit types in Rust:

  • ()
  • struct Unit;

Serialization

The serializer uses the Rust representation, so () for () and Unit for Unit.

Deserialization

() is always a valid unit type and FooUnit is allowed for deserializing into named unit types.

Configure the depth limit for item indentation

After a particular depth, don't insert newlines any more, e.g. (from @pyfisch custom format):

┌ Display List
│  ├─ ClipScrollNodes
│  │  └─ ClipScrollNode { id: Some(Clip(0, PipelineId(0, 1))), parent_index: ClipScrollNodeIndex(0), clip: ClippingRegion::Empty, content_rect: TypedRect(0.0×0.0 at (0.0,0.0)), node_type: ScrollFrame(ScriptAndInputEvents) }
│  ├─ Items
│  │  ├─ PushStackingContext(StackingContext at TypedRect(1024px×1077.2333333333333px at (0px,0px)) with overflow TypedRect(1024px×1077.2333333333333px at (0px,0px)): StackingContextId(0)) StackingContext: StackingContextId(0) ClippingAndScrolling { scrolling: ClipScrollNodeIndex(0), clipping: None }
│  │  ├─ SolidColor rgba(0, 0, 0, 0) @ TypedRect(1024px×1077.2333333333333px at (0px,0px)) Rect(TypedRect(1024.0×1077.2333 at (0.0,0.0))) StackingContext: StackingContextId(0) ClippingAndScrolling { scrolling: ClipScrollNodeIndex(0), clipping: None }

Move to Serde

rustc-serialize is now deprecated in favour of Serde, which hit 1.0

deserialize_any treats integers as f64

The current implementation of deserialize_any treats all numeric values as f64.

This causes issues when using crates such as serde-value as it will deserialize to the F64 variant preventing it from subsequently being able to be deserialized to an integer field, e.g.:

#[derive(Deserialize, Serialize)]
struct Config {
    value: u32
}

fn value_deserialize_ron() {
    let serialized = r#"(
        value: 5
    )"#;

    let value = ::ron::de::from_str::<::serde_value::Value>(serialized).unwrap();

    let config = value.deserialize_into::<Config>().expect("failed to deserialize from value");
}

This fails on the last line with the following error:

failed to deserialize from value: InvalidType(Float(5.0), "u32")

Both serde yaml:

fn value_deserialize_yaml() {
    let serialized = r#"
        value: 5
    "#;

    let value = ::serde_yaml::from_str::<::serde_value::Value>(serialized).unwrap();

    let config = value.deserialize_into::<Config>().expect("failed to deserialize from value");
}

And serde json:

fn value_deserialize_json() {
    let serialized = r#"{
        "value": 5
    }"#;

    let value = ::serde_json::from_str::<::serde_value::Value>(serialized).unwrap();

    let config = value.deserialize_into::<Config>().expect("failed to deserialize from value");
}

Are able to handle this case correctly, so I believe the issue is with how Ron parses these numeric values.

Support for multi-line string literals

Will RON ever support multi-line string literals? This is a feature that missing from JSON, but is present in YAML, TOML, and in Rust proper, like so:

# YAML multi-line string literals
key: >
  This is a very long sentence
  that spans several lines in the YAML
  but which will be rendered as a string
  without carriage returns.
# TOML multi-line string literals
key = '''
    This is a very long sentence
    that spans several lines in the TOML
    but which will be rendered as a string
    without carriage returns.
'''
// Rust multi-line string literals
let key = r#"
    This is a very long sentence
    that spans several lines in Rust
    but which will be rendered as a string
    without carriage returns.
"#;

let key = r##"
    This is a sentence which happens
    to contain a '#' character inside.
"##;

This could be a useful for storing localized strings for dialogue boxes, for example, or other complex strings that are too tedious and error-prone to escape by hand. Here is some pseudo-RON syntax showing how this feature could be used:

System(
    arch: "x86_64-linux",
    shell: "/usr/bin/bash",
    packages: ["firefox", "git", "rustup"],
    startup: r##"
        #!/usr/bin/bash
        export PS1="..."
        echo "Done booting!"
    "##,
)

Given that RON already mimics Rust's notation quite well, adopting its syntax for raw string literals would make this feature feel right at home. See the official reference page and Rust By Example for details.

Tuple structs

Tuple structs look like this:

struct TupleStruct(f32, f32);

Serializer

TupleStruct(2.0,3.0,)

Deserializer

TupleStruct(2.0, 3.0) or (2.0, 3.0)

Date and time

Interesting quote from a reddit comment:

No specification for how to handle dates or times. By convention, we've all kind of settled on ISO 8601, but JSON just gives us a string really. If you work with some older web services that offer JSON, particularly .NET-based ones, you're likely to get bit by this.

Pretty configuration

Possible things to configure:

  • type of indentation (N spaces, tab, etc)
  • type of newlines
  • making indentation for tuples

what else?

Register in Linguist database

Current view of a RON file in Github is rather unusable. Github uses Linguist for determining the syntax and applying the correct highlight. We should make an upstream feature to recognize RON.

Use in log-style formats

If the toplevel RON structure is an array, it needs matching [ and ] brackets in the beginning and end of the file, correct? What if I want to make an incremental log file that is only appended to and that parses as a valid RON file containing an array of log entry values after each write? I'd have to modify the existing file to remove the final ] before each new write.

There's JSON Lines for the JSON version of an incremental file. Maybe RON could have some built-in support?

A very hacky and nasty approach would be to simply let you omit the final closing ] if the toplevel syntax element is an array.

Consider a slightly more concise format especially for arrays

A more concise format for arrays can really help:

Instead of this:

Scene( // class name is optional
    materials: { // this is a map
        "metal": (
            reflectivity: 1.0,
        ),
        "plastic": (
            reflectivity: 0.5,
        ),
    },
    entities: [ // this is an array
        (
            name: "hero",
            material: "metal",
        ),
        (
            name: "monster",
            material: "plastic",
        ),
    ],
)

You can do something more concise:

Scene( // class name is optional
    materials: { // this is a map
        "metal": (
            reflectivity: 1.0,
        ),
        "plastic": (
            reflectivity: 0.5,
        ),
    },
    entities: [ 
       {"name", "material", }, //Use a map/tuple to define what fields will be there in each item in the array
       ( "hero", "metal"),  //the fields are presented in the same order with repeating column names
       ( "monster", "plastic",),
    ],
)

The first item in the array is actually an optional map which can be used to specify the column names.

entities[0]["name"] will be "hero"
entities[0]["material"] will be "metal"

..and so on.

If the map defining the list of column names is not provided for an array, perhaps we can default to using integers for the column names indexed from 0.

Consider an example below without column names:

Scene( // class name is optional
    materials: { // this is a map
        "metal": (
            reflectivity: 1.0,
        ),
        "plastic": (
            reflectivity: 0.5,
        ),
    },
    entities: [       
       ( "hero", "metal"),  //the fields are presented in the same order with repeating column names
       ( "monster", "plastic",),
    ],
)

That is:
entities[0][0] will be "hero"
entities[0][1] will be "metal"
entities[1][0] will be "monster"
entities[1][1] will be plastic"

Using a map or a tuple in an array is definitely a bit ugly - perhaps an alternate syntax can be used but it does significantly reduce the overall size of the data especially if there are 100s (or more) items in an array.

It is also conceivable that the map describing the columns could be made much more sophisticated.

Example:

Instead of:

  
"entities": [{"name", "material"},
     ("hero", "metal", ),
     ("monster", "plastic",),
 ],

The column definitions could be made much more detailed.

 "entities": [
            { "name": {
                 "type": "char",
                 "length": 10,
               },
              "material": {
                 "type": "char",
                 "length": 30,
              },
            },
          ("hero", "metal"),
          ("monster", "plastic"), 
  ]

Newtype structs

Newtype structs wrap an existing type:

struct NewType(i32);

I'm not sure here. Should it be NewType(3) with the name being optional? Or just 3?

a false deserialization panic: deserialize_ignore_any is called and not impl

test:

extern crate ron;
#[macro_use]
extern crate serde_derive;

#[derive(Serialize, Deserialize)]
pub struct ImVec2 {
    pub x: f32,
    pub y: f32,
}

#[derive(Serialize, Deserialize)]
pub struct ImColorsSave {
    pub text: f32,
}

#[derive(Serialize, Deserialize)]
pub struct ImGuiStyleSave {
    pub alpha: f32,
    pub window_padding: ImVec2,
    pub window_min_size: ImVec2,
    pub window_rounding: f32,
    pub window_title_align: ImVec2,
    pub child_window_rounding: f32,
    pub frame_padding: ImVec2,
    pub frame_rounding: f32,
    pub item_spacing: ImVec2,
    pub item_inner_spacing: ImVec2,
    pub touch_extra_padding: ImVec2,
    pub indent_spacing: f32,
    pub columns_min_spacing: f32,
    pub scrollbar_size: f32,
    pub scrollbar_rounding: f32,
    pub grab_min_size: f32,
    pub grab_rounding: f32,
    pub button_text_align: ImVec2,
    pub display_window_padding: ImVec2,
    pub display_safe_area_padding: ImVec2,
    pub anti_aliased_lines: bool,
    pub anti_aliased_shapes: bool,
    pub curve_tessellation_tol: f32,
    pub colors: ImColorsSave,
}

const CONFIG: &str = "
ImGuiStyleSave(
    alpha: 1.0,
    window_padding: (x: 8, y: 8),
    window_min_size: (x: 32, y: 32),
    window_rounding: 9.0,
    window_title_align: (x: 0.0, y: 0.5),
    child_window_rounding: 0.0,
    frame_padding: (x: 4, y: 3),
    frame_rounding: 0.0,
    item_spaciing: (x: 8, y: 4),
    item_inner_spacing: (x: 4, y: 4),
    touch_extra_padding: (x: 0, y: 0),
    indent_spacing: 21.0,
    columns_min_spacing: 6.0,
    scrollbar_size: 16,
    scrollbar_rounding: 9,
    grab_min_size: 10,
    grab_rounding: 0,
    button_text_align: (x: 0.5, y: 0.5),
    display_window_padding: (x: 22, y: 22),
    display_safe_area_padding: (x: 4, y: 4),
    anti_aliased_lines: true,
    anti_aliased_shapes: true,
    curve_tessellation_tol: 1.25,
    colors: (text: 4),
)";

#[test]
fn serde_with() {
    ron::de::from_str::<ImGuiStyleSave>(CONFIG).unwrap();
}
---- serde_with stdout ----
	thread 'serde_with' panicked at 'not yet implemented: IdDeserializer may only be used for identifiers', src/de/id.rs:224:8

Parser doesn't handle whitespace ...

between ( and [ of a newtype_struct wrapping a seq:

#[derive(Debug, Deserialize)]
struct Newtype(Vec<String>);

fn main() {
    let serialized = stringify!(
        Newtype([
            "a",
            "b",
            "c",
        ])
    );
    println!("{}", serialized);
    let deserialized: Result<Newtype, _> = ron::de::from_str(serialized);
    println!("{:#?}", deserialized);


    let serialized = r#"
        Newtype([
            "a",
            "b",
            "c",
        ])
    "#;
    println!("{}", serialized);
    let deserialized: Result<Newtype, _> = ron::de::from_str(serialized);
    println!("{:#?}", deserialized);
}
Newtype ( [ "a" , "b" , "c" , ] )
Err(
    Parser(
        ExpectedArray,
        Position {
            col: 10,
            line: 1
        }
    )
)

        Newtype([
            "a",
            "b",
            "c",
        ])
    
Ok(
    Newtype(
        [
            "a",
            "b",
            "c"
        ]
    )
)

(This is what I actually came here to report when I got sidetracked by the linguist+ronn history dive 😆)

Grammar in Repo rather than Wiki

We should probably put the specification for the grammar, and any related stuff (like recommendations or common uses), in the repo itself instead of the wiki. This way, we can modify and discuss the spec in pull requests; and the spec will be protected from a random person deciding to hit the "edit" button.

Don't allow struct name for unit

I think allowing that (as we currently do) is confusing; it provides no extra information, but makes it ambiguous whether it is a unit or an enum variant.

Structs

A struct in Rust looks like this

struct Struct {
    x: f32,
    y: f32,
}

Serializer

The serializer uses the following representation:

Struct(x:3.0,y:2.0,)

Deserialization

The values are expected to come in comma separated and surrounded by ( and ). The name of the struct is optional.

Comparison with Rust-Value (RSV)

In UNIC, we put auto-generated data tables into files we are calling Rust-Value (RSV), extensioned .rsv, which can contain basically any Rust expression (with all Rust requirements, like UTF-8 encoding), to be used inside the code using include!(<path-to-rsv>).

Examples:

What I want to note here is that RSV is more easier to use inside Rust code, being able to just include!()d. That's not exactly possible with RON, as the syntax is slightly different.

BUT, with a compile-time RON parser, it is possible to use RON in cases similar to UNIC's.

Just some thoughts, as we were considering to simplify data dumping process by using a serde-based solution, but couldn't find any existing tool.

Enums

Enums look like

enum Enum {
    A,
    B(i32),
    C(f32, f32),
    D { x: f32, y: f32 },
}

Proposed strategy: Only serialize / deserialize the variant name and use the format we have for unit types, newtype wrappers, tuple structs and structs, respectively.

Consider adding top-level attributes

Syntax: #![attribute_name] (like in Rust)

After reading https://ozkriff.github.io/2017-12-01--devlog.html where @ozkriff said that his configs (https://raw.githubusercontent.com/ozkriff/zemeroth_assets/master/objects.ron) aren't looking very nice because of how RON handles newtypes, I thought about adding attributes which allow to configure RON for your needs. Not only would this allow for toggles like #![unwrap_newtypes], but it could also be used to deal with new features. That way, we can just enforce that you need #![feature_name] to enable a RON feature, such that a parser without support for that feature can return a simple and understandable error.

Properly handle unicode

I'm pretty sure unicode support isn't fully implemented, so we would need tests and full support in serializer and deserializer. Additionally, rules should go into the spec (probably in a text document in this repository, as suggested somewhere).

'Invalid type' when deserialising to ndarray types

Unsure if this is a problem here, or ndarray, but considering I have no issues deserialising from json, yaml, messagepack etc to ndarray types, then I'm guessing here is a better place to start.

Using the Array3 type (which implements Deserialize if you enable the serde-1 feature) as an example, one can obtain the correct RON representation using to_string, but both from_reader and from_string yield an error.

A quick test:

let test = "(
    v: 1,
    dim: (1, 1, 1),
    data: [
        12.234,
    ],
)";

let conv: Array3<f64> = match ron::de::from_str(&test) {
    Ok(x) => x,
    Err(e) => {
        println!("{}", e);
    },
};

sees the following:

invalid type: byte array, expected "v", "dim", or "data"

Is this me configuring things incorrectly or has something been overlooked in this instance?

Design: trailing comma semantics

Current proposal:

  • require trailing comma for maps and non-tuple structs (which have named fields)
  • optional comma for tuples and tuple structs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.