mod canonical;
mod de;
mod integer;
mod ser;
pub use canonical::KeyOrder;
pub use integer::Integer;
#[derive(Clone, Debug)]
pub enum Error {
Custom(String),
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Error::Custom(msg) => write!(f, "{msg}"),
}
}
}
impl std::error::Error for Error {}
impl serde::de::Error for Error {
#[inline]
fn custom<T: core::fmt::Display>(msg: T) -> Self {
Self::Custom(msg.to_string())
}
}
impl serde::ser::Error for Error {
#[inline]
fn custom<T: core::fmt::Display>(msg: T) -> Self {
Self::Custom(msg.to_string())
}
}
#[non_exhaustive]
#[derive(Clone, PartialEq, PartialOrd)]
pub enum Value {
Integer(Integer),
Bytes(Vec<u8>),
Float(f64),
Text(String),
Bool(bool),
Null,
Tag(u64, Box<Value>),
Array(Vec<Value>),
Map(Vec<(Value, Value)>),
}
impl core::fmt::Debug for Value {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut out = String::new();
crate::diag::write_value_pretty(&mut out, self, 0);
f.write_str(&out)
}
}
macro_rules! accessors {
($(#[doc = $doc:literal] $is:ident $as:ident $into:ident($variant:ident) -> $t:ty;)+) => {
$(
#[doc = concat!("Returns true if the value is ", $doc, ".")]
#[inline]
pub fn $is(&self) -> bool {
matches!(self, Value::$variant(..))
}
#[doc = concat!("If the value is ", $doc, ", returns a reference to it. Returns `None` otherwise.")]
#[inline]
pub fn $as(&self) -> Option<&$t> {
match self {
Value::$variant(x) => Some(x),
_ => None,
}
}
#[doc = concat!("If the value is ", $doc, ", returns it as `Ok`. Returns `Err(self)` otherwise.")]
#[inline]
pub fn $into(self) -> Result<$t, Self> {
match self {
Value::$variant(x) => Ok(x),
other => Err(other),
}
}
)+
};
}
impl Value {
accessors! {
#[doc = "a byte string"]
is_bytes as_bytes into_bytes(Bytes) -> Vec<u8>;
#[doc = "an array"]
is_array as_array into_array(Array) -> Vec<Value>;
#[doc = "a map"]
is_map as_map into_map(Map) -> Vec<(Value, Value)>;
}
#[inline]
pub fn is_integer(&self) -> bool {
matches!(self, Value::Integer(..))
}
#[inline]
pub fn as_integer(&self) -> Option<Integer> {
match self {
Value::Integer(x) => Some(*x),
_ => None,
}
}
#[inline]
pub fn into_integer(self) -> Result<Integer, Self> {
match self {
Value::Integer(x) => Ok(x),
other => Err(other),
}
}
#[inline]
pub fn is_float(&self) -> bool {
matches!(self, Value::Float(..))
}
#[inline]
pub fn as_float(&self) -> Option<f64> {
match self {
Value::Float(x) => Some(*x),
_ => None,
}
}
#[inline]
pub fn into_float(self) -> Result<f64, Self> {
match self {
Value::Float(x) => Ok(x),
other => Err(other),
}
}
#[inline]
pub fn is_text(&self) -> bool {
matches!(self, Value::Text(..))
}
#[inline]
pub fn as_text(&self) -> Option<&str> {
match self {
Value::Text(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn into_text(self) -> Result<String, Self> {
match self {
Value::Text(x) => Ok(x),
other => Err(other),
}
}
#[inline]
pub fn is_bool(&self) -> bool {
matches!(self, Value::Bool(..))
}
#[inline]
pub fn as_bool(&self) -> Option<bool> {
match self {
Value::Bool(x) => Some(*x),
_ => None,
}
}
#[inline]
pub fn into_bool(self) -> Result<bool, Self> {
match self {
Value::Bool(x) => Ok(x),
other => Err(other),
}
}
#[inline]
pub fn is_null(&self) -> bool {
matches!(self, Value::Null)
}
#[inline]
pub fn is_tag(&self) -> bool {
matches!(self, Value::Tag(..))
}
#[inline]
pub fn as_tag(&self) -> Option<(u64, &Value)> {
match self {
Value::Tag(tag, data) => Some((*tag, data)),
_ => None,
}
}
#[inline]
pub fn into_tag(self) -> Result<(u64, Box<Value>), Self> {
match self {
Value::Tag(tag, data) => Ok((tag, data)),
other => Err(other),
}
}
#[inline]
pub fn as_bytes_mut(&mut self) -> Option<&mut Vec<u8>> {
match self {
Value::Bytes(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_text_mut(&mut self) -> Option<&mut String> {
match self {
Value::Text(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_array_mut(&mut self) -> Option<&mut Vec<Value>> {
match self {
Value::Array(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_map_mut(&mut self) -> Option<&mut Vec<(Value, Value)>> {
match self {
Value::Map(x) => Some(x),
_ => None,
}
}
#[inline]
pub fn as_tag_mut(&mut self) -> Option<(&mut u64, &mut Value)> {
match self {
Value::Tag(tag, data) => Some((tag, data.as_mut())),
_ => None,
}
}
}
impl core::fmt::Display for Value {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut out = String::new();
crate::diag::write_value(&mut out, self);
f.write_str(&out)
}
}
macro_rules! implfrom {
($($variant:ident($t:ty)),+ $(,)?) => {
$(
impl From<$t> for Value {
#[inline]
fn from(value: $t) -> Self {
Self::$variant(value.into())
}
}
)+
};
}
implfrom! {
Integer(Integer),
Integer(u64),
Integer(i64),
Integer(u32),
Integer(i32),
Integer(u16),
Integer(i16),
Integer(u8),
Integer(i8),
Bytes(Vec<u8>),
Bytes(&[u8]),
Float(f64),
Float(f32),
Text(String),
Text(&str),
Bool(bool),
Array(&[Value]),
Array(Vec<Value>),
Map(&[(Value, Value)]),
Map(Vec<(Value, Value)>),
}
impl From<u128> for Value {
#[inline]
fn from(value: u128) -> Self {
if let Ok(x) = Integer::try_from(value) {
return Value::Integer(x);
}
let mut bytes = &value.to_be_bytes()[..];
while let Some(0) = bytes.first() {
bytes = &bytes[1..];
}
Value::Tag(crate::core::tag::BIGPOS, Value::Bytes(bytes.into()).into())
}
}
impl From<i128> for Value {
#[inline]
fn from(value: i128) -> Self {
if let Ok(x) = Integer::try_from(value) {
return Value::Integer(x);
}
let (tag, raw) = match value.is_negative() {
true => (crate::core::tag::BIGNEG, value as u128 ^ !0),
false => (crate::core::tag::BIGPOS, value as u128),
};
let mut bytes = &raw.to_be_bytes()[..];
while let Some(0) = bytes.first() {
bytes = &bytes[1..];
}
Value::Tag(tag, Value::Bytes(bytes.into()).into())
}
}
impl From<char> for Value {
#[inline]
fn from(value: char) -> Self {
let mut v = String::with_capacity(value.len_utf8());
v.push(value);
Value::Text(v)
}
}