use crate::{Object, ObjectRef, ObjectRefMut};
#[allow(unused_imports)]
use crate::PatchOperation;
use alloc::collections::{BTreeMap, LinkedList, VecDeque};
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use core::marker::PhantomData;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PathSegment<'a> {
Field(&'a str),
Key(&'a str),
Variant(&'a str),
Item(usize),
}
#[derive(Clone, Default, PartialEq, Eq, Hash)]
pub struct OwnedPath {
encoded: String,
}
impl OwnedPath {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.encoded.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.iter().count()
}
#[inline]
pub fn push(&mut self, segment: PathSegment<'_>) {
let (tag, number, name) = match segment {
PathSegment::Field(name) => (FIELD_TAG, name.len(), name),
PathSegment::Key(key) => (KEY_TAG, key.len(), key),
PathSegment::Variant(name) => (VARIANT_TAG, name.len(), name),
PathSegment::Item(index) => (ITEM_TAG, index, ""),
};
self.encoded.push(tag);
push_number(&mut self.encoded, number);
self.encoded.push_str(name);
}
#[inline]
pub fn iter(&self) -> OwnedPathIter<'_> {
OwnedPathIter {
rest: &self.encoded,
}
}
}
fn encoded_len(segment: &PathSegment<'_>) -> usize {
let (number, name_len) = match segment {
PathSegment::Field(name) | PathSegment::Variant(name) | PathSegment::Key(name) => {
(name.len(), name.len())
}
PathSegment::Item(index) => (*index, 0),
};
1 + number_len(number) + name_len
}
const FIELD_TAG: char = '0';
const KEY_TAG: char = '1';
const VARIANT_TAG: char = '2';
const ITEM_TAG: char = '3';
const NUMBER_BITS: u32 = 6;
const NUMBER_MASK: u8 = 0x3F;
const NUMBER_CONTINUE: u8 = 0x40;
fn number_len(mut number: usize) -> usize {
let mut len = 1;
while number > usize::from(NUMBER_MASK) {
number >>= NUMBER_BITS;
len += 1;
}
len
}
fn push_number(encoded: &mut String, mut number: usize) {
loop {
let group = number as u8 & NUMBER_MASK;
number >>= NUMBER_BITS;
if number == 0 {
encoded.push(char::from(group));
return;
}
encoded.push(char::from(group | NUMBER_CONTINUE));
}
}
impl fmt::Debug for OwnedPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}
impl<'a> From<&[PathSegment<'a>]> for OwnedPath {
fn from(segments: &[PathSegment<'a>]) -> Self {
let capacity = segments.iter().map(encoded_len).sum();
let mut path = Self {
encoded: String::with_capacity(capacity),
};
for &segment in segments {
path.push(segment);
}
path
}
}
impl<'a> FromIterator<PathSegment<'a>> for OwnedPath {
fn from_iter<I: IntoIterator<Item = PathSegment<'a>>>(segments: I) -> Self {
let mut path = Self::new();
path.extend(segments);
path
}
}
impl<'a> Extend<PathSegment<'a>> for OwnedPath {
fn extend<I: IntoIterator<Item = PathSegment<'a>>>(&mut self, segments: I) {
for segment in segments {
self.push(segment);
}
}
}
impl<'a> IntoIterator for &'a OwnedPath {
type Item = PathSegment<'a>;
type IntoIter = OwnedPathIter<'a>;
fn into_iter(self) -> OwnedPathIter<'a> {
self.iter()
}
}
#[derive(Clone, Debug)]
pub struct OwnedPathIter<'a> {
rest: &'a str,
}
#[cold]
#[inline(never)]
fn split_variant(rest: &str, start: usize, len: usize) -> (PathSegment<'_>, &str) {
let end = start + len;
(PathSegment::Variant(&rest[start..end]), &rest[end..])
}
impl<'a> Iterator for OwnedPathIter<'a> {
type Item = PathSegment<'a>;
#[inline(always)]
fn next(&mut self) -> Option<PathSegment<'a>> {
let bytes = self.rest.as_bytes();
let tag = *bytes.first()?;
let mut number = 0_usize;
let mut shift = 0;
let mut position = 1;
loop {
let byte = bytes[position];
position += 1;
number |= usize::from(byte & NUMBER_MASK) << shift;
if byte & NUMBER_CONTINUE == 0 {
break;
}
shift += NUMBER_BITS;
}
let start = position;
if tag >= VARIANT_TAG as u8 {
if tag == ITEM_TAG as u8 {
self.rest = &self.rest[start..];
return Some(PathSegment::Item(number));
}
let (segment, rest) = split_variant(self.rest, start, number);
self.rest = rest;
return Some(segment);
}
let end = start + number;
let name = &self.rest[start..end];
self.rest = &self.rest[end..];
Some(if tag == FIELD_TAG as u8 {
PathSegment::Field(name)
} else {
PathSegment::Key(name)
})
}
}
pub struct TypedPath<'k, Root, Value> {
segments: Vec<PathSegment<'k>>,
marker: PhantomData<fn() -> (Root, Value)>,
}
#[derive(Clone, Copy)]
pub struct TypedField<Parent, Value> {
name: &'static str,
segments: Option<&'static [PathSegment<'static>]>,
marker: PhantomData<fn() -> (Parent, Value)>,
}
pub trait TypedSequence {
type Item;
}
impl<Item> TypedSequence for Vec<Item> {
type Item = Item;
}
impl<Item, const LENGTH: usize> TypedSequence for [Item; LENGTH] {
type Item = Item;
}
impl<Item> TypedSequence for VecDeque<Item> {
type Item = Item;
}
impl<Item> TypedSequence for LinkedList<Item> {
type Item = Item;
}
pub trait TypedMap {
type Value;
}
impl<Value> TypedMap for BTreeMap<String, Value> {
type Value = Value;
}
impl<Value> TypedMap for BTreeMap<&'static str, Value> {
type Value = Value;
}
#[cfg(feature = "std")]
impl<Value, State> TypedMap for std::collections::HashMap<String, Value, State> {
type Value = Value;
}
#[cfg(feature = "std")]
impl<Value, State> TypedMap for std::collections::HashMap<&'static str, Value, State> {
type Value = Value;
}
impl<Parent, Value> TypedField<Parent, Value> {
pub const fn new(name: &'static str) -> Self {
TypedField {
name,
segments: None,
marker: PhantomData,
}
}
#[doc(hidden)]
pub const fn from_segments(segments: &'static [PathSegment<'static>]) -> Self {
TypedField {
name: "",
segments: Some(segments),
marker: PhantomData,
}
}
pub fn then<Next>(self, next: TypedField<Value, Next>) -> TypedPath<'static, Parent, Next> {
TypedPath::root().then(self).then(next)
}
pub fn path(self) -> TypedPath<'static, Parent, Value> {
TypedPath::root().then(self)
}
}
impl<Parent, Sequence> TypedField<Parent, Sequence>
where
Sequence: TypedSequence,
{
pub fn item(self, index: usize) -> TypedPath<'static, Parent, Sequence::Item> {
self.path().item(index)
}
}
impl<Parent, Map> TypedField<Parent, Map>
where
Map: TypedMap,
{
pub fn key(self, key: &str) -> TypedPath<'_, Parent, Map::Value> {
self.path().key(key)
}
}
impl<'k, Root, Value> TypedPath<'k, Root, Value> {
pub fn then<Next>(mut self, field: TypedField<Value, Next>) -> TypedPath<'k, Root, Next> {
if let Some(segments) = field.segments {
self.segments.extend_from_slice(segments);
} else {
self.segments.push(PathSegment::Field(field.name));
}
TypedPath {
segments: self.segments,
marker: PhantomData,
}
}
pub fn segments(&self) -> &[PathSegment<'k>] {
&self.segments
}
}
impl<'k, Root, Sequence> TypedPath<'k, Root, Sequence>
where
Sequence: TypedSequence,
{
pub fn item(mut self, index: usize) -> TypedPath<'k, Root, Sequence::Item> {
self.segments.push(PathSegment::Item(index));
TypedPath {
segments: self.segments,
marker: PhantomData,
}
}
}
impl<'k, Root, Map> TypedPath<'k, Root, Map>
where
Map: TypedMap,
{
pub fn key(mut self, key: &'k str) -> TypedPath<'k, Root, Map::Value> {
self.segments.push(PathSegment::Key(key));
TypedPath {
segments: self.segments,
marker: PhantomData,
}
}
}
impl<Root> TypedPath<'_, Root, Root> {
pub fn root() -> Self {
TypedPath {
segments: Vec::new(),
marker: PhantomData,
}
}
}
impl<'k, Root, Value> IntoIterator for TypedPath<'k, Root, Value> {
type Item = PathSegment<'k>;
type IntoIter = alloc::vec::IntoIter<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
self.segments.into_iter()
}
}
impl<'a, 'k, Root, Value> IntoIterator for &'a TypedPath<'k, Root, Value> {
type Item = PathSegment<'k>;
type IntoIter = core::iter::Copied<core::slice::Iter<'a, Self::Item>>;
fn into_iter(self) -> Self::IntoIter {
self.segments.iter().copied()
}
}
pub trait FieldPathQuery<'a> {
type Output;
#[doc(hidden)]
fn resolve(self, root: ObjectRef<'a>) -> Option<Self::Output>;
}
impl<'a, 'b, 'c> FieldPathQuery<'a> for &'b [PathSegment<'c>] {
type Output = ObjectRef<'a>;
#[inline]
fn resolve(self, root: ObjectRef<'a>) -> Option<Self::Output> {
let mut current = root;
for segment in self {
current = match segment {
PathSegment::Field(name) => current.field(name)?,
PathSegment::Variant(name) => current.variant(name)?,
PathSegment::Item(index) => current.item(*index)?,
PathSegment::Key(key) => current.key(key)?,
};
}
Some(current)
}
}
impl<'a, 'b, 'c, const N: usize> FieldPathQuery<'a> for &'b [PathSegment<'c>; N] {
type Output = ObjectRef<'a>;
fn resolve(self, root: ObjectRef<'a>) -> Option<Self::Output> {
FieldPathQuery::resolve(self.as_slice(), root)
}
}
impl<'a, Root, Value: 'static> FieldPathQuery<'a> for TypedPath<'_, Root, Value> {
type Output = &'a Value;
fn resolve(self, root: ObjectRef<'a>) -> Option<Self::Output> {
root.field_path(self.segments())?.to_ref::<Value>()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReflectiveError {
PathNotFound,
MutationTypeMismatch,
}
impl fmt::Display for ReflectiveError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::PathNotFound => write!(f, "Reflective path not found"),
Self::MutationTypeMismatch => {
write!(f, "The value has an incompatible concrete type")
}
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for ReflectiveError {}
pub trait FieldPathQueryMut<'r> {
type Output;
type Value;
#[doc(hidden)]
fn resolve(self, root: ObjectRefMut<'r>) -> Result<Self::Output, ReflectiveError>;
#[doc(hidden)]
fn assign(self, root: ObjectRefMut<'r>, value: Self::Value) -> Result<(), ReflectiveError>;
}
impl<'r, 'b, 'c> FieldPathQueryMut<'r> for &'b [PathSegment<'c>] {
type Output = ObjectRefMut<'r>;
type Value = Object;
#[inline]
fn resolve(self, root: ObjectRefMut<'r>) -> Result<Self::Output, ReflectiveError> {
ObjectRefMut::path_from(root.inner, self).ok_or(ReflectiveError::PathNotFound)
}
#[inline]
fn assign(self, root: ObjectRefMut<'r>, value: Object) -> Result<(), ReflectiveError> {
FieldPathQueryMut::resolve(self, root)?.set(value)
}
}
impl<'r, 'b, 'c, const N: usize> FieldPathQueryMut<'r> for &'b [PathSegment<'c>; N] {
type Output = ObjectRefMut<'r>;
type Value = Object;
fn resolve(self, root: ObjectRefMut<'r>) -> Result<Self::Output, ReflectiveError> {
FieldPathQueryMut::resolve(self.as_slice(), root)
}
fn assign(self, root: ObjectRefMut<'r>, value: Object) -> Result<(), ReflectiveError> {
FieldPathQueryMut::assign(self.as_slice(), root, value)
}
}
impl<'r, Root, Value: 'static> FieldPathQueryMut<'r> for TypedPath<'_, Root, Value> {
type Output = &'r mut Value;
type Value = Value;
fn resolve(self, root: ObjectRefMut<'r>) -> Result<Self::Output, ReflectiveError> {
ObjectRefMut::path_from(root.inner, self.segments())
.ok_or(ReflectiveError::PathNotFound)?
.to_mut::<Value>()
}
fn assign(self, root: ObjectRefMut<'r>, value: Value) -> Result<(), ReflectiveError> {
*FieldPathQueryMut::resolve(self, root)? = value;
Ok(())
}
}