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

Roudtrip RON <-> JSON #543

Open
mrchantey opened this issue Aug 3, 2024 · 2 comments
Open

Roudtrip RON <-> JSON #543

mrchantey opened this issue Aug 3, 2024 · 2 comments

Comments

@mrchantey
Copy link

mrchantey commented Aug 3, 2024

It seems we can convert from RON to JSON but the inverse has unexpected behavior, calling ron::to_string_pretty() on a serde_json::Value outputs json, not ron.

use anyhow::Result;

pub fn ron_to_json(ron_str: &str) -> Result<String> {
  let ron_val = ron::de::from_str::<ron::Value>(ron_str)?;
  let json_str = serde_json::to_string_pretty(&ron_val)?;
  Ok(json_str)
}

pub fn json_to_ron(json_str: &str) -> Result<String> {
  let json_val = serde_json::from_str::<serde_json::Value>(json_str)?;
  let ron_str = ron::ser::to_string_pretty(&json_val, Default::default())?;
  Ok(ron_str)
}

#[cfg(test)]
mod test {
  use anyhow::Result;
  use serde::Deserialize;
  use serde::Serialize;
  use sweet::*;

  #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
  struct MyStruct {
    name: String,
    age: u32,
  }

  #[test]
  fn ron_to_json() -> Result<()> {
    let val = MyStruct {
      name: "John".to_string(),
      age: 32,
    };
    let ron_str = ron::ser::to_string_pretty(&val, Default::default())?;
    let json = crate::utils::ron_to_json(&ron_str)?;
    let ron_str2 = crate::utils::json_to_ron(&json)?;
    // this line fails because ron_str2 is outputted in json format
    let val2 = ron::de::from_str::<MyStruct>(&ron_str2)?;
    expect(val).to_be(val2)?;

    println!("{}", ron_str);
    println!("{}", json);
    println!("{}", ron_str2);

    Ok(())
  }
}
@juntyr
Copy link
Member

juntyr commented Aug 4, 2024

Yes, that is expected behaviour. RON is a superset of JSON, so all JSON documents are valid RON documents. But RON also supports structs and enums with a Rusty syntax, which is not supported by JSON. In your ron_to_json function, you serialize a ron::Value to JSON, which maps all RON-specific concepts down into JSON in a destructive process, e.g. MyStruct(name: "John", age: 32) becomes {"name": "John", "age": 32}. While RON can still parse this JSON document, it cannot convert it back to the original since a map is not a struct.

TLDR: RON can roundtrip JSON documents (through JSON and RON), but not RON documents through JSON.

Still, a reformulation of this issue is on my long-term TODO list. serde::Value will get some love in a future release to allow all RON documents to roundtrip through it. Perhaps it could then also be given the ability to switch to a more verbose encoding when targeting a non-RON format such that RON -> ron::Value -> JSON -> ron::Value -> RON could roundtrip ... but I'm still not 100% sure that this would work.

@mrchantey
Copy link
Author

Ok that makes sense thanks for the explanation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants