use core::fmt::Write;
use serde::{Deserialize, Serialize};
use crate::{DescendError, IntoKeys, KeysIter, Schema, Transcode};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)]
#[repr(transparent)]
#[serde(transparent)]
pub struct JsonPathIter<'a>(&'a str);
impl<'a> JsonPathIter<'a> {
pub fn new(value: &'a str) -> Self {
Self(value)
}
}
impl core::fmt::Display for JsonPathIter<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<'a> Iterator for JsonPathIter<'a> {
type Item = &'a str;
fn next(&mut self) -> Option<Self::Item> {
enum Close {
Inclusive(&'static str),
Exclusive(&'static [char]),
}
use Close::*;
for (open, close) in [
(".'", Inclusive("'")),
(".", Exclusive(&['.', '['])),
("['", Inclusive("']")),
("[", Inclusive("]")),
] {
if let Some(rest) = self.0.strip_prefix(open) {
let (pre, post) = match close {
Exclusive(close) => rest
.find(close)
.map(|i| rest.split_at(i))
.unwrap_or((rest, "")),
Inclusive(close) => rest.split_once(close)?,
};
self.0 = post;
return Some(pre);
}
}
None
}
}
impl core::iter::FusedIterator for JsonPathIter<'_> {}
#[derive(
Clone, Copy, Debug, Default, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash,
)]
#[repr(transparent)]
#[serde(transparent)]
pub struct JsonPath<T: ?Sized>(pub T);
impl<T> JsonPath<T> {
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: core::fmt::Display> core::fmt::Display for JsonPath<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
self.0.fmt(f)
}
}
impl<'a, T: AsRef<str> + ?Sized> IntoKeys for JsonPath<&'a T> {
type IntoKeys = KeysIter<JsonPathIter<'a>>;
fn into_keys(self) -> Self::IntoKeys {
JsonPathIter(self.0.as_ref()).into_keys()
}
}
impl<'a, T: AsRef<str> + ?Sized> IntoKeys for &'a JsonPath<T> {
type IntoKeys = <JsonPath<&'a str> as IntoKeys>::IntoKeys;
fn into_keys(self) -> Self::IntoKeys {
JsonPathIter(self.0.as_ref()).into_keys()
}
}
impl<T: Write + ?Sized> Transcode for JsonPath<T> {
type Error = core::fmt::Error;
fn transcode(
&mut self,
schema: &Schema,
keys: impl IntoKeys,
) -> Result<(), DescendError<Self::Error>> {
schema.descend(keys.into_keys(), |_meta, idx_internal| {
if let Some((index, internal)) = idx_internal {
if let Some(name) = internal.get_name(index) {
debug_assert!(!name.contains(['.', '\'', '[', ']']));
self.0.write_char('.')?;
self.0.write_str(name)?;
} else {
self.0.write_char('[')?;
self.0.write_str(itoa::Buffer::new().format(index))?;
self.0.write_char(']')?;
}
}
Ok(())
})
}
}