use std::borrow::Cow;
#[cfg(not(feature = "preserve_order"))]
use std::collections::BTreeMap;
use std::fmt;
use std::net::{IpAddr, SocketAddr};
#[cfg(feature = "preserve_order")]
use indexmap::IndexMap;
use serde::de::{self, MapAccess, SeqAccess, Visitor};
use serde::ser::SerializeMap;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::datetime::DateTime;
use crate::tokens::{
strip_ctor, TOKEN_CTOR, TOKEN_DATETIME, TOKEN_INT, TOKEN_IP, TOKEN_IPPORT, TOKEN_UINT,
};
#[cfg(not(feature = "preserve_order"))]
pub type Map = BTreeMap<String, Value>;
#[cfg(feature = "preserve_order")]
pub type Map = IndexMap<String, Value>;
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Null,
Bool(bool),
Number(f64),
String(String),
Array(Vec<Value>),
Object(Map),
Int(i64),
Uint(u64),
Int8(i8),
Int16(i16),
Int32(i32),
Int64(i64),
Uint8(u8),
Uint16(u16),
Uint32(u32),
Uint64(u64),
DateTime(DateTime),
Ip(IpAddr),
IpPort(SocketAddr),
Bytes(Vec<u8>),
Constructor {
name: String,
arg: Box<Value>,
},
}
impl Value {
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(b) => Some(*b),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match self {
Value::Number(n) => Some(*n),
Value::Int(n) | Value::Int64(n) => Some(*n as f64),
Value::Uint(n) | Value::Uint64(n) => Some(*n as f64),
Value::Int8(n) => Some(*n as f64),
Value::Int16(n) => Some(*n as f64),
Value::Int32(n) => Some(*n as f64),
Value::Uint8(n) => Some(*n as f64),
Value::Uint16(n) => Some(*n as f64),
Value::Uint32(n) => Some(*n as f64),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Value::Int(n) | Value::Int64(n) => Some(*n),
Value::Int8(n) => Some(*n as i64),
Value::Int16(n) => Some(*n as i64),
Value::Int32(n) => Some(*n as i64),
Value::Uint8(n) => Some(*n as i64),
Value::Uint16(n) => Some(*n as i64),
Value::Uint32(n) => Some(*n as i64),
Value::Uint(n) | Value::Uint64(n) => i64::try_from(*n).ok(),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[Value]> {
match self {
Value::Array(a) => Some(a),
_ => None,
}
}
pub fn as_object(&self) -> Option<&Map> {
match self {
Value::Object(m) => Some(m),
_ => None,
}
}
pub fn get(&self, key: &str) -> Option<&Value> {
match self {
Value::Object(m) => m.get(key),
_ => None,
}
}
pub fn get_index(&self, index: usize) -> Option<&Value> {
match self {
Value::Array(a) => a.get(index),
_ => None,
}
}
pub fn constructor(name: impl Into<String>, arg: impl Into<Value>) -> Value {
let name = name.into();
debug_assert!(
crate::tokens::is_ident(&name),
"constructor name {name:?} is not a valid JSONX identifier; \
it cannot be serialized to round-trippable JSONX"
);
Value::Constructor {
name,
arg: Box::new(arg.into()),
}
}
pub fn int(n: i64) -> Value {
Value::Int(n)
}
pub fn uint(n: u64) -> Value {
Value::Uint(n)
}
pub fn bytes(b: impl Into<Vec<u8>>) -> Value {
Value::Bytes(b.into())
}
pub fn string(s: impl Into<String>) -> Value {
Value::String(s.into())
}
pub fn to_jsonx_arg(&self) -> Option<String> {
Some(match self {
Value::Int(n) | Value::Int64(n) => n.to_string(),
Value::Uint(n) | Value::Uint64(n) => n.to_string(),
Value::Int8(n) => n.to_string(),
Value::Int16(n) => n.to_string(),
Value::Int32(n) => n.to_string(),
Value::Uint8(n) => n.to_string(),
Value::Uint16(n) => n.to_string(),
Value::Uint32(n) => n.to_string(),
Value::DateTime(dt) => crate::datetime::to_jsonx_string(dt),
Value::Ip(ip) => ip.to_string(),
Value::IpPort(sa) => sa.to_string(),
Value::Bytes(b) => crate::base64::encode(b),
Value::Constructor { arg, .. } => match arg.as_str() {
Some(s) => s.to_owned(),
None => crate::ser::to_string(arg).ok()?,
},
_ => return None,
})
}
}
macro_rules! impl_from {
($($ty:ty => $variant:ident),* $(,)?) => {
$(impl From<$ty> for Value {
fn from(v: $ty) -> Value { Value::$variant(v) }
})*
};
}
impl_from! {
bool => Bool,
f64 => Number,
String => String,
Vec<Value> => Array,
Map => Object,
i8 => Int8,
i16 => Int16,
i32 => Int32,
u8 => Uint8,
u16 => Uint16,
u32 => Uint32,
DateTime => DateTime,
IpAddr => Ip,
SocketAddr => IpPort,
}
impl From<&str> for Value {
fn from(v: &str) -> Value {
Value::String(v.to_owned())
}
}
impl From<i64> for Value {
fn from(v: i64) -> Value {
Value::Int64(v)
}
}
impl From<u64> for Value {
fn from(v: u64) -> Value {
Value::Uint64(v)
}
}
impl<T: Into<Value>> From<Option<T>> for Value {
fn from(v: Option<T>) -> Value {
match v {
Some(v) => v.into(),
None => Value::Null,
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match crate::ser::to_string(self) {
Ok(s) => f.write_str(&s),
Err(_) => f.write_str("null"),
}
}
}
impl Serialize for Value {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Value::Null => serializer.serialize_unit(),
Value::Bool(b) => serializer.serialize_bool(*b),
Value::Number(n) => serializer.serialize_f64(*n),
Value::String(s) => serializer.serialize_str(s),
Value::Array(a) => a.serialize(serializer),
Value::Object(m) => {
let mut map = serializer.serialize_map(Some(m.len()))?;
for (k, v) in m {
map.serialize_entry(k, v)?;
}
map.end()
}
Value::Int(n) => serializer.serialize_newtype_struct(TOKEN_INT, n),
Value::Uint(n) => serializer.serialize_newtype_struct(TOKEN_UINT, n),
Value::Int8(n) => serializer.serialize_i8(*n),
Value::Int16(n) => serializer.serialize_i16(*n),
Value::Int32(n) => serializer.serialize_i32(*n),
Value::Int64(n) => serializer.serialize_i64(*n),
Value::Uint8(n) => serializer.serialize_u8(*n),
Value::Uint16(n) => serializer.serialize_u16(*n),
Value::Uint32(n) => serializer.serialize_u32(*n),
Value::Uint64(n) => serializer.serialize_u64(*n),
Value::DateTime(dt) => serializer
.serialize_newtype_struct(TOKEN_DATETIME, &crate::datetime::to_jsonx_string(dt)),
Value::Ip(ip) => serializer.serialize_newtype_struct(TOKEN_IP, &ip.to_string()),
Value::IpPort(sa) => serializer.serialize_newtype_struct(TOKEN_IPPORT, &sa.to_string()),
Value::Bytes(b) => serializer.serialize_bytes(b),
Value::Constructor { name, arg } => {
serializer.serialize_newtype_struct(TOKEN_CTOR, &GenericCtor { name, arg })
}
}
}
}
struct GenericCtor<'a> {
name: &'a str,
arg: &'a Value,
}
impl Serialize for GenericCtor<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(Some(1))?;
map.serialize_entry(self.name, self.arg)?;
map.end()
}
}
impl<'de> Deserialize<'de> for Value {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Value, D::Error> {
deserializer.deserialize_any(ValueVisitor)
}
}
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Value;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("any valid JSONX value")
}
fn visit_bool<E>(self, v: bool) -> Result<Value, E> {
Ok(Value::Bool(v))
}
fn visit_i8<E>(self, v: i8) -> Result<Value, E> {
Ok(Value::Int8(v))
}
fn visit_i16<E>(self, v: i16) -> Result<Value, E> {
Ok(Value::Int16(v))
}
fn visit_i32<E>(self, v: i32) -> Result<Value, E> {
Ok(Value::Int32(v))
}
fn visit_i64<E>(self, v: i64) -> Result<Value, E> {
Ok(Value::Int64(v))
}
fn visit_i128<E>(self, v: i128) -> Result<Value, E> {
Ok(i64::try_from(v).map_or(Value::Number(v as f64), Value::Int64))
}
fn visit_u8<E>(self, v: u8) -> Result<Value, E> {
Ok(Value::Uint8(v))
}
fn visit_u16<E>(self, v: u16) -> Result<Value, E> {
Ok(Value::Uint16(v))
}
fn visit_u32<E>(self, v: u32) -> Result<Value, E> {
Ok(Value::Uint32(v))
}
fn visit_u64<E>(self, v: u64) -> Result<Value, E> {
Ok(Value::Uint64(v))
}
fn visit_u128<E>(self, v: u128) -> Result<Value, E> {
Ok(u64::try_from(v).map_or(Value::Number(v as f64), Value::Uint64))
}
fn visit_f32<E>(self, v: f32) -> Result<Value, E> {
Ok(Value::Number(v as f64))
}
fn visit_f64<E>(self, v: f64) -> Result<Value, E> {
Ok(Value::Number(v))
}
fn visit_str<E>(self, v: &str) -> Result<Value, E> {
Ok(Value::String(v.to_owned()))
}
fn visit_string<E>(self, v: String) -> Result<Value, E> {
Ok(Value::String(v))
}
fn visit_char<E>(self, v: char) -> Result<Value, E> {
Ok(Value::String(v.to_string()))
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Value, E> {
Ok(Value::Bytes(v.to_vec()))
}
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Value, E> {
Ok(Value::Bytes(v))
}
fn visit_none<E>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_unit<E>(self) -> Result<Value, E> {
Ok(Value::Null)
}
fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value, D::Error> {
Value::deserialize(deserializer)
}
fn visit_newtype_struct<D: Deserializer<'de>>(
self,
deserializer: D,
) -> Result<Value, D::Error> {
Value::deserialize(deserializer)
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value, A::Error> {
let mut values = Vec::new();
while let Some(value) = seq.next_element()? {
values.push(value);
}
Ok(Value::Array(values))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Value, A::Error> {
let Some(first_key) = map.next_key::<Cow<str>>()? else {
return Ok(Value::Object(Map::new()));
};
match first_key.as_ref() {
TOKEN_INT => return Ok(Value::Int(map.next_value()?)),
TOKEN_UINT => return Ok(Value::Uint(map.next_value()?)),
TOKEN_DATETIME => {
let s: String = map.next_value()?;
let dt = crate::datetime::parse(&s).map_err(de::Error::custom)?;
return Ok(Value::DateTime(dt));
}
TOKEN_IP => {
let s: String = map.next_value()?;
let ip = s.parse::<IpAddr>().map_err(de::Error::custom)?;
return Ok(Value::Ip(ip));
}
TOKEN_IPPORT => {
let s: String = map.next_value()?;
let sa = s.parse::<SocketAddr>().map_err(de::Error::custom)?;
return Ok(Value::IpPort(sa));
}
sentinel => {
if let Some(name) = strip_ctor(sentinel) {
let arg: Value = map.next_value()?;
return Ok(Value::Constructor {
name: name.to_owned(),
arg: Box::new(arg),
});
}
}
}
let mut object = Map::new();
let first_value: Value = map.next_value()?;
object.insert(first_key.into_owned(), first_value);
while let Some((k, v)) = map.next_entry()? {
object.insert(k, v);
}
Ok(Value::Object(object))
}
}