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

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:
//! ```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`
//! let result = JSON::parse("[0, 1, 2]");
@ -17,13 +18,23 @@
//! let result = result.unwrap();
//!
//! // If you want the value inside of the top `JSONValue`, you
//! // may use the `into` or `unwrap` methods
//! let array: JSONArray = result.clone().into(); // or
//! let array: JSONArray = result.clone().unwrap(); // or
//! let array = JSONArray::from(result.clone());
//! // may use the `unwrap` method
//! let array: JSONArray = result.clone().unwrap();
//!
//! // 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)]
use std::collections::HashMap;
use std::convert::TryFrom;
use std::iter::FromIterator;
use std::{char, u16};
@ -79,63 +90,71 @@ impl JSONValue {
///
/// # assert_eq!(str, &s);
/// ```
pub fn unwrap<T: From<JSONValue>>(self) -> T {
T::from(self)
pub fn unwrap<T: TryFrom<JSONValue>>(self) -> T {
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.
/// Otherwise, panics.
fn from(val: JSONValue) -> JSONMap {
match val {
JSONValue::Object(o) => o,
_ => unreachable!(),
fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
match v {
JSONValue::Object(o) => Ok(o),
_ => Err("Invalid type conversion")
}
}
}
impl From<JSONValue> for JSONArray {
impl TryFrom<JSONValue> for JSONArray {
type Error = &'static str;
/// Extracts the `Vec` in the `JSONValue` enum, if it exists.
/// Otherwise, panics.
fn from(val: JSONValue) -> JSONArray {
match val {
JSONValue::Array(a) => a,
_ => unreachable!(),
fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
match v {
JSONValue::Array(a) => Ok(a),
_ => Err("Invalid type conversion")
}
}
}
impl From<JSONValue> for f64 {
impl TryFrom<JSONValue> for f64 {
type Error = &'static str;
/// Extracts the `f64` in the `JSONValue` enum, if it exists.
/// Otherwise, panics.
fn from(val: JSONValue) -> f64 {
match val {
JSONValue::Number(n) => n,
_ => unreachable!(),
fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
match v {
JSONValue::Number(n) => Ok(n),
_ => Err("Invalid type conversion")
}
}
}
impl From<JSONValue> for String {
impl TryFrom<JSONValue> for String {
type Error = &'static str;
/// Extracts the `String` in the `JSONValue` enum, if it exists.
/// Otherwise, panics.
fn from(val: JSONValue) -> String {
match val {
JSONValue::String(s) => s,
_ => unreachable!(),
fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
match v {
JSONValue::String(s) => Ok(s),
_ => Err("Invalid type conversion")
}
}
}
impl From<JSONValue> for bool {
/// Extracts the `bool` value from the `JSONValue` enum, if it exists.
/// Otherwise, panics.
fn from(val: JSONValue) -> bool {
match val {
JSONValue::True => true,
JSONValue::False => false,
_ => unreachable!(),
impl TryFrom<JSONValue> for bool {
type Error = &'static str;
/// Extracts the `bool` in the `JSONValue` enum, if it exists.
fn try_from(v: JSONValue) -> Result<Self, Self::Error> {
match v {
JSONValue::True => Ok(true),
JSONValue::False => Ok(false),
_ => Err("Invalid type conversion")
}
}
}
@ -320,7 +339,7 @@ impl JSON {
self.skip_whitespace();
self.eat(':')?;
let key = maybe_key.unwrap().into();
let key = maybe_key.unwrap().unwrap();
let value = self.parse_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::*;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::f64::consts::PI;
#[test]
fn value_conversion() {
fn value_conversion() -> Result<(), &'static str> {
let map: JSONMap = HashMap::new();
let num = 9.380831539;
let str = "applesauce";
@ -14,13 +15,15 @@ fn value_conversion() {
JSONValue::from(str),
];
assert_eq!(map.clone(), JSONMap::from(JSONValue::from(map.clone())));
assert_eq!(num, f64::from(JSONValue::from(num)));
assert_eq!(String::from(str), String::from(JSONValue::from(str)));
assert_eq!(arr.clone(), JSONArray::from(JSONValue::from(arr.clone())));
assert_eq!(true, bool::from(JSONValue::from(true)));
assert_eq!(false, bool::from(JSONValue::from(false)));
assert_eq!(map.clone(), JSONMap::try_from(JSONValue::from(map.clone()))?);
assert_eq!(num, f64::try_from(JSONValue::from(num))?);
assert_eq!(String::from(str), String::try_from(JSONValue::from(str))?);
assert_eq!(arr.clone(), JSONArray::try_from(JSONValue::from(arr.clone()))?);
assert_eq!(true, bool::try_from(JSONValue::from(true))?);
assert_eq!(false, bool::try_from(JSONValue::from(false))?);
assert_eq!((), <()>::from(JSONValue::from(())));
Ok(())
}
#[test]