Use TryFrom trait instead of From trait for type conversions from JSONValue
All checks were successful
timw4mail/json-parser/master This commit looks good

This commit is contained in:
Timothy Warren 2020-02-12 13:33:20 -05:00
parent fe19b61803
commit cefaa86ded
2 changed files with 69 additions and 47 deletions

View File

@ -7,7 +7,8 @@
//! //!
//! Basic usage: //! Basic usage:
//! ```rust //! ```rust
//! use naive_json_parser::{JSON, JSONArray}; //! use std::convert::TryFrom;
//! use naive_json_parser::{JSON, JSONArray, JSONValue};
//! //!
//! // Convert the JSON string to a `JSONValue` //! // Convert the JSON string to a `JSONValue`
//! let result = JSON::parse("[0, 1, 2]"); //! let result = JSON::parse("[0, 1, 2]");
@ -17,13 +18,23 @@
//! let result = result.unwrap(); //! let result = result.unwrap();
//! //!
//! // If you want the value inside of the top `JSONValue`, you //! // If you want the value inside of the top `JSONValue`, you
//! // may use the `into` or `unwrap` methods //! // may use the `unwrap` method
//! let array: JSONArray = result.clone().into(); // or //! let array: JSONArray = result.clone().unwrap();
//! let array: JSONArray = result.clone().unwrap(); // or //!
//! let array = JSONArray::from(result.clone()); //! // You may also try the type conversion directly, so you can handle a potential error
//! let array = match JSONArray::try_from(result.clone()) {
//! Ok(a) => a,
//! Err(_) => todo!(),
//! };
//!
//! // If you want to create a `JSONValue` from one of its wrapped types, you
//! // may use the `from` or `into` methods
//! let json_array = JSONValue::from(array.clone()); // or
//! let json_array: JSONValue = array.clone().into();
//! ``` //! ```
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::{char, u16}; use std::{char, u16};
@ -79,63 +90,71 @@ impl JSONValue {
/// ///
/// # assert_eq!(str, &s); /// # assert_eq!(str, &s);
/// ``` /// ```
pub fn unwrap<T: From<JSONValue>>(self) -> T { pub fn unwrap<T: TryFrom<JSONValue>>(self) -> T {
T::from(self) match T::try_from(self) {
Ok(val) => val,
Err(_) => panic!("Tried to unwrap an empty value")
}
} }
} }
impl From<JSONValue> for JSONMap { impl TryFrom<JSONValue> for JSONMap {
type Error = &'static str;
/// Extracts the `HashMap` in the `JSONValue` enum, if it exists. /// Extracts the `HashMap` in the `JSONValue` enum, if it exists.
/// Otherwise, panics. fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
fn from(val: JSONValue) -> JSONMap { match v {
match val { JSONValue::Object(o) => Ok(o),
JSONValue::Object(o) => o, _ => Err("Invalid type conversion")
_ => unreachable!(),
} }
} }
} }
impl From<JSONValue> for JSONArray { impl TryFrom<JSONValue> for JSONArray {
type Error = &'static str;
/// Extracts the `Vec` in the `JSONValue` enum, if it exists. /// Extracts the `Vec` in the `JSONValue` enum, if it exists.
/// Otherwise, panics. fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
fn from(val: JSONValue) -> JSONArray { match v {
match val { JSONValue::Array(a) => Ok(a),
JSONValue::Array(a) => a, _ => Err("Invalid type conversion")
_ => unreachable!(),
} }
} }
} }
impl From<JSONValue> for f64 { impl TryFrom<JSONValue> for f64 {
type Error = &'static str;
/// Extracts the `f64` in the `JSONValue` enum, if it exists. /// Extracts the `f64` in the `JSONValue` enum, if it exists.
/// Otherwise, panics. fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
fn from(val: JSONValue) -> f64 { match v {
match val { JSONValue::Number(n) => Ok(n),
JSONValue::Number(n) => n, _ => Err("Invalid type conversion")
_ => unreachable!(),
} }
} }
} }
impl From<JSONValue> for String { impl TryFrom<JSONValue> for String {
type Error = &'static str;
/// Extracts the `String` in the `JSONValue` enum, if it exists. /// Extracts the `String` in the `JSONValue` enum, if it exists.
/// Otherwise, panics. fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
fn from(val: JSONValue) -> String { match v {
match val { JSONValue::String(s) => Ok(s),
JSONValue::String(s) => s, _ => Err("Invalid type conversion")
_ => unreachable!(),
} }
} }
} }
impl From<JSONValue> for bool { impl TryFrom<JSONValue> for bool {
/// Extracts the `bool` value from the `JSONValue` enum, if it exists. type Error = &'static str;
/// Otherwise, panics.
fn from(val: JSONValue) -> bool { /// Extracts the `bool` in the `JSONValue` enum, if it exists.
match val { fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
JSONValue::True => true, match v {
JSONValue::False => false, JSONValue::True => Ok(true),
_ => unreachable!(), JSONValue::False => Ok(false),
_ => Err("Invalid type conversion")
} }
} }
} }
@ -320,7 +339,7 @@ impl JSON {
self.skip_whitespace(); self.skip_whitespace();
self.eat(':')?; self.eat(':')?;
let key = maybe_key.unwrap().into(); let key = maybe_key.unwrap().unwrap();
let value = self.parse_value()?; let value = self.parse_value()?;
result.insert(key, value); result.insert(key, value);

View File

@ -1,10 +1,11 @@
use naive_json_parser::JSONValue::{Array, False, Null, Number, Object, True}; use naive_json_parser::JSONValue::{Array, False, Null, Number, Object, True};
use naive_json_parser::*; use naive_json_parser::*;
use std::collections::HashMap; use std::collections::HashMap;
use std::convert::TryFrom;
use std::f64::consts::PI; use std::f64::consts::PI;
#[test] #[test]
fn value_conversion() { fn value_conversion() -> Result<(), &'static str> {
let map: JSONMap = HashMap::new(); let map: JSONMap = HashMap::new();
let num = 9.380831539; let num = 9.380831539;
let str = "applesauce"; let str = "applesauce";
@ -14,13 +15,15 @@ fn value_conversion() {
JSONValue::from(str), JSONValue::from(str),
]; ];
assert_eq!(map.clone(), JSONMap::from(JSONValue::from(map.clone()))); assert_eq!(map.clone(), JSONMap::try_from(JSONValue::from(map.clone()))?);
assert_eq!(num, f64::from(JSONValue::from(num))); assert_eq!(num, f64::try_from(JSONValue::from(num))?);
assert_eq!(String::from(str), String::from(JSONValue::from(str))); assert_eq!(String::from(str), String::try_from(JSONValue::from(str))?);
assert_eq!(arr.clone(), JSONArray::from(JSONValue::from(arr.clone()))); assert_eq!(arr.clone(), JSONArray::try_from(JSONValue::from(arr.clone()))?);
assert_eq!(true, bool::from(JSONValue::from(true))); assert_eq!(true, bool::try_from(JSONValue::from(true))?);
assert_eq!(false, bool::from(JSONValue::from(false))); assert_eq!(false, bool::try_from(JSONValue::from(false))?);
assert_eq!((), <()>::from(JSONValue::from(()))); assert_eq!((), <()>::from(JSONValue::from(())));
Ok(())
} }
#[test] #[test]