[][src]Trait nop_json::TryFromJson

pub trait TryFromJson: Sized {
    fn try_from_json<T>(reader: &mut Reader<T>) -> Result<Self>
    where
        T: Iterator<Item = u8>
; }

Implementing this trait makes possible to any type (except unions) to be JSON deserializable. The common technique to implement this trait is automatically through #[derive(TryFromJson)].

Examples

use nop_json::{Reader, TryFromJson, DebugToJson};

#[derive(TryFromJson, DebugToJson, PartialEq)]
struct Point {x: i32, y: i32}

#[derive(TryFromJson, DebugToJson, PartialEq)]
#[json(type)]
enum Geometry
{	#[json(point)] Point(Point),
	#[json(cx, cy, r)] Circle(i32, i32, i32),
	Nothing,
}

let mut reader = Reader::new(r#" {"type": "Point", "point": {"x": 0, "y": 0}} "#.bytes());
let obj: Geometry = reader.read().unwrap();
assert_eq!(obj, Geometry::Point(Point {x: 0, y: 0}));

Here we deserialize a struct, and an enum. Struct Point {x: 0, y: 0} will be written as {"x": 0, "y": 0}.

We can use different names for "x" and "y". Every struct field can be optionally annotated with #[json(field_name)] attribute, or #[json("field_name")].

For enums we need to give names to each field, plus to "variant" field. The name of the "variant" field is specified at enum level. In the example above, it's "type" (#[json(type)]). So Geometry::Circle(0, 0, 1) will be written as {"type": "Circle", "cx": 0, "cy": 0, "r": 1}.

Variant name is printed as it's called in enum ("Point", "Circle", "Nothing"). We can rename them if specify #[json(variant_name(field_name_0, field_name_1, ...))].

use nop_json::{Reader, TryFromJson, DebugToJson};

#[derive(TryFromJson, DebugToJson, PartialEq)]
struct Point {x: i32, y: i32}

#[derive(TryFromJson, DebugToJson, PartialEq)]
#[json(var)]
enum Geometry
{	#[json(pnt(point))] Point(Point),
	#[json(cir(cx, cy, r))] Circle(i32, i32, i32),
	Nothing,
}

let mut reader = Reader::new(r#" {"var": "pnt", "point": {"x": 0, "y": 0}} "#.bytes());
let obj: Geometry = reader.read().unwrap();
assert_eq!(obj, Geometry::Point(Point {x: 0, y: 0}));

There's also another option: to choose variant according to content. To do so, we ommit #[json(...)] at enum level. This is only possible if variants have non-overlapping members.

use nop_json::{Reader, TryFromJson, DebugToJson};

#[derive(TryFromJson, DebugToJson, PartialEq)]
struct Point {x: i32, y: i32}

#[derive(TryFromJson, DebugToJson, PartialEq)]
enum Geometry
{	#[json(point)] Point(Point),
	#[json(cx, cy, r)] Circle(i32, i32, i32),
	Nothing,
}

let mut reader = Reader::new(r#" {"point": {"x": 0, "y": 0}} "#.bytes());
let obj: Geometry = reader.read().unwrap();
assert_eq!(obj, Geometry::Point(Point {x: 0, y: 0}));

To exclude a field from deserialization, and use default value for it, specify empty name (#[json("")]).

use nop_json::{Reader, TryFromJson, DebugToJson};

#[derive(TryFromJson, DebugToJson, PartialEq)]
struct Point {x: i32, y: i32, #[json("")] comments: String}

#[derive(TryFromJson, DebugToJson, PartialEq)]
enum Geometry
{	#[json(point)] Point(Point),
	#[json(cx, cy, r)] Circle(i32, i32, i32),
	Nothing,
}

let mut reader = Reader::new(r#" {"point": {"x": 0, "y": 0, "comments": "hello"}} "#.bytes());
let obj_0: Geometry = reader.read().unwrap();
assert_eq!(obj_0, Geometry::Point(Point {x: 0, y: 0, comments: String::new()}));

let mut reader = Reader::new(r#" {"point": {"x": 0, "y": 0}} "#.bytes());
let obj_0: Geometry = reader.read().unwrap();
assert_eq!(obj_0, Geometry::Point(Point {x: 0, y: 0, comments: String::new()}));

It's possible to validate object right after deserialization. To do so implement ok_from_json() function.

use nop_json::{Reader, TryFromJson};

#[derive(TryFromJson, Debug)]
struct FromTo {from: i32, to: i32}

impl FromTo
{	fn ok_from_json(self) -> Result<Self, String>
	{	if self.from <= self.to
		{	Ok(self)
		}
		else
		{	Err("to must be after from".to_string())
		}
	}
}

Automatic implementation through #[derive(TryFromJson)] has 1 limitation: object key string must be not longer than 128 bytes, or it will be cut.

Sometimes that can be different reasons to implement TryFromJson manually. Let's see how the automatic implementation looks like.

struct Point {x: i32, y: i32}

impl nop_json::TryFromJson for Point
{	fn try_from_json<T>(reader: &mut nop_json::Reader<T>) -> std::io::Result<Self> where T: Iterator<Item=u8>
	{	use nop_json::OrDefault;
		use nop_json::OkFromJson;

		let mut x = None;
		let mut y = None;

		reader.read_object_use_buffer
		(	|reader|
			{	match reader.get_key()
				{	b"x" => x = reader.read_prop("x")?,
					b"y" => y = reader.read_prop("y")?,
					_ => return Err(reader.format_error_fmt(format_args!("Invalid property: {}", String::from_utf8_lossy(reader.get_key()))))
				}
				Ok(())
			}
		)?;

		let result = Self
		{	x: x.or_default().ok_or_else(|| reader.format_error("Member \"x\" doesn't have default value. To make optional #[derive(Default)]"))?,
			y: y.or_default().ok_or_else(|| reader.format_error("Member \"y\" doesn't have default value. To make optional #[derive(Default)]"))?,
		};
		result.ok_from_json().map_err(|msg| reader.format_error(&msg))
	}
}

This implementation uses reader.read_object_use_buffer() which reads object keys to internal buffer which is 128 bytes, without memory allocation. You can use reader.read_object() instead. Also you can do different things in this implementation function.

Required methods

fn try_from_json<T>(reader: &mut Reader<T>) -> Result<Self> where
    T: Iterator<Item = u8>, 

Loading content...

Implementations on Foreign Types

impl TryFromJson for ()[src]

impl TryFromJson for isize[src]

impl TryFromJson for i128[src]

impl TryFromJson for i64[src]

impl TryFromJson for i32[src]

impl TryFromJson for i16[src]

impl TryFromJson for i8[src]

impl TryFromJson for usize[src]

impl TryFromJson for u128[src]

impl TryFromJson for u64[src]

impl TryFromJson for u32[src]

impl TryFromJson for u16[src]

impl TryFromJson for u8[src]

impl TryFromJson for f64[src]

impl TryFromJson for f32[src]

impl TryFromJson for bool[src]

impl TryFromJson for char[src]

impl TryFromJson for String[src]

impl<U> TryFromJson for Box<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for RwLock<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for Mutex<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for Rc<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for Arc<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for Option<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for Vec<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for HashSet<U> where
    U: Eq + Hash + TryFromJson
[src]

impl<U> TryFromJson for LinkedList<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for VecDeque<U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for BTreeSet<U> where
    U: Ord + TryFromJson
[src]

impl<U> TryFromJson for HashMap<String, U> where
    U: TryFromJson
[src]

impl<U> TryFromJson for BTreeMap<String, U> where
    U: TryFromJson
[src]

impl<U, V> TryFromJson for (U, V) where
    U: TryFromJson,
    V: TryFromJson
[src]

impl<U, V, W> TryFromJson for (U, V, W) where
    U: TryFromJson,
    V: TryFromJson,
    W: TryFromJson
[src]

Loading content...

Implementors

impl TryFromJson for Value[src]

Loading content...