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

JSON abstraction #803

Closed
timothee-haudebourg opened this issue Sep 16, 2021 · 2 comments
Closed

JSON abstraction #803

timothee-haudebourg opened this issue Sep 16, 2021 · 2 comments

Comments

@timothee-haudebourg
Copy link

timothee-haudebourg commented Sep 16, 2021

JSON is an ubiquitous format used in many applications. There is no single way of storing JSON values depending on the context, sometimes leading some applications to use multiples representations of JSON values in the same place. This can cause a problem for JSON processing libraries that should not care about the actual internal representation of JSON values, but are forced to stick to a particular format, leading to unwanted and costly conversions between the different formats.

I am currently working on the json-ld library that provides an implementation of the JSON-LD data interchange format, based on JSON. One of my goals is to provide useful error reports when the input JSON document cannot be processed. This includes pinpointing the exact line-column position of the error, something that cannot be done with serde_json since code-mapping metadata is not kept by the parser. That is why I am also working on a JSON parsing crate providing such information. However I do not want to force my users to use my crate over serde_json whenever precise error reports are not needed.

To solve this issue, my idea was to define common JSON features in a dedicated library, generic-json (still a work in progress), defining a basic Json trait abstracting away implementation details and a standard Value type defining the structure of a JSON value. This could give something like this:

/// JSON document with metadata.
pub trait Json {
	/// Metadata associated to each JSON value.
	/// In the case of `serde_json` this would be `()`.
	/// In my case, that would be a more complicated type including code-mapping info.
	type MetaData;
	
	/// Number type.
	type Number;

	/// String type.
	type String;

	/// Array type.
	type Array;

	/// Object key type.
	type Key;

	/// Object type.
	type Object;
}

pub trait MetaValue<T: Json> {
	fn metadata(&self) -> &T::Metadata;

	fn value(&self) -> &Value<T>;
}

pub enum Value<T: Json> {
	Null,
	Bool(bool),
	Number(T::Number),
	String(T::String),
	Array(T::Array),
	Object(T::Object)
}

Would you be open to rely on such crate to define the Value type and improve interoperability with other JSON crates?
Your Value type definition would become something like:

pub struct SerdeJson;

impl generic_json::Json for SerdeJson {
	type MetaData = ();
	
	type Number = Number;

	type String = String;

	type Array = Vec<Value>;

	type Key = String;

	type Object = Map<String, Value>;
}

pub type Value = generic_json::Value<SerdeJson>;

impl generic_json::MetaValue for Value {
	fn metadata(&self) -> &() {
		&()
	}

	fn value(&self) -> &Value {
		self
	}
}

In practice, that would not change anything about the Value type except that its actual definition would end up in an upstream crate. In theory, you would not need a major release for this. What do you think? I can open a PR for this (once the we agree on the content of the generic-json crate).

@timothee-haudebourg
Copy link
Author

Well even if it is in theory possible, having Value as an upstream type is too cumbersome. Instead, I propose to have a ValueRef type that holds reference to the inner data of the value:

pub trait MetaValue<T: Json> {
	fn metadata(&self) -> &T::Metadata;

	fn value(&self) -> &ValueRef<'_, T>;
}

pub enum ValueRef<'v, T: Json> {
	Null,
	Bool(bool),
	Number(&'v T::Number),
	String(&'v T::String),
	Array(&'v T::Array),
	Object(&'v T::Object)
}

Pros: the definition of Value stays in the crate, nothing is removed. My proposition could even be feature gated.
Cons: this adds a level of translation between Value and ValueRef, but I think it is a small price to pay to gain interoperability.

@dtolnay
Copy link
Member

dtolnay commented Jan 22, 2022

I don't think anything here is something I would want to pursue in this crate. Thanks anyway for the suggestion!

@dtolnay dtolnay closed this as completed Jan 22, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants