mod de;
mod ser;
use std::cmp::{Ord, Ordering, PartialOrd};
use std::collections::BTreeMap;
#[doc(inline)]
pub use self::de::from_value;
#[doc(inline)]
pub use self::ser::to_value;
#[derive(Clone, Debug)]
pub enum Value {
Null,
Bool(bool),
Integer(i128),
Float(f64),
Bytes(Vec<u8>),
Text(String),
Array(Vec<Value>),
Map(BTreeMap<Value, Value>),
Tag(u64, Box<Value>),
#[doc(hidden)]
__Hidden,
}
impl PartialEq for Value {
fn eq(&self, other: &Value) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl Eq for Value {}
impl PartialOrd for Value {
fn partial_cmp(&self, other: &Value) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Value {
fn cmp(&self, other: &Value) -> Ordering {
use self::Value::*;
if self.major_type() != other.major_type() {
return self.major_type().cmp(&other.major_type());
}
match (self, other) {
(Integer(a), Integer(b)) => a.abs().cmp(&b.abs()),
(Bytes(a), Bytes(b)) if a.len() != b.len() => a.len().cmp(&b.len()),
(Text(a), Text(b)) if a.len() != b.len() => a.len().cmp(&b.len()),
(Array(a), Array(b)) if a.len() != b.len() => a.len().cmp(&b.len()),
(Map(a), Map(b)) if a.len() != b.len() => a.len().cmp(&b.len()),
(Bytes(a), Bytes(b)) => a.cmp(b),
(Text(a), Text(b)) => a.cmp(b),
(a, b) => {
let a = crate::to_vec(a).expect("self is serializable");
let b = crate::to_vec(b).expect("other is serializable");
a.cmp(&b)
}
}
}
}
macro_rules! impl_from {
($variant:path, $for_type:ty) => {
impl From<$for_type> for Value {
fn from(v: $for_type) -> Value {
$variant(v.into())
}
}
};
}
impl_from!(Value::Bool, bool);
impl_from!(Value::Integer, i8);
impl_from!(Value::Integer, i16);
impl_from!(Value::Integer, i32);
impl_from!(Value::Integer, i64);
impl_from!(Value::Integer, u8);
impl_from!(Value::Integer, u16);
impl_from!(Value::Integer, u32);
impl_from!(Value::Integer, u64);
impl_from!(Value::Float, f32);
impl_from!(Value::Float, f64);
impl_from!(Value::Bytes, Vec<u8>);
impl_from!(Value::Text, String);
impl_from!(Value::Array, Vec<Value>);
impl_from!(Value::Map, BTreeMap<Value, Value>);
impl Value {
fn major_type(&self) -> u8 {
use self::Value::*;
match self {
Null => 7,
Bool(_) => 7,
Integer(v) => {
if *v >= 0 {
0
} else {
1
}
}
Tag(_, _) => 6,
Float(_) => 7,
Bytes(_) => 2,
Text(_) => 3,
Array(_) => 4,
Map(_) => 5,
__Hidden => unreachable!(),
}
}
}