mod array;
mod object;
pub use crate::yason::array::{Array, ArrayIter};
pub use crate::yason::object::{KeyIter, Object, ObjectIter, ValueIter};
use crate::binary::{ARRAY_SIZE, DATA_TYPE_SIZE, NUMBER_LENGTH_SIZE, OBJECT_SIZE};
use crate::format::{CompactFormatter, FormatResult, Formatter, LazyFormat, PrettyFormatter};
use crate::util::decode_varint;
use crate::{BuildError, DataType, Number, Scalar};
use std::borrow::Borrow;
use std::collections::TryReserveError;
use std::error::Error;
use std::fmt;
use std::fmt::Display;
use std::mem::size_of;
use std::ops::Deref;
#[derive(Debug)]
pub enum YasonError {
IndexOutOfBounds { len: usize, index: usize },
UnexpectedType { expected: DataType, actual: DataType },
InvalidDataType(u8),
MultiValuesWithoutWrapper,
TryReserveError(TryReserveError),
InvalidPathExpression,
}
impl fmt::Display for YasonError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
match self {
YasonError::IndexOutOfBounds { len, index } => {
write!(f, "index out of bounds: the len is {} but the index is {}", len, index)
}
YasonError::UnexpectedType { expected, actual } => {
write!(f, "data type mismatch, expect {}, but actual {}", expected, actual)
}
YasonError::InvalidDataType(e) => write!(f, "invalid data type value '{}'", e),
YasonError::MultiValuesWithoutWrapper => {
write!(f, "multiple values cannot be returned without array wrapper")
}
YasonError::TryReserveError(e) => write!(f, "{}", e),
YasonError::InvalidPathExpression => write!(f, "invalid path expression"),
}
}
}
impl From<BuildError> for YasonError {
#[inline]
fn from(err: BuildError) -> Self {
match err {
BuildError::TryReserveError(e) => YasonError::TryReserveError(e),
_ => unreachable!(),
}
}
}
impl Error for YasonError {}
pub type YasonResult<T> = std::result::Result<T, YasonError>;
#[derive(Debug, Clone)]
#[repr(transparent)]
pub struct YasonBuf {
bytes: Vec<u8>,
}
impl YasonBuf {
#[inline]
pub unsafe fn new_unchecked(bytes: Vec<u8>) -> Self {
debug_assert!(!bytes.is_empty());
YasonBuf { bytes }
}
#[inline]
pub fn clone_from_yason(&mut self, yason: &Yason) {
self.bytes.clear();
self.bytes.extend_from_slice(yason.as_bytes())
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct Yason {
bytes: [u8],
}
impl Deref for YasonBuf {
type Target = Yason;
#[inline]
fn deref(&self) -> &Yason {
unsafe { Yason::new_unchecked(&self.bytes) }
}
}
impl Borrow<Yason> for YasonBuf {
#[inline]
fn borrow(&self) -> &Yason {
self.deref()
}
}
impl ToOwned for Yason {
type Owned = YasonBuf;
#[inline]
fn to_owned(&self) -> YasonBuf {
unsafe { YasonBuf::new_unchecked(self.bytes.to_vec()) }
}
}
impl AsRef<Yason> for Yason {
#[inline]
fn as_ref(&self) -> &Yason {
self
}
}
impl AsRef<Yason> for YasonBuf {
#[inline]
fn as_ref(&self) -> &Yason {
self
}
}
impl Yason {
#[inline]
pub unsafe fn new_unchecked<B: AsRef<[u8]> + ?Sized>(bytes: &B) -> &Yason {
debug_assert!(!bytes.as_ref().is_empty());
&*(bytes.as_ref() as *const [u8] as *const Yason)
}
#[inline]
pub fn to_yason_buf(&self) -> YasonResult<YasonBuf> {
let mut bytes = Vec::new();
bytes
.try_reserve(self.bytes.len())
.map_err(YasonError::TryReserveError)?;
bytes.extend_from_slice(&self.bytes);
Ok(YasonBuf { bytes })
}
#[inline]
pub fn data_type(&self) -> YasonResult<DataType> {
let data_type = self.get(0)?;
DataType::try_from(data_type).map_err(|_| YasonError::InvalidDataType(data_type))
}
#[inline]
pub fn object(&self) -> YasonResult<Object> {
self.check_type(0, DataType::Object)?;
unsafe { self.object_unchecked() }
}
#[inline]
pub(crate) unsafe fn object_unchecked(&self) -> YasonResult<Object> {
debug_assert!(self.data_type()? == DataType::Object);
Ok(Object::new_unchecked(self))
}
#[inline]
pub fn array(&self) -> YasonResult<Array> {
self.check_type(0, DataType::Array)?;
unsafe { self.array_unchecked() }
}
#[inline]
pub(crate) unsafe fn array_unchecked(&self) -> YasonResult<Array> {
debug_assert!(self.data_type()? == DataType::Array);
Ok(Array::new_unchecked(self))
}
#[inline]
pub fn string(&self) -> YasonResult<&str> {
self.check_type(0, DataType::String)?;
unsafe { self.string_unchecked() }
}
#[inline]
pub(crate) unsafe fn string_unchecked(&self) -> YasonResult<&str> {
debug_assert!(self.data_type()? == DataType::String);
self.read_string(0)
}
#[inline]
pub fn number(&self) -> YasonResult<Number> {
self.check_type(0, DataType::Number)?;
unsafe { self.number_unchecked() }
}
#[inline]
pub(crate) unsafe fn number_unchecked(&self) -> YasonResult<Number> {
debug_assert!(self.data_type()? == DataType::Number);
self.read_number(0)
}
#[inline]
pub fn bool(&self) -> YasonResult<bool> {
self.check_type(0, DataType::Bool)?;
unsafe { self.bool_unchecked() }
}
#[inline]
pub(crate) unsafe fn bool_unchecked(&self) -> YasonResult<bool> {
debug_assert!(self.data_type()? == DataType::Bool);
self.read_bool(0)
}
#[inline]
pub fn is_null(&self) -> YasonResult<bool> {
self.is_type(0, DataType::Null as u8)
}
#[inline]
pub fn format(&self, pretty: bool) -> impl Display + '_ {
LazyFormat::new(self, pretty)
}
#[inline]
pub fn format_to<W: fmt::Write>(&self, pretty: bool, buf: &mut W) -> FormatResult<()> {
if pretty {
let mut fmt = PrettyFormatter::new();
fmt.format(self, buf)
} else {
let mut fmt = CompactFormatter::new();
fmt.format(self, buf)
}
}
#[inline]
pub fn as_bytes(&self) -> &[u8] {
&self.bytes
}
#[inline]
pub fn equals<T: AsRef<Yason>>(&self, other: T) -> YasonResult<bool> {
let other = other.as_ref();
if self.bytes.len() != other.bytes.len() || self.data_type()? != other.data_type()? {
return Ok(false);
}
let left = LazyValue::try_from(self)?;
let right = LazyValue::try_from(other)?;
left.equals(right)
}
}
impl Yason {
#[inline]
fn get(&self, index: usize) -> YasonResult<u8> {
self.bytes.get(index).map_or_else(
|| {
Err(YasonError::IndexOutOfBounds {
len: self.bytes.len(),
index,
})
},
|v| Ok(*v),
)
}
#[allow(clippy::unnecessary_lazy_evaluations)]
#[inline]
fn slice(&self, from: usize, to: usize) -> YasonResult<&[u8]> {
self.bytes.get(from..to).ok_or_else(|| YasonError::IndexOutOfBounds {
len: self.bytes.len(),
index: to,
})
}
#[inline]
fn read_type(&self, index: usize) -> YasonResult<DataType> {
let data_type = self.get(index)?;
DataType::try_from(data_type).map_err(|_| YasonError::InvalidDataType(data_type))
}
#[inline]
fn is_type(&self, index: usize, data_type: u8) -> YasonResult<bool> {
Ok(self.get(index)? == data_type)
}
#[inline]
fn read_i32(&self, index: usize) -> YasonResult<i32> {
let end = index + size_of::<i32>();
let bytes = self.slice(index, end)?;
Ok(i32::from_le_bytes(bytes.try_into().unwrap()))
}
#[inline]
fn read_u8(&self, index: usize) -> YasonResult<u8> {
self.get(index)
}
#[inline]
fn read_u16(&self, index: usize) -> YasonResult<u16> {
let end = index + size_of::<u16>();
let bytes = self.slice(index, end)?;
Ok(u16::from_le_bytes(bytes.try_into().unwrap()))
}
#[inline]
fn read_u32(&self, index: usize) -> YasonResult<u32> {
let end = index + size_of::<u32>();
let bytes = self.slice(index, end)?;
Ok(u32::from_le_bytes(bytes.try_into().unwrap()))
}
#[inline]
fn read_object(&self, index: usize) -> YasonResult<Object> {
let size = self.read_i32(index + DATA_TYPE_SIZE)? as usize + DATA_TYPE_SIZE + OBJECT_SIZE;
let yason = unsafe { Yason::new_unchecked(self.slice(index, size + index)?) };
Ok(unsafe { Object::new_unchecked(yason) })
}
#[inline]
fn read_array(&self, index: usize) -> YasonResult<Array> {
let size = self.read_i32(index + DATA_TYPE_SIZE)? as usize + DATA_TYPE_SIZE + ARRAY_SIZE;
let yason = unsafe { Yason::new_unchecked(self.slice(index, size + index)?) };
Ok(unsafe { Array::new_unchecked(yason) })
}
#[inline]
fn read_string(&self, index: usize) -> YasonResult<&str> {
let index = index + DATA_TYPE_SIZE;
let (data_length, data_length_len) = decode_varint(&self.bytes, index)?;
let end = index + data_length_len + data_length as usize;
let bytes = self.slice(index + data_length_len, end)?;
let string = unsafe { std::str::from_utf8_unchecked(bytes) };
Ok(string)
}
#[inline]
fn read_number(&self, index: usize) -> YasonResult<Number> {
let index = index + DATA_TYPE_SIZE;
let data_length = self.get(index)? as usize;
let end = index + NUMBER_LENGTH_SIZE + data_length;
let bytes = self.slice(index + NUMBER_LENGTH_SIZE, end)?;
Ok(Number::decode(bytes))
}
#[inline]
fn read_bool(&self, index: usize) -> YasonResult<bool> {
Ok(self.read_u8(index + DATA_TYPE_SIZE)? == 1)
}
#[inline]
fn check_type(&self, index: usize, expected: DataType) -> YasonResult<()> {
if !self.is_type(index, expected as u8)? {
return Err(YasonError::UnexpectedType {
expected,
actual: self.read_type(index)?,
});
}
Ok(())
}
}
impl PartialEq for Yason {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.equals(other).expect("an error occurred when comparing yason")
}
}
impl PartialEq for YasonBuf {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.as_ref()
.equals(other)
.expect("an error occurred when comparing yason")
}
}
#[derive(Clone, Debug)]
pub enum Value<'a> {
Object(Object<'a>),
Array(Array<'a>),
String(&'a str),
Number(Number),
Bool(bool),
Null,
}
impl<'a> Value<'a> {
#[inline]
pub fn data_type(&self) -> DataType {
match self {
Value::Object(_) => DataType::Object,
Value::Array(_) => DataType::Array,
Value::String(_) => DataType::String,
Value::Number(_) => DataType::Number,
Value::Bool(_) => DataType::Bool,
Value::Null => DataType::Null,
}
}
#[inline]
pub fn try_to_yason(&self, buf: &'a mut Vec<u8>) -> YasonResult<&Yason> {
match self {
Value::Object(object) => Ok(object.yason()),
Value::Array(array) => Ok(array.yason()),
Value::String(str) => Ok(Scalar::string_with_vec(str, buf)?),
Value::Number(num) => Ok(Scalar::number_with_vec(num, buf)?),
Value::Bool(bool) => Ok(Scalar::bool_with_vec(*bool, buf)?),
Value::Null => Ok(Scalar::null_with_vec(buf)?),
}
}
#[inline]
pub(crate) fn format_to<W: fmt::Write>(&self, pretty: bool, writer: &mut W) -> FormatResult<()> {
match self {
Value::Object(object) => object.yason().format_to(pretty, writer),
Value::Array(array) => array.yason().format_to(pretty, writer),
Value::String(str) => {
let mut fmt = CompactFormatter::new();
fmt.write_string(str, writer)
}
Value::Number(number) => {
let mut fmt = CompactFormatter::new();
fmt.write_number(number, writer)
}
Value::Bool(bool) => {
let mut fmt = CompactFormatter::new();
fmt.write_bool(*bool, writer)
}
Value::Null => {
let mut fmt = CompactFormatter::new();
fmt.write_null(writer)
}
}
}
}
impl<'a> TryFrom<&'a Yason> for Value<'a> {
type Error = YasonError;
#[inline]
fn try_from(yason: &'a Yason) -> Result<Self, Self::Error> {
match yason.data_type()? {
DataType::Object => Ok(Value::Object(unsafe { Object::new_unchecked(yason) })),
DataType::Array => Ok(Value::Array(unsafe { Array::new_unchecked(yason) })),
DataType::String => Ok(Value::String(unsafe { yason.string_unchecked()? })),
DataType::Number => Ok(Value::Number(unsafe { yason.number_unchecked()? })),
DataType::Bool => Ok(Value::Bool(unsafe { yason.bool_unchecked()? })),
DataType::Null => Ok(Value::Null),
}
}
}
pub struct LazyValue<'a, const IN_ARRAY: bool> {
yason: &'a Yason,
ty: DataType,
value_pos: usize,
}
impl<'a, const IN_ARRAY: bool> LazyValue<'a, IN_ARRAY> {
#[inline]
const fn new(yason: &'a Yason, ty: DataType, value_pos: usize) -> Self {
Self { yason, ty, value_pos }
}
#[inline]
pub const fn data_type(&self) -> DataType {
self.ty
}
#[inline]
pub fn value(&self) -> YasonResult<Value<'a>> {
let res = unsafe {
match self.ty {
DataType::Object => Value::Object(self.object()?),
DataType::Array => Value::Array(self.array()?),
DataType::String => Value::String(self.string()?),
DataType::Number => Value::Number(self.number()?),
DataType::Bool => Value::Bool(self.bool()?),
DataType::Null => Value::Null,
}
};
Ok(res)
}
#[inline]
pub unsafe fn object(&self) -> YasonResult<Object<'a>> {
debug_assert!(self.ty == DataType::Object);
if IN_ARRAY {
Array::new_unchecked(self.yason).read_object(self.value_pos)
} else {
self.yason.read_object(self.value_pos)
}
}
#[inline]
pub unsafe fn array(&self) -> YasonResult<Array<'a>> {
debug_assert!(self.ty == DataType::Array);
if IN_ARRAY {
Array::new_unchecked(self.yason).read_array(self.value_pos)
} else {
self.yason.read_array(self.value_pos)
}
}
#[inline]
pub unsafe fn string(&self) -> YasonResult<&'a str> {
debug_assert!(self.ty == DataType::String);
if IN_ARRAY {
Array::new_unchecked(self.yason).read_string(self.value_pos)
} else {
self.yason.read_string(self.value_pos)
}
}
#[inline]
pub unsafe fn number(&self) -> YasonResult<Number> {
debug_assert!(self.ty == DataType::Number);
if IN_ARRAY {
Array::new_unchecked(self.yason).read_number(self.value_pos)
} else {
self.yason.read_number(self.value_pos)
}
}
#[inline]
pub unsafe fn bool(&self) -> YasonResult<bool> {
debug_assert!(self.ty == DataType::Bool);
if IN_ARRAY {
Array::new_unchecked(self.yason).read_bool(self.value_pos)
} else {
self.yason.read_bool(self.value_pos)
}
}
#[inline]
pub fn equals(&self, other: LazyValue<IN_ARRAY>) -> YasonResult<bool> {
if self.data_type() != other.data_type() || self.yason.bytes.len() != other.yason.bytes.len() {
return Ok(false);
}
match self.data_type() {
DataType::Object => unsafe { self.object()?.equals(other.object()?) },
DataType::Array => unsafe { self.array()?.equals(other.array()?) },
DataType::String => unsafe { Ok(self.string()?.eq(other.string()?)) },
DataType::Number => unsafe { Ok(self.number()?.eq(&other.number()?)) },
DataType::Bool => unsafe { Ok(self.bool()?.eq(&other.bool()?)) },
DataType::Null => Ok(true),
}
}
}
impl<'a> TryFrom<&'a Yason> for LazyValue<'a, false> {
type Error = YasonError;
#[inline]
fn try_from(yason: &'a Yason) -> Result<Self, Self::Error> {
let data_type = yason.data_type()?;
Ok(Self {
yason,
ty: data_type,
value_pos: 0,
})
}
}