esexpr 0.2.5

ESExpr serialization format and related utilities.
Documentation
use alloc::borrow::Cow;
use alloc::format;
use alloc::string::String;
use half::f16;
use num_bigint::{BigInt, BigUint};
use esexpr::ESExprEncodedEq;
use crate::cowstr::CowStr;
use crate::{DecodeError, DecodeErrorPath, DecodeErrorType, ESExpr, ESExprCodec, ESExprTag, ESExprTagSet};

macro_rules! encoded_as_partial_eq {
    ($t: ty) => {
		impl ESExprEncodedEq for $t {
			fn is_encoded_eq(&self, other: &Self) -> bool {
				*self == *other
			}
		}
	};
}

encoded_as_partial_eq!(bool);

impl<'a> ESExprCodec<'a> for bool {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Bool]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Bool(*self)
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Bool(b) => Ok(b),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}

encoded_as_partial_eq!(BigInt);

impl<'a> ESExprCodec<'a> for BigInt {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Int]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Int(Cow::Borrowed(self))
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Int(i) => Ok(i.into_owned()),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}

encoded_as_partial_eq!(BigUint);

impl<'a> ESExprCodec<'a> for BigUint {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Int]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Int(Cow::Owned(BigInt::from(self.clone())))
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Int(i) => match BigUint::try_from(i.into_owned()) {
				Ok(i) => Ok(i),
				Err(_) => Err(DecodeError::new(
					DecodeErrorType::OutOfRange(format!("Unexpected integer value for {}", stringify!($T))),
					DecodeErrorPath::Current,
				)),
			},
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}

macro_rules! int_codec {
	($T: ty) => {
		encoded_as_partial_eq!($T);
		impl<'a> ESExprCodec<'a> for $T {
			const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Int]);

			fn encode_esexpr(&self) -> ESExpr<'a> {
				ESExpr::Int(Cow::Owned(BigInt::from(*self)))
			}

			fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
				match expr {
					ESExpr::Int(i) => match <$T>::try_from(i.into_owned()) {
						Ok(i) => Ok(i),
						Err(_) => Err(DecodeError::new(
							DecodeErrorType::OutOfRange(format!("Unexpected integer value for {}", stringify!($T))),
							DecodeErrorPath::Current,
						)),
					},
					_ => Err(DecodeError::new(
						DecodeErrorType::UnexpectedExpr {
							expected_tags: Self::TAGS,
							actual_tag: expr.tag().into_owned(),
						},
						DecodeErrorPath::Current,
					)),
				}
			}
		}
	};
}

int_codec!(isize);
int_codec!(usize);
int_codec!(i128);
int_codec!(u128);
int_codec!(i64);
int_codec!(u64);
int_codec!(i32);
int_codec!(u32);
int_codec!(i16);
int_codec!(u16);
int_codec!(i8);
int_codec!(u8);



encoded_as_partial_eq!(String);

impl<'a> ESExprCodec<'a> for String {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Str]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Str(CowStr::Borrowed(self))
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Str(s) => Ok(s.into_string()),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}


impl <'a> ESExprEncodedEq for Cow<'a, str> {
	fn is_encoded_eq(&self, other: &Self) -> bool {
		self == other
	}
}

impl<'a> ESExprCodec<'a> for Cow<'a, str> {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Str]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Str(CowStr::Borrowed(self.as_ref()))
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Str(s) => Ok(Cow::from(s)),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}


impl <'a> ESExprEncodedEq for CowStr<'a> {
	fn is_encoded_eq(&self, other: &Self) -> bool {
		self == other
	}
}

impl<'a> ESExprCodec<'a> for CowStr<'a> {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Str]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Str(self.as_borrowed())
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Str(s) => Ok(s),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}



impl <'a> ESExprEncodedEq for f16 {
	fn is_encoded_eq(&self, other: &Self) -> bool {
		self.to_bits() == other.to_bits()
	}
}

impl<'a> ESExprCodec<'a> for f16 {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Float16]);

	fn encode_esexpr(&self) -> ESExpr<'a> {
		ESExpr::Float16(*self)
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Float16(f) => Ok(f),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}

impl <'a> ESExprEncodedEq for f32 {
	fn is_encoded_eq(&self, other: &Self) -> bool {
		self.to_bits() == other.to_bits()
	}
}

impl<'a> ESExprCodec<'a> for f32 {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Float32]);

	fn encode_esexpr(&self) -> ESExpr<'a> {
		ESExpr::Float32(*self)
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Float32(f) => Ok(f),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}

impl <'a> ESExprEncodedEq for f64 {
	fn is_encoded_eq(&self, other: &Self) -> bool {
		self.to_bits() == other.to_bits()
	}
}

impl<'a> ESExprCodec<'a> for f64 {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Float64]);

	fn encode_esexpr(&'a self) -> ESExpr<'a> {
		ESExpr::Float64(*self)
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Float64(f) => Ok(f),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}


encoded_as_partial_eq!(());

impl<'a> ESExprCodec<'a> for () {
	const TAGS: ESExprTagSet = ESExprTagSet::Tags(&[ESExprTag::Null]);

	fn encode_esexpr<'b>(&'b self) -> ESExpr<'b> {
		ESExpr::Null(Cow::Owned(BigUint::ZERO))
	}

	fn decode_esexpr(expr: ESExpr<'a>) -> Result<Self, DecodeError> {
		match expr {
			ESExpr::Null(level) if *level == BigUint::ZERO => Ok(()),
			_ => Err(DecodeError::new(
				DecodeErrorType::UnexpectedExpr {
					expected_tags: Self::TAGS,
					actual_tag: expr.tag().into_owned(),
				},
				DecodeErrorPath::Current,
			)),
		}
	}
}