blob: 817ad34393181407486dd6d41ed7f099b7d5c9c8 [file] [log] [blame]
use { Result, Error };
use std::ops::{ Index, IndexMut, Deref };
use std::{ fmt, mem, usize, u8, u16, u32, u64, isize, i8, i16, i32, i64, f32 };
use std::string::String;
use std::vec::Vec;
use std::io::{ self, Write };
use short::Short;
use number::Number;
use object::Object;
use iterators::{ Members, MembersMut, Entries, EntriesMut };
use codegen::{ Generator, PrettyGenerator, DumpGenerator, WriterGenerator, PrettyWriterGenerator };
mod implements;
// These are convenience macros for converting `f64` to the `$unsigned` type.
// The macros check that the numbers are representable the target type.
macro_rules! number_to_unsigned {
($unsigned:ident, $value:expr, $high:ty) => {
if $value > $unsigned::MAX as $high {
None
} else {
Some($value as $unsigned)
}
}
}
macro_rules! number_to_signed {
($signed:ident, $value:expr, $high:ty) => {
if $value < $signed::MIN as $high || $value > $signed::MAX as $high {
None
} else {
Some($value as $signed)
}
}
}
#[derive(Debug, Clone)]
pub enum JsonValue {
Null,
Short(Short),
String(String),
Number(Number),
Boolean(bool),
Object(Object),
Array(Vec<JsonValue>),
}
impl PartialEq for JsonValue {
fn eq(&self, other: &Self) -> bool {
use self::JsonValue::*;
match (self, other) {
(&Null, &Null) => true,
(&Short(ref a), &Short(ref b)) => a == b,
(&String(ref a), &String(ref b)) => a == b,
(&Short(ref a), &String(ref b))
| (&String(ref b), &Short(ref a)) => a.as_str() == b.as_str(),
(&Number(ref a), &Number(ref b)) => a == b,
(&Boolean(ref a), &Boolean(ref b)) => a == b,
(&Object(ref a), &Object(ref b)) => a == b,
(&Array(ref a), &Array(ref b)) => a == b,
_ => false,
}
}
}
impl Eq for JsonValue {}
/// Implements formatting
///
/// ```
/// # use json;
/// let data = json::parse(r#"{"url":"https://github.com/"}"#).unwrap();
/// println!("{}", data);
/// println!("{:#}", data);
/// ```
impl fmt::Display for JsonValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
f.write_str(&self.pretty(4))
} else {
match *self {
JsonValue::Short(ref value) => value.fmt(f),
JsonValue::String(ref value) => value.fmt(f),
JsonValue::Number(ref value) => value.fmt(f),
JsonValue::Boolean(ref value) => value.fmt(f),
JsonValue::Null => f.write_str("null"),
_ => f.write_str(&self.dump())
}
}
}
}
static NULL: JsonValue = JsonValue::Null;
impl JsonValue {
/// Create an empty `JsonValue::Object` instance.
/// When creating an object with data, consider using the `object!` macro.
pub fn new_object() -> JsonValue {
JsonValue::Object(Object::new())
}
/// Create an empty `JsonValue::Array` instance.
/// When creating array with data, consider using the `array!` macro.
pub fn new_array() -> JsonValue {
JsonValue::Array(Vec::new())
}
/// Prints out the value as JSON string.
pub fn dump(&self) -> String {
let mut gen = DumpGenerator::new();
gen.write_json(self).expect("Can't fail");
gen.consume()
}
/// Pretty prints out the value as JSON string. Takes an argument that's
/// number of spaces to indent new blocks with.
pub fn pretty(&self, spaces: u16) -> String {
let mut gen = PrettyGenerator::new(spaces);
gen.write_json(self).expect("Can't fail");
gen.consume()
}
/// Writes the JSON as byte stream into an implementor of `std::io::Write`.
///
/// This method is deprecated as it will panic on io errors, use `write` instead.
#[deprecated(since="0.10.2", note="use `JsonValue::write` instead")]
pub fn to_writer<W: Write>(&self, writer: &mut W) {
let mut gen = WriterGenerator::new(writer);
gen.write_json(self).expect("Deprecated");
}
/// Writes the JSON as byte stream into an implementor of `std::io::Write`.
pub fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
let mut gen = WriterGenerator::new(writer);
gen.write_json(self)
}
/// Writes the JSON as byte stream into an implementor of `std::io::Write`.
pub fn write_pretty<W: Write>(&self, writer: &mut W, spaces: u16) -> io::Result<()> {
let mut gen = PrettyWriterGenerator::new(writer, spaces);
gen.write_json(self)
}
pub fn is_string(&self) -> bool {
match *self {
JsonValue::Short(_) => true,
JsonValue::String(_) => true,
_ => false,
}
}
pub fn is_number(&self) -> bool {
match *self {
JsonValue::Number(_) => true,
_ => false,
}
}
pub fn is_boolean(&self) -> bool {
match *self {
JsonValue::Boolean(_) => true,
_ => false
}
}
pub fn is_null(&self) -> bool {
match *self {
JsonValue::Null => true,
_ => false,
}
}
pub fn is_object(&self) -> bool {
match *self {
JsonValue::Object(_) => true,
_ => false,
}
}
pub fn is_array(&self) -> bool {
match *self {
JsonValue::Array(_) => true,
_ => false,
}
}
/// Checks whether the value is empty. Returns true for:
///
/// - empty string (`""`)
/// - number `0`
/// - boolean `false`
/// - null
/// - empty array (`array![]`)
/// - empty object (`object!{}`)
pub fn is_empty(&self) -> bool {
match *self {
JsonValue::Null => true,
JsonValue::Short(ref value) => value.is_empty(),
JsonValue::String(ref value) => value.is_empty(),
JsonValue::Number(ref value) => value.is_empty(),
JsonValue::Boolean(ref value) => !value,
JsonValue::Array(ref value) => value.is_empty(),
JsonValue::Object(ref value) => value.is_empty(),
}
}
pub fn as_str(&self) -> Option<&str> {
match *self {
JsonValue::Short(ref value) => Some(value),
JsonValue::String(ref value) => Some(value),
_ => None
}
}
pub fn as_number(&self) -> Option<Number> {
match *self {
JsonValue::Number(value) => Some(value),
_ => None
}
}
pub fn as_f64(&self) -> Option<f64> {
self.as_number().map(|value| value.into())
}
pub fn as_f32(&self) -> Option<f32> {
self.as_number().map(|value| value.into())
}
pub fn as_u64(&self) -> Option<u64> {
self.as_number().and_then(|value| {
if value.is_sign_positive() {
Some(value.into())
} else {
None
}
})
}
pub fn as_u32(&self) -> Option<u32> {
self.as_u64().and_then(|value| number_to_unsigned!(u32, value, u64))
}
pub fn as_u16(&self) -> Option<u16> {
self.as_u64().and_then(|value| number_to_unsigned!(u16, value, u64))
}
pub fn as_u8(&self) -> Option<u8> {
self.as_u64().and_then(|value| number_to_unsigned!(u8, value, u64))
}
pub fn as_usize(&self) -> Option<usize> {
self.as_u64().and_then(|value| number_to_unsigned!(usize, value, u64))
}
pub fn as_i64(&self) -> Option<i64> {
self.as_number().map(|value| value.into())
}
pub fn as_i32(&self) -> Option<i32> {
self.as_i64().and_then(|value| number_to_signed!(i32, value, i64))
}
pub fn as_i16(&self) -> Option<i16> {
self.as_i64().and_then(|value| number_to_signed!(i16, value, i64))
}
pub fn as_i8(&self) -> Option<i8> {
self.as_i64().and_then(|value| number_to_signed!(i8, value, i64))
}
pub fn as_isize(&self) -> Option<isize> {
self.as_i64().and_then(|value| number_to_signed!(isize, value, i64))
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
JsonValue::Boolean(ref value) => Some(*value),
_ => None
}
}
/// Obtain an integer at a fixed decimal point. This is useful for
/// converting monetary values and doing arithmetic on them without
/// rounding errors introduced by floating point operations.
///
/// Will return `None` if `Number` called on a value that's not a number,
/// or if the number is negative or a NaN.
///
/// ```
/// # use json::JsonValue;
/// let price_a = JsonValue::from(5.99);
/// let price_b = JsonValue::from(7);
/// let price_c = JsonValue::from(10.2);
///
/// assert_eq!(price_a.as_fixed_point_u64(2), Some(599));
/// assert_eq!(price_b.as_fixed_point_u64(2), Some(700));
/// assert_eq!(price_c.as_fixed_point_u64(2), Some(1020));
/// ```
pub fn as_fixed_point_u64(&self, point: u16) -> Option<u64> {
match *self {
JsonValue::Number(ref value) => value.as_fixed_point_u64(point),
_ => None
}
}
/// Analog to `as_fixed_point_u64`, except returning a signed
/// `i64`, properly handling negative numbers.
///
/// ```
/// # use json::JsonValue;
/// let balance_a = JsonValue::from(-1.49);
/// let balance_b = JsonValue::from(42);
///
/// assert_eq!(balance_a.as_fixed_point_i64(2), Some(-149));
/// assert_eq!(balance_b.as_fixed_point_i64(2), Some(4200));
/// ```
pub fn as_fixed_point_i64(&self, point: u16) -> Option<i64> {
match *self {
JsonValue::Number(ref value) => value.as_fixed_point_i64(point),
_ => None
}
}
/// Take over the ownership of the value, leaving `Null` in it's place.
///
/// ## Example
///
/// ```
/// # #[macro_use] extern crate json;
/// # fn main() {
/// let mut data = array!["Foo", 42];
///
/// let first = data[0].take();
/// let second = data[1].take();
///
/// assert!(first == "Foo");
/// assert!(second == 42);
///
/// assert!(data[0].is_null());
/// assert!(data[1].is_null());
/// # }
/// ```
pub fn take(&mut self) -> JsonValue {
mem::replace(self, JsonValue::Null)
}
/// Checks that self is a string, returns an owned Rust `String`, leaving
/// `Null` in it's place.
///
/// - If the contained string is already a heap allocated `String`, then
/// the ownership is moved without any heap allocation.
///
/// - If the contained string is a `Short`, this will perform a heap
/// allocation to convert the types for you.
///
/// ## Example
///
/// ```
/// # #[macro_use] extern crate json;
/// # fn main() {
/// let mut data = array!["Hello", "World"];
///
/// let owned = data[0].take_string().expect("Should be a string");
///
/// assert_eq!(owned, "Hello");
/// assert!(data[0].is_null());
/// # }
/// ```
pub fn take_string(&mut self) -> Option<String> {
let mut placeholder = JsonValue::Null;
mem::swap(self, &mut placeholder);
match placeholder {
JsonValue::Short(short) => return Some(short.into()),
JsonValue::String(string) => return Some(string),
// Not a string? Swap the original value back in place!
_ => mem::swap(self, &mut placeholder)
}
None
}
/// Works on `JsonValue::Array` - pushes a new value to the array.
pub fn push<T>(&mut self, value: T) -> Result<()>
where T: Into<JsonValue> {
match *self {
JsonValue::Array(ref mut vec) => {
vec.push(value.into());
Ok(())
},
_ => Err(Error::wrong_type("Array"))
}
}
/// Works on `JsonValue::Array` - remove and return last element from
/// an array. On failure returns a null.
pub fn pop(&mut self) -> JsonValue {
match *self {
JsonValue::Array(ref mut vec) => {
vec.pop().unwrap_or(JsonValue::Null)
},
_ => JsonValue::Null
}
}
/// Works on `JsonValue::Array` - checks if the array contains a value
pub fn contains<T>(&self, item: T) -> bool where T: PartialEq<JsonValue> {
match *self {
JsonValue::Array(ref vec) => vec.iter().any(|member| item == *member),
_ => false
}
}
/// Works on `JsonValue::Object` - checks if the object has a key
pub fn has_key(&self, key: &str) -> bool {
match *self {
JsonValue::Object(ref object) => object.get(key).is_some(),
_ => false
}
}
/// Returns length of array or object (number of keys), defaults to `0` for
/// other types.
pub fn len(&self) -> usize {
match *self {
JsonValue::Array(ref vec) => {
vec.len()
},
JsonValue::Object(ref object) => {
object.len()
},
_ => 0
}
}
/// Works on `JsonValue::Array` - returns an iterator over members.
/// Will return an empty iterator if called on non-array types.
pub fn members(&self) -> Members {
match *self {
JsonValue::Array(ref vec) => {
vec.iter()
},
_ => [].iter()
}
}
/// Works on `JsonValue::Array` - returns a mutable iterator over members.
/// Will return an empty iterator if called on non-array types.
pub fn members_mut(&mut self) -> MembersMut {
match *self {
JsonValue::Array(ref mut vec) => {
vec.iter_mut()
},
_ => [].iter_mut()
}
}
/// Works on `JsonValue::Object` - returns an iterator over key value pairs.
/// Will return an empty iterator if called on non-object types.
pub fn entries(&self) -> Entries {
match *self {
JsonValue::Object(ref object) => {
object.iter()
},
_ => Entries::empty()
}
}
/// Works on `JsonValue::Object` - returns a mutable iterator over
/// key value pairs.
/// Will return an empty iterator if called on non-object types.
pub fn entries_mut(&mut self) -> EntriesMut {
match *self {
JsonValue::Object(ref mut object) => {
object.iter_mut()
},
_ => EntriesMut::empty()
}
}
/// Works on `JsonValue::Object` - remove a key and return the value it held.
/// If the key was not present, the method is called on anything but an
/// object, it will return a null.
pub fn remove(&mut self, key: &str) -> JsonValue {
match *self {
JsonValue::Object(ref mut object) => {
object.remove(key).unwrap_or(JsonValue::Null)
},
_ => JsonValue::Null
}
}
/// Works on `JsonValue::Array` - remove an entry and return the value it held.
/// If the method is called on anything but an object or if the index is out of bounds, it
/// will return `JsonValue::Null`.
pub fn array_remove(&mut self, index: usize) -> JsonValue {
match *self {
JsonValue::Array(ref mut vec) => {
if index < vec.len() {
vec.remove(index)
} else {
JsonValue::Null
}
},
_ => JsonValue::Null
}
}
/// When called on an array or an object, will wipe them clean. When called
/// on a string will clear the string. Numbers and booleans become null.
pub fn clear(&mut self) {
match *self {
JsonValue::String(ref mut string) => string.clear(),
JsonValue::Object(ref mut object) => object.clear(),
JsonValue::Array(ref mut vec) => vec.clear(),
_ => *self = JsonValue::Null,
}
}
}
/// Implements indexing by `usize` to easily access array members:
///
/// ## Example
///
/// ```
/// # use json::JsonValue;
/// let mut array = JsonValue::new_array();
///
/// array.push("foo");
///
/// assert!(array[0] == "foo");
/// ```
impl Index<usize> for JsonValue {
type Output = JsonValue;
fn index(&self, index: usize) -> &JsonValue {
match *self {
JsonValue::Array(ref vec) => vec.get(index).unwrap_or(&NULL),
_ => &NULL
}
}
}
/// Implements mutable indexing by `usize` to easily modify array members:
///
/// ## Example
///
/// ```
/// # #[macro_use]
/// # extern crate json;
/// #
/// # fn main() {
/// let mut array = array!["foo", 3.14];
///
/// array[1] = "bar".into();
///
/// assert!(array[1] == "bar");
/// # }
/// ```
impl IndexMut<usize> for JsonValue {
fn index_mut(&mut self, index: usize) -> &mut JsonValue {
match *self {
JsonValue::Array(ref mut vec) => {
let in_bounds = index < vec.len();
if in_bounds {
&mut vec[index]
} else {
vec.push(JsonValue::Null);
vec.last_mut().unwrap()
}
}
_ => {
*self = JsonValue::new_array();
self.push(JsonValue::Null).unwrap();
self.index_mut(index)
}
}
}
}
/// Implements indexing by `&str` to easily access object members:
///
/// ## Example
///
/// ```
/// # #[macro_use]
/// # extern crate json;
/// #
/// # fn main() {
/// let object = object!{
/// "foo" => "bar"
/// };
///
/// assert!(object["foo"] == "bar");
/// # }
/// ```
impl<'a> Index<&'a str> for JsonValue {
type Output = JsonValue;
fn index(&self, index: &str) -> &JsonValue {
match *self {
JsonValue::Object(ref object) => &object[index],
_ => &NULL
}
}
}
impl Index<String> for JsonValue {
type Output = JsonValue;
fn index(&self, index: String) -> &JsonValue {
self.index(index.deref())
}
}
impl<'a> Index<&'a String> for JsonValue {
type Output = JsonValue;
fn index(&self, index: &String) -> &JsonValue {
self.index(index.deref())
}
}
/// Implements mutable indexing by `&str` to easily modify object members:
///
/// ## Example
///
/// ```
/// # #[macro_use]
/// # extern crate json;
/// #
/// # fn main() {
/// let mut object = object!{};
///
/// object["foo"] = 42.into();
///
/// assert!(object["foo"] == 42);
/// # }
/// ```
impl<'a> IndexMut<&'a str> for JsonValue {
fn index_mut(&mut self, index: &str) -> &mut JsonValue {
match *self {
JsonValue::Object(ref mut object) => {
&mut object[index]
},
_ => {
*self = JsonValue::new_object();
self.index_mut(index)
}
}
}
}
impl IndexMut<String> for JsonValue {
fn index_mut(&mut self, index: String) -> &mut JsonValue {
self.index_mut(index.deref())
}
}
impl<'a> IndexMut<&'a String> for JsonValue {
fn index_mut(&mut self, index: &String) -> &mut JsonValue {
self.index_mut(index.deref())
}
}