use std::io;
use std::str;
use std::str::FromStr;
use std::iter::FromIterator;
use std::convert::{ TryFrom, TryInto };
use std::borrow::Cow;
use std::collections::{ BTreeSet, BTreeMap, HashSet, HashMap };
use std::fmt::{ Display, Formatter, Result as FmtResult };
use ordered_float::{ NotNan, OrderedFloat };
use serde::{
ser::{ Serialize, Serializer },
de::{
Deserialize, Deserializer, Visitor,
SeqAccess, MapAccess,
Unexpected, Error as DeError,
},
};
#[cfg(feature = "serde_json")]
use serde_json::{
Number as JsonNumber,
Value as JsonValue,
Map as JsonMap,
};
#[cfg(feature = "chrono")]
use chrono::prelude::*;
#[cfg(feature = "uuid")]
use uuid::Uuid;
#[cfg(feature = "quickcheck")]
use quickcheck::{ Arbitrary, Gen };
use crate::error::{ Error, ResultExt };
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Value {
Null,
Opt(Box<Value>),
Bool(bool),
Int(i64),
Uint(u64),
Float(NotNan<f64>),
String(String),
Blob(Vec<u8>),
Array(Vec<Value>),
Map(BTreeMap<Value, Value>),
}
impl Value {
#[must_use]
pub const fn value_type(&self) -> ValueType {
match *self {
Value::Null => ValueType::Null,
Value::Opt(_) => ValueType::Opt,
Value::Bool(_) => ValueType::Bool,
Value::Int(_) => ValueType::Int,
Value::Uint(_) => ValueType::Uint,
Value::Float(_) => ValueType::Float,
Value::String(_) => ValueType::String,
Value::Blob(_) => ValueType::Blob,
Value::Array(_) => ValueType::Array,
Value::Map(_) => ValueType::Map,
}
}
#[must_use]
pub const fn is_null(&self) -> bool {
matches!(*self, Value::Null)
}
#[must_use]
pub const fn is_opt(&self) -> bool {
matches!(*self, Value::Opt(_))
}
#[must_use]
pub const fn is_null_or_opt(&self) -> bool {
self.is_null() || self.is_opt()
}
#[must_use]
pub const fn is_bool(&self) -> bool {
matches!(*self, Value::Bool(_))
}
#[must_use]
pub const fn is_int(&self) -> bool {
matches!(*self, Value::Int(_))
}
#[must_use]
pub const fn is_uint(&self) -> bool {
matches!(*self, Value::Uint(_))
}
#[must_use]
pub const fn is_float(&self) -> bool {
matches!(*self, Value::Float(_))
}
#[must_use]
pub const fn is_number(&self) -> bool {
self.is_int() || self.is_uint() || self.is_float()
}
#[must_use]
pub const fn is_string(&self) -> bool {
matches!(*self, Value::String(_))
}
#[must_use]
pub const fn is_blob(&self) -> bool {
matches!(*self, Value::Blob(_))
}
#[must_use]
pub const fn is_array(&self) -> bool {
matches!(*self, Value::Array(_))
}
#[must_use]
pub const fn is_map(&self) -> bool {
matches!(*self, Value::Map(_))
}
fn type_error<T>(&self, expected: ValueType) -> Result<T, Error> {
Err(Error::new(
format!("expected: {}, actual: {}", expected, self.value_type())
))
}
pub fn as_null(&self) -> Result<(), Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Null => Ok(()),
_ => self.type_error(ValueType::Null),
}
}
pub fn as_opt(&self) -> Result<Option<&Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Null => Ok(None),
Value::Opt(ref inner) => Ok(Some(inner)),
_ => self.type_error(ValueType::Opt),
}
}
pub fn into_opt(self) -> Result<Option<Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match self {
Value::Null => Ok(None),
Value::Opt(inner) => Ok(Some(*inner)),
_ => self.type_error(ValueType::Opt),
}
}
pub fn as_bool(&self) -> Result<bool, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Bool(b) => Ok(b),
_ => self.type_error(ValueType::Bool),
}
}
pub fn as_int(&self) -> Result<i64, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Int(i) => Ok(i),
_ => self.type_error(ValueType::Int),
}
}
pub fn as_uint(&self) -> Result<u64, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Uint(u) => Ok(u),
_ => self.type_error(ValueType::Uint),
}
}
pub fn as_float(&self) -> Result<f64, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Float(f) => Ok(f.into_inner()),
_ => self.type_error(ValueType::Float),
}
}
pub fn as_str(&self) -> Result<&str, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::String(ref s) => Ok(s),
_ => self.type_error(ValueType::String),
}
}
pub fn as_mut_string(&mut self) -> Result<&mut String, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::String(ref mut s) => Ok(s),
_ => self.type_error(ValueType::String),
}
}
pub fn into_string(self) -> Result<String, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match self {
Value::String(s) => Ok(s),
_ => self.type_error(ValueType::String),
}
}
pub fn as_blob(&self) -> Result<&[u8], Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Blob(ref bytes) => Ok(bytes),
_ => self.type_error(ValueType::Blob),
}
}
pub fn as_mut_blob(&mut self) -> Result<&mut Vec<u8>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Blob(ref mut bytes) => Ok(bytes),
_ => self.type_error(ValueType::Blob),
}
}
pub fn into_blob(self) -> Result<Vec<u8>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match self {
Value::Blob(bytes) => Ok(bytes),
_ => self.type_error(ValueType::Blob),
}
}
pub fn as_array(&self) -> Result<&[Value], Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Array(ref array) => Ok(array),
_ => self.type_error(ValueType::Array),
}
}
pub fn as_mut_array(&mut self) -> Result<&mut Vec<Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Array(ref mut array) => Ok(array),
_ => self.type_error(ValueType::Array),
}
}
pub fn into_array(self) -> Result<Vec<Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match self {
Value::Array(array) => Ok(array),
_ => self.type_error(ValueType::Array),
}
}
pub fn as_map(&self) -> Result<&BTreeMap<Value, Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Map(ref map) => Ok(map),
_ => self.type_error(ValueType::Map),
}
}
pub fn as_mut_map(&mut self) -> Result<&mut BTreeMap<Value, Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match *self {
Value::Map(ref mut map) => Ok(map),
_ => self.type_error(ValueType::Map),
}
}
pub fn into_map(self) -> Result<BTreeMap<Value, Value>, Error> {
#[allow(clippy::wildcard_enum_match_arm)]
match self {
Value::Map(map) => Ok(map),
_ => self.type_error(ValueType::Map),
}
}
}
impl Default for Value {
fn default() -> Self {
Value::Null
}
}
impl From<()> for Value {
fn from(_: ()) -> Self {
Value::Null
}
}
impl<T> From<Option<T>> for Value
where
T: Into<Value>,
{
fn from(value: Option<T>) -> Self {
value.map_or(Value::Null, |v| Value::Opt(v.into().into()))
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Value::Bool(value)
}
}
impl From<i8> for Value {
fn from(value: i8) -> Self {
Value::Int(value.into())
}
}
impl From<i16> for Value {
fn from(value: i16) -> Self {
Value::Int(value.into())
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Value::Int(value.into())
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Value::Int(value)
}
}
impl TryFrom<i128> for Value {
type Error = Error;
fn try_from(value: i128) -> Result<Self, Self::Error> {
i64::try_from(value).map(Value::Int).conv_err()
}
}
impl TryFrom<isize> for Value {
type Error = Error;
fn try_from(value: isize) -> Result<Self, Self::Error> {
i64::try_from(value).map(Value::Int).conv_err()
}
}
impl From<u8> for Value {
fn from(value: u8) -> Self {
Value::Uint(value.into())
}
}
impl From<u16> for Value {
fn from(value: u16) -> Self {
Value::Uint(value.into())
}
}
impl From<u32> for Value {
fn from(value: u32) -> Self {
Value::Uint(value.into())
}
}
impl From<u64> for Value {
fn from(value: u64) -> Self {
Value::Uint(value)
}
}
impl TryFrom<u128> for Value {
type Error = Error;
fn try_from(value: u128) -> Result<Self, Self::Error> {
u64::try_from(value).map(Value::Uint).conv_err()
}
}
impl TryFrom<usize> for Value {
type Error = Error;
fn try_from(value: usize) -> Result<Self, Self::Error> {
u64::try_from(value).map(Value::Uint).conv_err()
}
}
impl From<f32> for Value {
fn from(value: f32) -> Self {
Value::from(f64::from(value))
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
NotNan::try_from(value).map_or(Value::Null, Value::Float)
}
}
impl From<OrderedFloat<f32>> for Value {
fn from(value: OrderedFloat<f32>) -> Self {
Value::from(value.into_inner())
}
}
impl From<OrderedFloat<f64>> for Value {
fn from(value: OrderedFloat<f64>) -> Self {
Value::from(value.into_inner())
}
}
impl From<NotNan<f32>> for Value {
fn from(value: NotNan<f32>) -> Self {
Value::Float(value.into())
}
}
impl From<NotNan<f64>> for Value {
fn from(value: NotNan<f64>) -> Self {
Value::Float(value)
}
}
#[cfg(feature = "serde_json")]
impl From<JsonNumber> for Value {
fn from(value: JsonNumber) -> Self {
if let Some(u) = value.as_u64() {
u.into()
} else if let Some(i) = value.as_i64() {
i.into()
} else if let Some(f) = value.as_f64() {
f.into()
} else {
unreachable!("number `{}` is neither u64, i64, nor f64", value)
}
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Value::String(value.into())
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Value::String(value)
}
}
impl From<Cow<'_, str>> for Value {
fn from(value: Cow<'_, str>) -> Self {
Value::String(value.into_owned())
}
}
impl From<Box<str>> for Value {
fn from(value: Box<str>) -> Self {
Value::String(value.into())
}
}
impl From<char> for Value {
fn from(value: char) -> Self {
Value::String(value.to_string())
}
}
#[cfg(feature = "chrono")]
impl<Tz: TimeZone> From<DateTime<Tz>> for Value {
fn from(value: DateTime<Tz>) -> Self {
Value::String(format!("{:?}", value))
}
}
#[cfg(feature = "uuid")]
impl From<Uuid> for Value {
fn from(value: Uuid) -> Self {
Value::String(value.to_string())
}
}
impl<T> From<Vec<T>> for Value
where
T: Into<Value>,
{
fn from(value: Vec<T>) -> Self {
value.into_iter().collect()
}
}
impl<T> From<&[T]> for Value
where
T: ToOwned,
T::Owned: Into<Value>,
{
fn from(value: &[T]) -> Self {
value.iter().map(ToOwned::to_owned).collect()
}
}
impl<T> From<Box<[T]>> for Value
where
T: Into<Value>,
{
fn from(value: Box<[T]>) -> Self {
value.into_vec().into()
}
}
impl<T> From<Cow<'_, [T]>> for Value
where
[T]: ToOwned<Owned = Vec<T>>,
T: Into<Value>,
{
fn from(value: Cow<[T]>) -> Self {
value.into_owned().into()
}
}
impl<T> From<BTreeSet<T>> for Value
where
T: Into<Value>,
{
fn from(value: BTreeSet<T>) -> Self {
value.into_iter().collect()
}
}
impl<T, S> From<HashSet<T, S>> for Value
where
T: Into<Value>,
{
fn from(value: HashSet<T, S>) -> Self {
value.into_iter().collect()
}
}
impl<K, V> From<BTreeMap<K, V>> for Value
where
K: Into<Value>,
V: Into<Value>,
{
fn from(value: BTreeMap<K, V>) -> Self {
value.into_iter().collect()
}
}
impl<K, V, S> From<HashMap<K, V, S>> for Value
where
K: Into<Value>,
V: Into<Value>,
{
fn from(value: HashMap<K, V, S>) -> Self {
value.into_iter().collect()
}
}
#[cfg(feature = "serde_json")]
impl From<JsonMap<String, JsonValue>> for Value {
fn from(value: JsonMap<String, JsonValue>) -> Self {
value.into_iter().collect()
}
}
#[cfg(feature = "serde_json")]
impl From<JsonValue> for Value {
fn from(value: JsonValue) -> Self {
match value {
JsonValue::Null => Value::Null,
JsonValue::Bool(b) => b.into(),
JsonValue::Number(n) => n.into(),
JsonValue::String(s) => s.into(),
JsonValue::Array(array) => array.into(),
JsonValue::Object(map) => map.into(),
}
}
}
#[cfg(feature = "serde_json")]
impl TryFrom<Value> for JsonValue {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match value {
Value::Null => Ok(JsonValue::Null),
Value::Opt(inner) => JsonValue::try_from(*inner),
Value::Bool(b) => Ok(JsonValue::Bool(b)),
Value::Int(i) => Ok(JsonValue::from(i)),
Value::Uint(u) => Ok(JsonValue::from(u)),
Value::Float(f) => {
JsonNumber::from_f64(f.into()).map_or_else(
|| Err(Error::new("infinite floating-point number")),
|n| Ok(JsonValue::Number(n)),
)
},
Value::String(s) => Ok(JsonValue::String(s)),
Value::Blob(bytes) => Ok(JsonValue::from(bytes)),
Value::Array(items) => {
items
.into_iter()
.map(TryFrom::try_from)
.collect::<Result<_, _>>()
.map(JsonValue::Array)
},
Value::Map(entries) => {
entries
.into_iter()
.map(|(k, v)| if let Value::String(key) = k {
let value = JsonValue::try_from(v)?;
Ok((key, value))
} else {
Err(Error::new("non-string key in map"))
})
.collect::<Result<_, _>>()
.map(JsonValue::Object)
},
}
}
}
impl<T> FromIterator<T> for Value
where
T: Into<Value>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
Value::Array(iter.into_iter().map(Into::into).collect())
}
}
impl<K, V> FromIterator<(K, V)> for Value
where
K: Into<Value>,
V: Into<Value>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
{
let map = iter
.into_iter()
.map(|(key, val)| (key.into(), val.into()))
.collect();
Value::Map(map)
}
}
impl FromStr for Value {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
crate::from_str(s)
}
}
impl Display for Value {
fn fmt(&self, formatter: &mut Formatter) -> FmtResult {
struct TextIo<'a, 'b>(&'a mut Formatter<'b>);
impl<'a, 'b> io::Write for TextIo<'a, 'b> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let s = str::from_utf8(buf).map_err(
|e| io::Error::new(io::ErrorKind::Other, e)
)?;
self.0.write_str(s).map_err(
|e| io::Error::new(io::ErrorKind::Other, e)
)?;
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
let padding = if formatter.alternate() {
None
} else {
Some(" ")
};
crate::ser::text::to_writer(
&mut TextIo(formatter),
self,
padding,
).map_err(
|_error| std::fmt::Error )
}
}
impl Serialize for Value {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
match *self {
Value::Null => ser.serialize_none(),
Value::Opt(ref inner) => ser.serialize_some(inner),
Value::Bool(b) => ser.serialize_bool(b),
Value::Int(i) => ser.serialize_i64(i),
Value::Uint(u) => ser.serialize_u64(u),
Value::Float(f) => ser.serialize_f64(f.into_inner()),
Value::String(ref string) => ser.serialize_str(string),
Value::Blob(ref bytes) => ser.serialize_bytes(bytes),
Value::Array(ref values) => ser.collect_seq(values),
Value::Map(ref items) => ser.collect_map(items),
}
}
}
impl<'a> Deserialize<'a> for Value {
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
de.deserialize_any(ValueVisitor)
}
}
#[derive(Debug, Clone, Copy)]
struct ValueVisitor;
impl<'a> Visitor<'a> for ValueVisitor {
type Value = Value;
fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
formatter.pad("a Neodyn Exchange value")
}
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
Ok(v.into())
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E> {
Ok(v.into())
}
fn visit_i128<E: DeError>(self, v: i128) -> Result<Self::Value, E> {
v.try_into().map_err(|_error| { E::invalid_value(
Unexpected::Other(&format!("i128 `{}`", v)),
&"signed integer fitting into i64",
)
})
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E> {
Ok(v.into())
}
fn visit_u128<E: DeError>(self, v: u128) -> Result<Self::Value, E> {
v.try_into().map_err(|_error| { E::invalid_value(
Unexpected::Other(&format!("u128 `{}`", v)),
&"unsigned integer fitting into u64",
)
})
}
fn visit_f64<E>(self, v: f64) -> Result<Self::Value, E> {
Ok(v.into())
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> {
Ok(v.into())
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E> {
Ok(v.into())
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> {
Ok(Value::Blob(v.to_vec()))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> {
Ok(Value::Blob(v))
}
fn visit_none<E>(self) -> Result<Self::Value, E> {
Ok(Value::Null)
}
fn visit_some<D: Deserializer<'a>>(self, de: D) -> Result<Self::Value, D::Error> {
Deserialize::deserialize(de).map(|v| Value::Opt(Box::new(v)))
}
fn visit_unit<E>(self) -> Result<Self::Value, E> {
Ok(Value::Null)
}
fn visit_newtype_struct<D: Deserializer<'a>>(self, de: D) -> Result<Self::Value, D::Error> {
Deserialize::deserialize(de)
}
fn visit_seq<A: SeqAccess<'a>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let len = seq.size_hint().unwrap_or(0);
let mut values = Vec::with_capacity(len);
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok(Value::Array(values))
}
fn visit_map<A: MapAccess<'a>>(self, mut map: A) -> Result<Self::Value, A::Error> {
let mut values = BTreeMap::new();
while let Some((key, value)) = map.next_entry()? {
values.insert(key, value);
}
Ok(Value::Map(values))
}
}
#[cfg(feature = "quickcheck")]
impl Arbitrary for Value {
fn arbitrary(g: &mut Gen) -> Self {
#[allow(clippy::cast_possible_truncation)]
let max = (0..32)
.find(|&n: &u32| (g.size() as u32) << n <= n.pow(n))
.unwrap_or(32);
random_value_tree(g, max, max)
}
fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
fn shrink_map_value<A>(arb: &A) -> Box<dyn Iterator<Item = Value>>
where
A: Arbitrary + Into<Value>,
{
Box::new(arb.shrink().map(Into::into))
}
match *self {
Value::Null => quickcheck::empty_shrinker(),
Value::Opt(ref inner) => {
let copy = (**inner).clone();
Box::new(inner
.shrink()
.map(Value::Opt)
.chain(vec![copy, Value::Null]))
},
Value::Bool(b) => shrink_map_value(&b),
Value::Int(i) => shrink_map_value(&i),
Value::Uint(u) => shrink_map_value(&u),
Value::Float(f) => {
Box::new(f.into_inner().shrink().map(f64::into))
},
Value::String(ref s) => shrink_map_value(s),
Value::Blob(ref bytes) => {
Box::new(bytes.shrink().map(Value::Blob))
},
Value::Array(ref array) => shrink_map_value(array),
Value::Map(ref map) => shrink_map_value(map),
}
}
}
#[cfg(feature = "quickcheck")]
fn random_value_tree(g: &mut Gen, max_depth: u32, max_branch: u32) -> Value {
fn not_nan_float(g: &mut Gen) -> NotNan<f64> {
loop {
let x = f64::arbitrary(g);
if let Ok(value) = NotNan::try_from(x) {
break value;
}
}
}
fn random_scalar_value(g: &mut Gen) -> Value {
match u8::arbitrary(g) {
0 ..= 4 => Value::Null,
5 ..= 15 => Value::Bool(bool::arbitrary(g)),
16 ..= 63 => Value::Int(i64::arbitrary(g)),
64 ..=111 => Value::Uint(u64::arbitrary(g)),
112..=159 => Value::Float(not_nan_float(g)),
160..=207 => Value::String(String::arbitrary(g)),
208..=255 => Value::Blob(Vec::arbitrary(g)),
}
}
if max_depth == 0 || max_branch == 0 {
return random_scalar_value(g);
}
let num_children = u32::arbitrary(g) % max_branch;
if num_children == 0 && bool::arbitrary(g) {
return random_scalar_value(g);
}
if num_children == 1 && bool::arbitrary(g) {
let child = random_value_tree(g, max_depth - 1, max_branch);
return Value::Opt(Box::new(child));
}
if bool::arbitrary(g) {
(0..num_children)
.map(|_| random_value_tree(g, max_depth - 1, max_branch))
.collect()
} else {
(0..num_children)
.map(|_| {
let key = random_value_tree(g, max_depth - 1, max_branch);
let val = random_value_tree(g, max_depth - 1, max_branch);
(key, val)
})
.collect()
}
}
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ValueType {
Null,
Opt,
Bool,
Int,
Uint,
Float,
String,
Blob,
Array,
Map,
}
impl ValueType {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
ValueType::Null => "null",
ValueType::Opt => "opt",
ValueType::Bool => "bool",
ValueType::Int => "int",
ValueType::Uint => "uint",
ValueType::Float => "float",
ValueType::String => "string",
ValueType::Blob => "blob",
ValueType::Array => "array",
ValueType::Map => "map",
}
}
}
impl Display for ValueType {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
f.pad(self.as_str())
}
}
impl FromStr for ValueType {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"null" => ValueType::Null,
"opt" => ValueType::Opt,
"bool" => ValueType::Bool,
"int" => ValueType::Int,
"uint" => ValueType::Uint,
"float" => ValueType::Float,
"string" => ValueType::String,
"blob" => ValueType::Blob,
"array" => ValueType::Array,
"map" => ValueType::Map,
_ => return Err(Error::custom(
format_args!("invalid value type `{}`", s),
)),
})
}
}
impl Serialize for ValueType {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(self.as_str())
}
}
impl<'a> Deserialize<'a> for ValueType {
fn deserialize<D: Deserializer<'a>>(de: D) -> Result<Self, D::Error> {
de.deserialize_str(ValueTypeVisitor)
}
}
#[derive(Debug, Clone, Copy)]
struct ValueTypeVisitor;
impl<'a> Visitor<'a> for ValueTypeVisitor {
type Value = ValueType;
fn expecting(&self, f: &mut Formatter) -> FmtResult {
f.pad("a type string for a Neodyn Exchange value")
}
fn visit_str<E: DeError>(self, v: &str) -> Result<Self::Value, E> {
ValueType::from_str(v).map_err(E::custom)
}
}
impl<'a> From<&'a Value> for Unexpected<'a> {
fn from(value: &'a Value) -> Self {
match *value {
Value::Null => Unexpected::Unit,
Value::Opt(_) => Unexpected::Option,
Value::Bool(b) => Unexpected::Bool(b),
Value::Int(i) => Unexpected::Signed(i),
Value::Uint(u) => Unexpected::Unsigned(u),
Value::Float(f) => Unexpected::Float(f.into()),
Value::String(ref s) => Unexpected::Str(s),
Value::Blob(ref bytes) => Unexpected::Bytes(bytes),
Value::Array(_) => Unexpected::Seq,
Value::Map(_) => Unexpected::Map,
}
}
}