Trait nop_json::TryFromJson[][src]

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 for any type (except unions) to be JSON deserializable. The common technique to implement this trait is automatically through #[derive(TryFromJson)]. Every type that implements TryFromJson must also implement ValidateJson. And every deserializable field must implement Default.

Examples

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

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

#[derive(TryFromJson, ValidateJson, 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, ValidateJson, DebugToJson};

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

#[derive(TryFromJson, ValidateJson, 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, ValidateJson, DebugToJson};

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

#[derive(TryFromJson, ValidateJson, 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, ValidateJson, DebugToJson};

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

#[derive(TryFromJson, ValidateJson, 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 ValidateJson.

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

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

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

let mut reader = Reader::new(r#" {"from": 1, "to": 2}  {"from": 2, "to": 1} "#.bytes());
let from_to_1_2: Result<FromTo, std::io::Error> = reader.read();
let from_to_2_1: Result<FromTo, std::io::Error> = reader.read();
assert!(from_to_1_2.is_ok());
assert!(from_to_2_1.is_err());

Implementing TryFromJson manually

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

Sometimes there can be different reasons to implement TryFromJson manually. Let’s see what the automatic implementation does expand to.

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

struct Point {x: i32, y: i32}

impl ValidateJson for Point {}

impl TryFromJson for Point
{	fn try_from_json<T>(reader: &mut Reader<T>) -> std::io::Result<Self> where T: Iterator<Item=u8>
	{	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.unwrap_or_default(),
			y: y.unwrap_or_default(),
		};
		result.validate_json().map_err(|msg| reader.format_error(&msg))
	}
}

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

The automatic TryFromJson implementation generates JSON objects. If our struct is just a wrapper around a primitive type, we may wish to serialize it to a primitive type.

use std::{io, fmt};
use nop_json::{Reader, TryFromJson, DebugToJson, escape};

#[derive(PartialEq)]
struct Wrapper
{	value: String,
	comment: String,
}

impl TryFromJson for Wrapper
{	fn try_from_json<T>(reader: &mut Reader<T>) -> io::Result<Self> where T: Iterator<Item=u8>
	{	reader.read::<String>().map(|value| Self {value, comment: Default::default()})
	}
}
impl DebugToJson for Wrapper
{	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{	write!(f, "\"{}\"", escape(&self.value))
	}
}
impl fmt::Debug for Wrapper
{	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
	{	DebugToJson::fmt(self, f)
	}
}

let mut reader = Reader::new(r#" "the value" "#.bytes());
let wrp: Wrapper = reader.read().unwrap();
assert_eq!(wrp, Wrapper {value: "the value".to_string(), comment: "".to_string()});

Required methods

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

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...