use std::{
fmt,
fmt::{Debug, Display},
hash::Hash,
str::from_utf8_unchecked,
sync::Arc,
};
use faststr::FastStr;
use crate::{
from_str, get_unchecked, index::Index, input::JsonSlice, serde::Number, JsonType,
JsonValueTrait, LazyValue, Result,
};
pub struct OwnedLazyValue {
pub(crate) raw: FastStr,
unescape: Option<Arc<str>>,
}
impl JsonValueTrait for OwnedLazyValue {
type ValueType<'v> = OwnedLazyValue;
fn as_bool(&self) -> Option<bool> {
match self.raw.as_bytes() {
b"true" => Some(true),
b"false" => Some(false),
_ => None,
}
}
fn as_number(&self) -> Option<Number> {
if let Ok(num) = from_str(self.as_raw_str()) {
Some(num)
} else {
None
}
}
#[cfg(feature = "arbitrary_precision")]
fn as_raw_number(&self) -> Option<crate::RawNumber> {
if let Ok(num) = from_str(self.as_raw_str()) {
Some(num)
} else {
None
}
}
fn as_str(&self) -> Option<&str> {
if !self.is_str() {
None
} else if let Some(escaped) = self.unescape.as_ref() {
Some(escaped.as_ref())
} else {
let origin = {
let raw = self.as_raw_str().as_bytes();
&raw[1..raw.len() - 1]
};
Some(unsafe { from_utf8_unchecked(origin) })
}
}
fn get_type(&self) -> crate::JsonType {
match self.raw.as_bytes()[0] {
b'-' | b'0'..=b'9' => JsonType::Number,
b'"' => JsonType::String,
b'{' => JsonType::Object,
b'[' => JsonType::Array,
b't' | b'f' => JsonType::Boolean,
b'n' => JsonType::Null,
_ => unreachable!(),
}
}
fn get<I: Index>(&self, index: I) -> Option<OwnedLazyValue> {
if let Some(key) = index.as_key() {
self.get_key(key)
} else if let Some(index) = index.as_index() {
self.get_index(index)
} else {
unreachable!("index must be key or index")
}
}
fn pointer<P: IntoIterator>(&self, path: P) -> Option<OwnedLazyValue>
where
P::Item: Index,
{
let lv = unsafe { get_unchecked(&self.raw, path).ok() };
lv.map(|v| v.into())
}
}
impl OwnedLazyValue {
pub fn as_raw_str(&self) -> &str {
unsafe { from_utf8_unchecked(self.raw.as_ref()) }
}
pub fn as_raw_faststr(&self) -> FastStr {
self.raw.clone()
}
pub(crate) fn get_index(&self, index: usize) -> Option<Self> {
let path = [index];
let lv = unsafe { get_unchecked(&self.raw, path.iter()).ok() };
lv.map(|v| v.into())
}
pub(crate) fn get_key(&self, key: &str) -> Option<Self> {
let path = [key];
let lv = unsafe { get_unchecked(&self.raw, path.iter()).ok() };
lv.map(|v| v.into())
}
pub(crate) fn new(raw: JsonSlice, has_escaped: bool) -> Result<Self> {
let raw = match raw {
JsonSlice::Raw(r) => FastStr::new(unsafe { from_utf8_unchecked(r) }),
JsonSlice::FastStr(f) => f.clone(),
};
let unescape = if has_escaped {
let unescape: Arc<str> = unsafe { crate::from_slice_unchecked(raw.as_ref()) }?;
Some(unescape)
} else {
None
};
Ok(Self { raw, unescape })
}
}
impl<'de> From<LazyValue<'de>> for OwnedLazyValue {
fn from(lv: LazyValue<'de>) -> Self {
let raw = match lv.raw {
JsonSlice::Raw(r) => FastStr::new(unsafe { from_utf8_unchecked(r) }),
JsonSlice::FastStr(f) => f.clone(),
};
Self {
raw,
unescape: lv.unescape,
}
}
}
impl Debug for OwnedLazyValue {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter
.debug_tuple("OwnedLazyValue")
.field(&format_args!("{}", &self.as_raw_str()))
.finish()
}
}
impl Display for OwnedLazyValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.as_raw_str())
}
}
impl Default for OwnedLazyValue {
fn default() -> Self {
Self {
raw: FastStr::new("null"),
unescape: None,
}
}
}
impl PartialEq for OwnedLazyValue {
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}
impl Clone for OwnedLazyValue {
fn clone(&self) -> Self {
Self {
raw: self.raw.clone(),
unescape: self.unescape.clone(),
}
}
}
impl PartialOrd for OwnedLazyValue {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for OwnedLazyValue {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.raw.cmp(&other.raw)
}
}
impl Eq for OwnedLazyValue {}
impl Hash for OwnedLazyValue {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.raw.hash(state)
}
}