mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-10-09 06:45:08 +02:00
384 lines
12 KiB
Rust
384 lines
12 KiB
Rust
#![doc(html_root_url="https://docs.rs/serde-value/0.7.0/")]
|
|
|
|
use std::collections::BTreeMap;
|
|
use std::cmp::Ordering;
|
|
use std::hash::{Hash, Hasher};
|
|
use serde::Deserialize;
|
|
use ordered_float::OrderedFloat;
|
|
|
|
pub use de::*;
|
|
pub use ser::*;
|
|
|
|
mod de;
|
|
mod ser;
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum Value {
|
|
Bool(bool),
|
|
|
|
U8(u8),
|
|
U16(u16),
|
|
U32(u32),
|
|
U64(u64),
|
|
|
|
I8(i8),
|
|
I16(i16),
|
|
I32(i32),
|
|
I64(i64),
|
|
|
|
F32(f32),
|
|
F64(f64),
|
|
|
|
Char(char),
|
|
String(String),
|
|
|
|
Unit,
|
|
Option(Option<Box<Value>>),
|
|
Newtype(Box<Value>),
|
|
Seq(Vec<Value>),
|
|
Map(BTreeMap<Value, Value>),
|
|
Bytes(Vec<u8>),
|
|
}
|
|
|
|
impl Hash for Value {
|
|
fn hash<H>(&self, hasher: &mut H)
|
|
where
|
|
H: Hasher
|
|
{
|
|
self.discriminant().hash(hasher);
|
|
match *self {
|
|
Value::Bool(v) => v.hash(hasher),
|
|
Value::U8(v) => v.hash(hasher),
|
|
Value::U16(v) => v.hash(hasher),
|
|
Value::U32(v) => v.hash(hasher),
|
|
Value::U64(v) => v.hash(hasher),
|
|
Value::I8(v) => v.hash(hasher),
|
|
Value::I16(v) => v.hash(hasher),
|
|
Value::I32(v) => v.hash(hasher),
|
|
Value::I64(v) => v.hash(hasher),
|
|
Value::F32(v) => OrderedFloat(v).hash(hasher),
|
|
Value::F64(v) => OrderedFloat(v).hash(hasher),
|
|
Value::Char(v) => v.hash(hasher),
|
|
Value::String(ref v) => v.hash(hasher),
|
|
Value::Unit => ().hash(hasher),
|
|
Value::Option(ref v) => v.hash(hasher),
|
|
Value::Newtype(ref v) => v.hash(hasher),
|
|
Value::Seq(ref v) => v.hash(hasher),
|
|
Value::Map(ref v) => v.hash(hasher),
|
|
Value::Bytes(ref v) => v.hash(hasher),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PartialEq for Value {
|
|
fn eq(&self, rhs: &Self) -> bool {
|
|
match (self, rhs) {
|
|
(&Value::Bool(v0), &Value::Bool(v1)) if v0 == v1 => true,
|
|
(&Value::U8(v0), &Value::U8(v1)) if v0 == v1 => true,
|
|
(&Value::U16(v0), &Value::U16(v1)) if v0 == v1 => true,
|
|
(&Value::U32(v0), &Value::U32(v1)) if v0 == v1 => true,
|
|
(&Value::U64(v0), &Value::U64(v1)) if v0 == v1 => true,
|
|
(&Value::I8(v0), &Value::I8(v1)) if v0 == v1 => true,
|
|
(&Value::I16(v0), &Value::I16(v1)) if v0 == v1 => true,
|
|
(&Value::I32(v0), &Value::I32(v1)) if v0 == v1 => true,
|
|
(&Value::I64(v0), &Value::I64(v1)) if v0 == v1 => true,
|
|
(&Value::F32(v0), &Value::F32(v1)) if OrderedFloat(v0) == OrderedFloat(v1) => true,
|
|
(&Value::F64(v0), &Value::F64(v1)) if OrderedFloat(v0) == OrderedFloat(v1) => true,
|
|
(&Value::Char(v0), &Value::Char(v1)) if v0 == v1 => true,
|
|
(&Value::String(ref v0), &Value::String(ref v1)) if v0 == v1 => true,
|
|
(&Value::Unit, &Value::Unit) => true,
|
|
(&Value::Option(ref v0), &Value::Option(ref v1)) if v0 == v1 => true,
|
|
(&Value::Newtype(ref v0), &Value::Newtype(ref v1)) if v0 == v1 => true,
|
|
(&Value::Seq(ref v0), &Value::Seq(ref v1)) if v0 == v1 => true,
|
|
(&Value::Map(ref v0), &Value::Map(ref v1)) if v0 == v1 => true,
|
|
(&Value::Bytes(ref v0), &Value::Bytes(ref v1)) if v0 == v1 => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ord for Value {
|
|
fn cmp(&self, rhs: &Self) -> Ordering {
|
|
match (self, rhs) {
|
|
(&Value::Bool(v0), &Value::Bool(ref v1)) => v0.cmp(v1),
|
|
(&Value::U8(v0), &Value::U8(ref v1)) => v0.cmp(v1),
|
|
(&Value::U16(v0), &Value::U16(ref v1)) => v0.cmp(v1),
|
|
(&Value::U32(v0), &Value::U32(ref v1)) => v0.cmp(v1),
|
|
(&Value::U64(v0), &Value::U64(ref v1)) => v0.cmp(v1),
|
|
(&Value::I8(v0), &Value::I8(ref v1)) => v0.cmp(v1),
|
|
(&Value::I16(v0), &Value::I16(ref v1)) => v0.cmp(v1),
|
|
(&Value::I32(v0), &Value::I32(ref v1)) => v0.cmp(v1),
|
|
(&Value::I64(v0), &Value::I64(ref v1)) => v0.cmp(v1),
|
|
(&Value::F32(v0), &Value::F32(v1)) => OrderedFloat(v0).cmp(&OrderedFloat(v1)),
|
|
(&Value::F64(v0), &Value::F64(v1)) => OrderedFloat(v0).cmp(&OrderedFloat(v1)),
|
|
(&Value::Char(v0), &Value::Char(ref v1)) => v0.cmp(v1),
|
|
(&Value::String(ref v0), &Value::String(ref v1)) => v0.cmp(v1),
|
|
(&Value::Unit, &Value::Unit) => Ordering::Equal,
|
|
(&Value::Option(ref v0), &Value::Option(ref v1)) => v0.cmp(v1),
|
|
(&Value::Newtype(ref v0), &Value::Newtype(ref v1)) => v0.cmp(v1),
|
|
(&Value::Seq(ref v0), &Value::Seq(ref v1)) => v0.cmp(v1),
|
|
(&Value::Map(ref v0), &Value::Map(ref v1)) => v0.cmp(v1),
|
|
(&Value::Bytes(ref v0), &Value::Bytes(ref v1)) => v0.cmp(v1),
|
|
(ref v0, ref v1) => v0.discriminant().cmp(&v1.discriminant()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Value {
|
|
fn discriminant(&self) -> usize {
|
|
match *self {
|
|
Value::Bool(..) => 0,
|
|
Value::U8(..) => 1,
|
|
Value::U16(..) => 2,
|
|
Value::U32(..) => 3,
|
|
Value::U64(..) => 4,
|
|
Value::I8(..) => 5,
|
|
Value::I16(..) => 6,
|
|
Value::I32(..) => 7,
|
|
Value::I64(..) => 8,
|
|
Value::F32(..) => 9,
|
|
Value::F64(..) => 10,
|
|
Value::Char(..) => 11,
|
|
Value::String(..) => 12,
|
|
Value::Unit => 13,
|
|
Value::Option(..) => 14,
|
|
Value::Newtype(..) => 15,
|
|
Value::Seq(..) => 16,
|
|
Value::Map(..) => 17,
|
|
Value::Bytes(..) => 18,
|
|
}
|
|
}
|
|
|
|
fn unexpected(&self) -> serde::de::Unexpected {
|
|
match *self {
|
|
Value::Bool(b) => serde::de::Unexpected::Bool(b),
|
|
Value::U8(n) => serde::de::Unexpected::Unsigned(n as u64),
|
|
Value::U16(n) => serde::de::Unexpected::Unsigned(n as u64),
|
|
Value::U32(n) => serde::de::Unexpected::Unsigned(n as u64),
|
|
Value::U64(n) => serde::de::Unexpected::Unsigned(n),
|
|
Value::I8(n) => serde::de::Unexpected::Signed(n as i64),
|
|
Value::I16(n) => serde::de::Unexpected::Signed(n as i64),
|
|
Value::I32(n) => serde::de::Unexpected::Signed(n as i64),
|
|
Value::I64(n) => serde::de::Unexpected::Signed(n),
|
|
Value::F32(n) => serde::de::Unexpected::Float(n as f64),
|
|
Value::F64(n) => serde::de::Unexpected::Float(n),
|
|
Value::Char(c) => serde::de::Unexpected::Char(c),
|
|
Value::String(ref s) => serde::de::Unexpected::Str(s),
|
|
Value::Unit => serde::de::Unexpected::Unit,
|
|
Value::Option(_) => serde::de::Unexpected::Option,
|
|
Value::Newtype(_) => serde::de::Unexpected::NewtypeStruct,
|
|
Value::Seq(_) => serde::de::Unexpected::Seq,
|
|
Value::Map(_) => serde::de::Unexpected::Map,
|
|
Value::Bytes(ref b) => serde::de::Unexpected::Bytes(b),
|
|
}
|
|
}
|
|
|
|
pub fn deserialize_into<'de, T: Deserialize<'de>>(self) -> Result<T, DeserializerError> {
|
|
T::deserialize(self)
|
|
}
|
|
}
|
|
|
|
impl Eq for Value { }
|
|
impl PartialOrd for Value {
|
|
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
|
|
Some(self.cmp(rhs))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
use serde_derive::{Deserialize, Serialize};
|
|
|
|
#[test]
|
|
fn de_smoke_test() {
|
|
// some convoluted Value
|
|
let value = Value::Option(Some(Box::new(Value::Seq(vec![
|
|
Value::U16(8),
|
|
Value::Char('a'),
|
|
Value::F32(1.0),
|
|
Value::String("hello".into()),
|
|
Value::Map(vec![
|
|
(Value::Bool(false), Value::Unit),
|
|
(Value::Bool(true), Value::Newtype(Box::new(
|
|
Value::Bytes(b"hi".as_ref().into())
|
|
))),
|
|
].into_iter().collect()),
|
|
]))));
|
|
|
|
// assert that the value remains unchanged through deserialization
|
|
let value_de = Value::deserialize(value.clone()).unwrap();
|
|
assert_eq!(value_de, value);
|
|
}
|
|
|
|
#[test]
|
|
fn ser_smoke_test() {
|
|
#[derive(Serialize)]
|
|
struct Foo {
|
|
a: u32,
|
|
b: String,
|
|
c: Vec<bool>,
|
|
}
|
|
|
|
let foo = Foo {
|
|
a: 15,
|
|
b: "hello".into(),
|
|
c: vec![true, false],
|
|
};
|
|
|
|
let expected = Value::Map(vec![
|
|
(Value::String("a".into()), Value::U32(15)),
|
|
(Value::String("b".into()), Value::String("hello".into())),
|
|
(Value::String("c".into()), Value::Seq(vec![Value::Bool(true), Value::Bool(false)])),
|
|
].into_iter().collect());
|
|
|
|
let value = to_value(&foo).unwrap();
|
|
assert_eq!(expected, value);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_into_enum() {
|
|
#[derive(Deserialize, Debug, PartialEq, Eq)]
|
|
enum Foo {
|
|
Bar,
|
|
Baz(u8),
|
|
}
|
|
|
|
let value = Value::String("Bar".into());
|
|
assert_eq!(Foo::deserialize(value).unwrap(), Foo::Bar);
|
|
|
|
let value = Value::Map(vec![
|
|
(Value::String("Baz".into()), Value::U8(1))
|
|
].into_iter().collect());
|
|
assert_eq!(Foo::deserialize(value).unwrap(), Foo::Baz(1));
|
|
}
|
|
|
|
#[test]
|
|
fn serialize_from_enum() {
|
|
#[derive(Serialize)]
|
|
enum Foo {
|
|
Bar,
|
|
Baz(u8),
|
|
Qux { quux: u8 },
|
|
Corge(u8, u8),
|
|
}
|
|
|
|
let bar = Foo::Bar;
|
|
assert_eq!(to_value(&bar).unwrap(), Value::String("Bar".into()));
|
|
|
|
let baz = Foo::Baz(1);
|
|
assert_eq!(
|
|
to_value(&baz).unwrap(),
|
|
Value::Map(
|
|
vec![(Value::String("Baz".into()), Value::U8(1))]
|
|
.into_iter()
|
|
.collect(),
|
|
)
|
|
);
|
|
|
|
let qux = Foo::Qux { quux: 2 };
|
|
assert_eq!(
|
|
to_value(&qux).unwrap(),
|
|
Value::Map(
|
|
vec![(
|
|
Value::String("Qux".into()),
|
|
Value::Map(
|
|
vec![(Value::String("quux".into()), Value::U8(2))]
|
|
.into_iter()
|
|
.collect()
|
|
)
|
|
)]
|
|
.into_iter()
|
|
.collect()
|
|
)
|
|
);
|
|
|
|
let corge = Foo::Corge(3, 4);
|
|
assert_eq!(
|
|
to_value(&corge).unwrap(),
|
|
Value::Map(
|
|
vec![(
|
|
Value::String("Corge".into()),
|
|
Value::Seq(vec![Value::U8(3), Value::U8(4)])
|
|
)]
|
|
.into_iter()
|
|
.collect()
|
|
)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_inside_deserialize_impl() {
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
enum Event {
|
|
Added(u32),
|
|
Error(u8),
|
|
}
|
|
|
|
impl<'de> serde::Deserialize<'de> for Event {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: serde::Deserializer<'de> {
|
|
#[derive(Deserialize)]
|
|
struct RawEvent {
|
|
kind: String,
|
|
object: Value,
|
|
}
|
|
|
|
let raw_event = RawEvent::deserialize(deserializer)?;
|
|
|
|
// Cannot directly use Value as Deserializer, since error type needs to be
|
|
// generic D::Error rather than specific serde_value::DeserializerError
|
|
let object_deserializer = ValueDeserializer::new(raw_event.object);
|
|
|
|
Ok(match &*raw_event.kind {
|
|
"ADDED" => Event::Added(<_>::deserialize(object_deserializer)?),
|
|
"ERROR" => Event::Error(<_>::deserialize(object_deserializer)?),
|
|
kind => return Err(serde::de::Error::unknown_variant(kind, &["ADDED", "ERROR"])),
|
|
})
|
|
}
|
|
}
|
|
|
|
let input = Value::Map(vec![
|
|
(Value::String("kind".to_owned()), Value::String("ADDED".to_owned())),
|
|
(Value::String("object".to_owned()), Value::U32(5)),
|
|
].into_iter().collect());
|
|
let event = Event::deserialize(input).expect("could not deserialize ADDED event");
|
|
assert_eq!(event, Event::Added(5));
|
|
|
|
let input = Value::Map(vec![
|
|
(Value::String("kind".to_owned()), Value::String("ERROR".to_owned())),
|
|
(Value::String("object".to_owned()), Value::U8(5)),
|
|
].into_iter().collect());
|
|
let event = Event::deserialize(input).expect("could not deserialize ERROR event");
|
|
assert_eq!(event, Event::Error(5));
|
|
|
|
let input = Value::Map(vec![
|
|
(Value::String("kind".to_owned()), Value::String("ADDED".to_owned())),
|
|
(Value::String("object".to_owned()), Value::Unit),
|
|
].into_iter().collect());
|
|
let _ = Event::deserialize(input).expect_err("expected deserializing bad ADDED event to fail");
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_newtype() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
struct Foo(i32);
|
|
|
|
let input = Value::I32(5);
|
|
let foo = Foo::deserialize(input).unwrap();
|
|
assert_eq!(foo, Foo(5));
|
|
}
|
|
|
|
#[test]
|
|
fn deserialize_newtype2() {
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
struct Foo(i32);
|
|
|
|
#[derive(Debug, Deserialize, PartialEq)]
|
|
struct Bar {
|
|
foo: Foo,
|
|
}
|
|
|
|
let input = Value::Map(vec![
|
|
(Value::String("foo".to_owned()), Value::I32(5))
|
|
].into_iter().collect());
|
|
let bar = Bar::deserialize(input).unwrap();
|
|
assert_eq!(bar, Bar { foo: Foo(5) });
|
|
}
|