From 10f4764a515b6d21ffbce00f417cf224e18d389a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Fri, 16 Sep 2016 19:04:24 +0200 Subject: [PATCH 1/3] Added ValueType which represents type of Json value --- json/src/value.rs | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/json/src/value.rs b/json/src/value.rs index ce6d9b5fe..7b5a05e2c 100644 --- a/json/src/value.rs +++ b/json/src/value.rs @@ -473,6 +473,99 @@ impl de::Deserialize for Value { } } +/// Represents type of a JSON value +#[derive(Clone, Copy, Eq, PartialEq, Debug)] +pub enum ValueType { + /// Represents a JSON null value type + Null, + + /// Represents a JSON Boolean type + Bool, + + /// Represents a JSON signed integer type + I64, + + /// Represents a JSON unsigned integer type + U64, + + /// Represents a JSON floating point number type + F64, + + /// Represents a JSON string type + String, + + /// Represents a JSON array type + Array, + + /// Represents a JSON object type + Object, +} + +impl ValueType { + + /// Returns type of a value + /// + /// # Example + /// + /// ```rust + /// extern crate serde_json; + /// + /// use serde_json::to_value; + /// use serde_json::value::ValueType; + /// use std::collections::BTreeMap; + /// + /// fn main() { + /// let null = to_value(()); + /// let boolean = to_value(true); + /// let int64 = to_value(-42i64); + /// let uint64 = to_value(18446744073709551337u64); + /// let float = to_value(3.1415926535f64); + /// let string = to_value("Hello world!"); + /// let array = to_value(&[1, 2, 3, 4, 5]); + /// let mut map = BTreeMap::new(); + /// map.insert("foo", to_value("bar")); + /// let map = to_value(&map); + /// + /// assert_eq!(ValueType::of(&null), ValueType::Null); + /// assert_eq!(ValueType::of(&boolean), ValueType::Bool); + /// assert_eq!(ValueType::of(&int64), ValueType::I64); + /// assert_eq!(ValueType::of(&uint64), ValueType::U64); + /// assert_eq!(ValueType::of(&float), ValueType::F64); + /// assert_eq!(ValueType::of(&string), ValueType::String); + /// assert_eq!(ValueType::of(&array), ValueType::Array); + /// assert_eq!(ValueType::of(&map), ValueType::Object); + /// } + pub fn of(val: &Value) -> Self { + match *val { + Value::Null => ValueType::Null, + Value::Bool(_) => ValueType::Bool, + Value::I64(_) => ValueType::I64, + Value::U64(_) => ValueType::U64, + Value::F64(_) => ValueType::F64, + Value::String(_) => ValueType::String, + Value::Array(_) => ValueType::Array, + Value::Object(_) => ValueType::Object, + } + } +} + +impl fmt::Display for ValueType { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + use self::ValueType::*; + + write!(f, "{}", match *self { + Null => "Null", + Bool => "Bool", + I64 => "I64", + U64 => "U64", + F64 => "F64", + String => "String", + Array => "Array", + Object => "Object", + }) + } +} + struct WriterFormatter<'a, 'b: 'a> { inner: &'a mut fmt::Formatter<'b>, } From e34a22839e751f414b3de7945e03dbdd20ee7cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Fri, 16 Sep 2016 19:09:04 +0200 Subject: [PATCH 2/3] Added TypeError --- json/src/error.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/json/src/error.rs b/json/src/error.rs index 7e863379d..adce45941 100644 --- a/json/src/error.rs +++ b/json/src/error.rs @@ -11,6 +11,8 @@ use std::result; use serde::de; use serde::ser; +use value::ValueType; + /// The errors that can arise while parsing a JSON stream. #[derive(Clone, PartialEq, Debug)] pub enum ErrorCode { @@ -256,3 +258,25 @@ impl ser::Error for Error { /// Helper alias for `Result` objects that return a JSON `Error`. pub type Result = result::Result; + +/// Represents type mismatch +#[derive(Debug)] +pub struct TypeError { + /// Type which was required + pub expected: ValueType, + + /// Type which was found in Json + pub provided: ValueType, +} + +impl error::Error for TypeError { + fn description(&self) -> &str { + "type mismatch" + } +} + +impl fmt::Display for TypeError { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "expected type: {} found type: {}", self.expected, self.provided) + } +} From ec4654e01b1076f1ecf4d72cc2b6d270fad9b574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Fri, 16 Sep 2016 22:53:27 +0200 Subject: [PATCH 3/3] Implemented as_borrow() and as_borrow_mut() generic functions. --- json/src/value.rs | 224 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 223 insertions(+), 1 deletion(-) diff --git a/json/src/value.rs b/json/src/value.rs index 7b5a05e2c..d46e9a1e7 100644 --- a/json/src/value.rs +++ b/json/src/value.rs @@ -48,7 +48,7 @@ use num_traits::NumCast; use serde::de; use serde::ser; -use error::{Error, ErrorCode}; +use error::{Error, ErrorCode, TypeError}; /// Represents a key/value type. #[cfg(not(feature = "preserve_order"))] @@ -215,6 +215,92 @@ impl Value { } } + /// If the `Value` is of type `T`, returns borrow of internal value. + /// Returns Err otherwise. + /// + /// Useful for generics with larger/allocated types to speed things up. + /// + /// # Example + /// + /// ```rust + /// extern crate serde_json; + /// + /// use serde_json::{to_value,Value}; + /// use serde_json::value::ValueType; + /// use std::collections::BTreeMap; + /// + /// fn main() { + /// let null = to_value(()); + /// let boolean = to_value(true); + /// let int64 = to_value(-42i64); + /// let uint64 = to_value(18446744073709551337u64); + /// let float = to_value(3.1415926535f64); + /// let string = to_value("Hello world!"); + /// let array = to_value(&[1, 2, 3, 4, 5]); + /// let mut map = BTreeMap::new(); + /// map.insert("foo", to_value("bar")); + /// let map = to_value(&map); + /// + /// let _: &() = null.as_borrow().unwrap(); + /// let _: &bool = boolean.as_borrow().unwrap(); + /// let _: &i64 = int64.as_borrow().unwrap(); + /// let _: &u64 = uint64.as_borrow().unwrap(); + /// let _: &f64 = float.as_borrow().unwrap(); + /// let _: &str = string.as_borrow().unwrap(); + /// let _: &String = string.as_borrow().unwrap(); + /// let _: &[Value] = array.as_borrow().unwrap(); + /// let _: &Vec = array.as_borrow().unwrap(); + /// let _: &BTreeMap = map.as_borrow().unwrap(); + /// } + pub fn as_borrow<'a, T: TryBorrow<'a>>(&'a self) -> Result { + T::try_borrow(self) + } + + /// If the `Value` is of type `T`, returns mutable borrow of internal value. + /// Returns Err otherwise. + /// + /// Useful for generics with larger/allocated types to speed things up. + /// + /// # Example + /// + /// ```rust + /// extern crate serde_json; + /// + /// use serde_json::{to_value,Value}; + /// use serde_json::value::ValueType; + /// use std::collections::BTreeMap; + /// + /// fn main() { + /// let mut null = to_value(()); + /// let mut boolean = to_value(true); + /// let mut int64 = to_value(-42i64); + /// let mut uint64 = to_value(18446744073709551337u64); + /// let mut float = to_value(3.1415926535f64); + /// let mut string = to_value("Hello world!"); + /// let mut array = to_value(&[1, 2, 3, 4, 5]); + /// let mut map = BTreeMap::new(); + /// map.insert("foo", to_value("bar")); + /// let mut map = to_value(&map); + /// + /// let _: &mut () = null.as_borrow_mut().unwrap(); + /// let _: &mut bool = boolean.as_borrow_mut().unwrap(); + /// let _: &mut i64 = int64.as_borrow_mut().unwrap(); + /// let _: &mut u64 = uint64.as_borrow_mut().unwrap(); + /// let _: &mut f64 = float.as_borrow_mut().unwrap(); + /// { + /// let _: &mut str = string.as_borrow_mut().unwrap(); + /// } + /// let _: &mut String = string.as_borrow_mut().unwrap(); + /// { + /// let _: &mut [Value] = array.as_borrow_mut().unwrap(); + /// } + /// let _: &mut Vec = array.as_borrow_mut().unwrap(); + /// let _: &mut BTreeMap = map.as_borrow_mut().unwrap(); + /// } + pub fn as_borrow_mut<'a, T: TryBorrowMut<'a>>(&'a mut self) -> Result { + T::try_borrow_mut(self) + } + /// Returns true if the `Value` is an Object. Returns false otherwise. pub fn is_object(&self) -> bool { self.as_object().is_some() @@ -1426,3 +1512,139 @@ impl ToJson for T to_value(&self) } } + +/// Just like `std::borrow::Borrow` but borrowing may fail. +pub trait TryBorrow<'a>: 'a + ::std::marker::Sized { + /// Returns reference to internal data if type matches. + fn try_borrow(value: &'a Value) -> Result; +} + +impl<'a> TryBorrow<'a> for &'a () { + fn try_borrow(value: &'a Value) -> Result { + static EMPTY: () = (); + if value.is_null() { Ok(&EMPTY) } else { Err(TypeError { expected: ValueType::Null, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a bool { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::Bool(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Bool, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a u64 { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::U64(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::U64, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a i64 { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::I64(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::I64, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a f64 { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::F64(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::F64, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a str { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::String(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::String, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a String { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::String(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::String, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a [Value] { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::Array(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Array, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a Vec { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::Array(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Array, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrow<'a> for &'a Map { + fn try_borrow(value: &'a Value) -> Result { + if let &Value::Object(ref val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Object, provided: ValueType::of(value) }) } + } +} + +/// Just like `std::borrow::BorrowMut` but borrowing may fail. +pub trait TryBorrowMut<'a>: 'a + ::std::marker::Sized { + /// Returns mutable reference to internal data if type matches. + fn try_borrow_mut(value: &'a mut Value) -> Result; +} + +impl<'a> TryBorrowMut<'a> for &'a mut () { + fn try_borrow_mut(value: &'a mut Value) -> Result { + static mut EMPTY: () = (); + // Use of static &mut () is always safe, because it's value actually can't be changed + if value.is_null() { unsafe { Ok(&mut EMPTY) } } else { Err(TypeError { expected: ValueType::Null, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut bool { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::Bool(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Bool, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut u64 { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::U64(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::U64, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut i64 { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::I64(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::I64, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut f64 { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::F64(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::F64, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut str { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::String(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::String, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut String { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::String(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::String, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut [Value] { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::Array(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Array, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut Vec { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::Array(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Array, provided: ValueType::of(value) }) } + } +} + +impl<'a> TryBorrowMut<'a> for &'a mut Map { + fn try_borrow_mut(value: &'a mut Value) -> Result { + if let &mut Value::Object(ref mut val) = value { Ok(val) } else { Err(TypeError { expected: ValueType::Object, provided: ValueType::of(value) }) } + } +} +