use std::{
fmt::{self, Display},
ops::RangeInclusive,
};
use ordered_float::OrderedFloat;
use super::*;
const MAX_JS_INT: i64 = 0x001F_FFFF_FFFF_FFFF;
const MIN_JS_INT: i64 = -MAX_JS_INT;
pub const JS_INT_RANGE: RangeInclusive<i64> = MIN_JS_INT..=MAX_JS_INT;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(fuzzing, derive(arbitrary::Arbitrary))]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub enum Any {
Undefined,
Null,
Integer(i32),
Float32(OrderedFloat<f32>),
Float64(OrderedFloat<f64>),
BigInt64(i64),
False,
True,
String(String),
#[cfg_attr(test, proptest(skip))]
Object(HashMap<String, Any>),
#[cfg_attr(test, proptest(skip))]
Array(Vec<Any>),
Binary(Vec<u8>),
}
impl<R: CrdtReader> CrdtRead<R> for Any {
fn read(reader: &mut R) -> JwstCodecResult<Self> {
let index = reader.read_u8()?;
match 127u8.overflowing_sub(index).0 {
0 => Ok(Any::Undefined),
1 => Ok(Any::Null),
2 => Ok(Any::Integer(reader.read_var_i32()?)), 3 => Ok(Any::Float32(reader.read_f32_be()?.into())), 4 => Ok(Any::Float64(reader.read_f64_be()?.into())), 5 => Ok(Any::BigInt64(reader.read_i64_be()?)), 6 => Ok(Any::False),
7 => Ok(Any::True),
8 => Ok(Any::String(reader.read_var_string()?)), 9 => {
let len = reader.read_var_u64()?;
let object = (0..len)
.map(|_| Self::read_key_value(reader))
.collect::<Result<Vec<_>, _>>()?;
Ok(Any::Object(object.into_iter().collect()))
} 10 => {
let len = reader.read_var_u64()?;
let any = (0..len).map(|_| Self::read(reader)).collect::<Result<Vec<_>, _>>()?;
Ok(Any::Array(any))
} 11 => {
let binary = reader.read_var_buffer()?;
Ok(Any::Binary(binary.to_vec()))
} _ => Ok(Any::Undefined),
}
}
}
impl<W: CrdtWriter> CrdtWrite<W> for Any {
fn write(&self, writer: &mut W) -> JwstCodecResult {
match self {
Any::Undefined => writer.write_u8(127)?,
Any::Null => writer.write_u8(127 - 1)?,
Any::Integer(value) => {
writer.write_u8(127 - 2)?;
writer.write_var_i32(*value)?;
}
Any::Float32(value) => {
writer.write_u8(127 - 3)?;
writer.write_f32_be(value.into_inner())?;
}
Any::Float64(value) => {
writer.write_u8(127 - 4)?;
writer.write_f64_be(value.into_inner())?;
}
Any::BigInt64(value) => {
writer.write_u8(127 - 5)?;
writer.write_i64_be(*value)?;
}
Any::False => writer.write_u8(127 - 6)?,
Any::True => writer.write_u8(127 - 7)?,
Any::String(value) => {
writer.write_u8(127 - 8)?;
writer.write_var_string(value)?;
}
Any::Object(value) => {
writer.write_u8(127 - 9)?;
writer.write_var_u64(value.len() as u64)?;
for (key, value) in value {
Self::write_key_value(writer, key, value)?;
}
}
Any::Array(values) => {
writer.write_u8(127 - 10)?;
writer.write_var_u64(values.len() as u64)?;
for value in values {
value.write(writer)?;
}
}
Any::Binary(value) => {
writer.write_u8(127 - 11)?;
writer.write_var_buffer(value)?;
}
}
Ok(())
}
}
impl Any {
fn read_key_value<R: CrdtReader>(reader: &mut R) -> JwstCodecResult<(String, Any)> {
let key = reader.read_var_string()?;
let value = Self::read(reader)?;
Ok((key, value))
}
fn write_key_value<W: CrdtWriter>(writer: &mut W, key: &str, value: &Any) -> JwstCodecResult {
writer.write_var_string(key)?;
value.write(writer)?;
Ok(())
}
pub(crate) fn read_multiple<R: CrdtReader>(reader: &mut R) -> JwstCodecResult<Vec<Any>> {
let len = reader.read_var_u64()? as usize;
let mut vec = Vec::with_capacity(len);
for _ in 0..len {
vec.push(Any::read(reader)?);
}
Ok(vec)
}
pub(crate) fn write_multiple<W: CrdtWriter>(writer: &mut W, any: &[Any]) -> JwstCodecResult {
writer.write_var_u64(any.len() as u64)?;
for value in any {
value.write(writer)?;
}
Ok(())
}
}
macro_rules! impl_primitive_from {
(unsigned, $($ty: ty),*) => {
$(
impl From<$ty> for Any {
fn from(value: $ty) -> Self {
let int: i64 = value as i64;
if JS_INT_RANGE.contains(&int) {
if int <= i32::MAX as i64 {
Self::Integer(int as i32)
} else if int as f32 as i64 == int {
Self::Float32((int as f32).into())
} else {
Self::Float64((int as f64).into())
}
} else {
Self::BigInt64(int)
}
}
}
)*
};
(signed, $($ty: ty),*) => {
$(
impl From<$ty> for Any {
fn from(value: $ty) -> Self {
let int: i64 = value.into();
if JS_INT_RANGE.contains(&int) {
if int <= i32::MAX as i64 {
Self::Integer(int as i32)
} else if int as f32 as i64 == int {
Self::Float32((int as f32).into())
} else {
Self::Float64((int as f64).into())
}
} else {
Self::BigInt64(int)
}
}
}
)*
};
(string, $($ty: ty),*) => {
$(
impl From<$ty> for Any {
fn from(value: $ty) -> Self {
Self::String(value.into())
}
}
)*
};
}
impl_primitive_from!(unsigned, u8, u16, u32, u64);
impl_primitive_from!(signed, i8, i16, i32, i64);
impl_primitive_from!(string, String, &str);
impl From<usize> for Any {
fn from(value: usize) -> Self {
(value as u64).into()
}
}
impl From<isize> for Any {
fn from(value: isize) -> Self {
(value as i64).into()
}
}
impl From<f32> for Any {
fn from(value: f32) -> Self {
Self::Float32(value.into())
}
}
impl From<f64> for Any {
fn from(value: f64) -> Self {
if value.trunc() == value {
(value as i64).into()
} else if value as f32 as f64 == value {
Self::Float32((value as f32).into())
} else {
Self::Float64(value.into())
}
}
}
impl From<bool> for Any {
fn from(value: bool) -> Self {
if value { Self::True } else { Self::False }
}
}
impl TryFrom<Any> for String {
type Error = JwstCodecError;
fn try_from(value: Any) -> Result<Self, Self::Error> {
match value {
Any::String(s) => Ok(s),
_ => Err(JwstCodecError::UnexpectedType("String")),
}
}
}
impl TryFrom<Any> for HashMap<String, Any> {
type Error = JwstCodecError;
fn try_from(value: Any) -> Result<Self, Self::Error> {
match value {
Any::Object(map) => Ok(map),
_ => Err(JwstCodecError::UnexpectedType("Object")),
}
}
}
impl TryFrom<Any> for Vec<Any> {
type Error = JwstCodecError;
fn try_from(value: Any) -> Result<Self, Self::Error> {
match value {
Any::Array(vec) => Ok(vec),
_ => Err(JwstCodecError::UnexpectedType("Array")),
}
}
}
impl TryFrom<Any> for bool {
type Error = JwstCodecError;
fn try_from(value: Any) -> Result<Self, Self::Error> {
match value {
Any::True => Ok(true),
Any::False => Ok(false),
_ => Err(JwstCodecError::UnexpectedType("Boolean")),
}
}
}
impl FromIterator<Any> for Any {
fn from_iter<I: IntoIterator<Item = Any>>(iter: I) -> Self {
Self::Array(iter.into_iter().collect())
}
}
impl<'a> FromIterator<&'a Any> for Any {
fn from_iter<I: IntoIterator<Item = &'a Any>>(iter: I) -> Self {
Self::Array(iter.into_iter().cloned().collect())
}
}
impl FromIterator<(String, Any)> for Any {
fn from_iter<I: IntoIterator<Item = (String, Any)>>(iter: I) -> Self {
let mut map = HashMap::new();
map.extend(iter);
Self::Object(map)
}
}
impl From<HashMap<String, Any>> for Any {
fn from(value: HashMap<String, Any>) -> Self {
Self::Object(value)
}
}
impl From<Vec<u8>> for Any {
fn from(value: Vec<u8>) -> Self {
Self::Binary(value)
}
}
impl From<&[u8]> for Any {
fn from(value: &[u8]) -> Self {
Self::Binary(value.into())
}
}
impl<T: Into<Any>> From<Option<T>> for Any {
fn from(value: Option<T>) -> Self {
if let Some(val) = value { val.into() } else { Any::Null }
}
}
#[cfg(feature = "serde_json")]
impl From<serde_json::Value> for Any {
fn from(value: serde_json::Value) -> Self {
match value {
serde_json::Value::Null => Self::Null,
serde_json::Value::Bool(b) => {
if b {
Self::True
} else {
Self::False
}
}
serde_json::Value::Number(n) => {
if n.is_f64() {
Self::Float64(n.as_f64().unwrap().into())
} else if n.is_i64() {
Self::Integer(n.as_i64().unwrap() as i32)
} else {
Self::Integer(n.as_u64().unwrap() as i32)
}
}
serde_json::Value::String(s) => Self::String(s),
serde_json::Value::Array(vec) => Self::Array(vec.into_iter().map(|v| v.into()).collect::<Vec<_>>()),
serde_json::Value::Object(obj) => Self::Object(obj.into_iter().map(|(k, v)| (k, v.into())).collect()),
}
}
}
impl<'de> serde::Deserialize<'de> for Any {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
struct ValueVisitor;
impl<'de> Visitor<'de> for ValueVisitor {
type Value = Any;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("any valid JSON value")
}
#[inline]
fn visit_bool<E>(self, value: bool) -> Result<Any, E> {
Ok(if value { Any::True } else { Any::False })
}
#[inline]
fn visit_i64<E>(self, value: i64) -> Result<Any, E> {
Ok(Any::BigInt64(value))
}
#[inline]
fn visit_u64<E>(self, value: u64) -> Result<Any, E> {
Ok((value as i64).into())
}
#[inline]
fn visit_f64<E>(self, value: f64) -> Result<Any, E> {
Ok(Any::Float64(OrderedFloat(value)))
}
#[inline]
fn visit_str<E>(self, value: &str) -> Result<Any, E>
where
E: Error,
{
self.visit_string(String::from(value))
}
#[inline]
fn visit_string<E>(self, value: String) -> Result<Any, E> {
Ok(Any::String(value))
}
#[inline]
fn visit_none<E>(self) -> Result<Any, E> {
Ok(Any::Null)
}
#[inline]
fn visit_some<D>(self, deserializer: D) -> Result<Any, D::Error>
where
D: serde::Deserializer<'de>,
{
serde::Deserialize::deserialize(deserializer)
}
#[inline]
fn visit_unit<E>(self) -> Result<Any, E> {
Ok(Any::Null)
}
#[inline]
fn visit_seq<V>(self, mut visitor: V) -> Result<Any, V::Error>
where
V: SeqAccess<'de>,
{
let mut vec = Vec::new();
while let Some(elem) = visitor.next_element()? {
vec.push(elem);
}
Ok(Any::Array(vec))
}
fn visit_map<V>(self, mut visitor: V) -> Result<Any, V::Error>
where
V: MapAccess<'de>,
{
match visitor.next_key::<String>()? {
Some(k) => {
let mut values = HashMap::new();
values.insert(k, visitor.next_value()?);
while let Some((key, value)) = visitor.next_entry()? {
values.insert(key, value);
}
Ok(Any::Object(values))
}
None => Ok(Any::Object(HashMap::new())),
}
}
}
deserializer.deserialize_any(ValueVisitor)
}
}
impl serde::Serialize for Any {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::{SerializeMap, SerializeSeq};
match self {
Any::Null => serializer.serialize_none(),
Any::Undefined => serializer.serialize_none(),
Any::True => serializer.serialize_bool(true),
Any::False => serializer.serialize_bool(false),
Any::Float32(value) => serializer.serialize_f32(value.0),
Any::Float64(value) => serializer.serialize_f64(value.0),
Any::Integer(value) => serializer.serialize_i32(*value),
Any::BigInt64(value) => serializer.serialize_i64(*value),
Any::String(value) => serializer.serialize_str(value.as_ref()),
Any::Array(values) => {
let mut seq = serializer.serialize_seq(Some(values.len()))?;
for value in values.iter() {
seq.serialize_element(value)?;
}
seq.end()
}
Any::Object(entries) => {
let mut map = serializer.serialize_map(Some(entries.len()))?;
for (key, value) in entries.iter() {
map.serialize_entry(key, value)?;
}
map.end()
}
Any::Binary(buf) => serializer.serialize_bytes(buf),
}
}
}
impl Display for Any {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::True => write!(f, "true"),
Self::False => write!(f, "false"),
Self::String(s) => write!(f, "\"{s}\""),
Self::Integer(i) => write!(f, "{i}"),
Self::Float32(v) => write!(f, "{v}"),
Self::Float64(v) => write!(f, "{v}"),
Self::BigInt64(v) => write!(f, "{v}"),
Self::Object(map) => {
write!(f, "{{")?;
for (i, (key, value)) in map.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{key}: {value}")?;
}
write!(f, "}}")
}
Self::Array(vec) => {
write!(f, "[")?;
for (i, value) in vec.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{value}")?;
}
write!(f, "]")
}
Self::Binary(buf) => write!(f, "{buf:?}"),
Self::Undefined => write!(f, "undefined"),
Self::Null => write!(f, "null"),
}
}
}
#[cfg(test)]
mod tests {
use proptest::{collection::vec, prelude::*};
use super::*;
#[test]
fn test_any_codec() {
let any = Any::Object(
vec![
("name".to_string(), Any::String("Alice".to_string())),
("age".to_string(), Any::Integer(25)),
(
"contacts".to_string(),
Any::Array(vec![
Any::Object(
vec![
("type".to_string(), Any::String("Mobile".to_string())),
("number".to_string(), Any::String("1234567890".to_string())),
]
.into_iter()
.collect(),
),
Any::Object(
vec![
("type".to_string(), Any::String("Email".to_string())),
("address".to_string(), Any::String("alice@example.com".to_string())),
]
.into_iter()
.collect(),
),
Any::Undefined,
]),
),
(
"standard_data".to_string(),
Any::Array(vec![
Any::Undefined,
Any::Null,
Any::Integer(114514),
Any::Float32(114.514.into()),
Any::Float64(115.514.into()),
Any::BigInt64(-1145141919810),
Any::False,
Any::True,
Any::Object(
vec![
("name".to_string(), Any::String("tadokoro".to_string())),
("age".to_string(), Any::String("24".to_string())),
("profession".to_string(), Any::String("student".to_string())),
]
.into_iter()
.collect(),
),
Any::Binary(vec![1, 2, 3, 4, 5]),
]),
),
]
.into_iter()
.collect(),
);
let mut encoder = RawEncoder::default();
any.write(&mut encoder).unwrap();
let encoded = encoder.into_inner();
let mut decoder = RawDecoder::new(&encoded);
let decoded = Any::read(&mut decoder).unwrap();
assert_eq!(any, decoded);
}
proptest! {
#[test]
#[cfg_attr(miri, ignore)]
fn test_random_any(any in vec(any::<Any>(), 0..100)) {
for any in &any {
let mut encoder = RawEncoder::default();
any.write(&mut encoder).unwrap();
let encoded = encoder.into_inner();
let mut decoder = RawDecoder::new(&encoded);
let decoded = Any::read(&mut decoder).unwrap();
assert_eq!(any, &decoded);
}
}
}
#[test]
fn test_convert_to_any() {
let any: Vec<Any> = vec![
42u8.into(),
42u16.into(),
42u32.into(),
42u64.into(),
114.514f32.into(),
1919.810f64.into(),
(-42i8).into(),
(-42i16).into(),
(-42i32).into(),
(-42i64).into(),
false.into(),
true.into(),
"JWST".to_string().into(),
"OctoBase".into(),
vec![1u8, 9, 1, 9].into(),
(&[8u8, 1, 0][..]).into(),
[Any::True, 42u8.into()].iter().collect(),
];
assert_eq!(
any,
vec![
Any::Integer(42),
Any::Integer(42),
Any::Integer(42),
Any::Integer(42),
Any::Float32(114.514.into()),
Any::Float64(1919.810.into()),
Any::Integer(-42),
Any::Integer(-42),
Any::Integer(-42),
Any::Integer(-42),
Any::False,
Any::True,
Any::String("JWST".to_string()),
Any::String("OctoBase".to_string()),
Any::Binary(vec![1, 9, 1, 9]),
Any::Binary(vec![8, 1, 0]),
Any::Array(vec![Any::True, Any::Integer(42)])
]
);
assert_eq!(
vec![("key".to_string(), 10u64.into())].into_iter().collect::<Any>(),
Any::Object(HashMap::from_iter(vec![("key".to_string(), Any::Integer(10))]))
);
let any: Any = 10u64.into();
assert_eq!([any].iter().collect::<Any>(), Any::Array(vec![Any::Integer(10)]));
}
}