use alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use core::iter::FusedIterator;
use core::iter::Peekable;
use crate::enum_::VariantKind;
use crate::type_info::TypeAtPath;
use crate::Reflect;
use crate::ReflectMut;
use crate::ReflectRef;
use crate::Value;
pub trait GetPath {
fn at(&self, key_path: &KeyPath) -> Option<&dyn Reflect>;
fn get_at<T>(&self, key_path: &KeyPath) -> Option<&T>
where
T: Reflect,
{
self.at(key_path)?.downcast_ref()
}
fn at_mut(&mut self, key_path: &KeyPath) -> Option<&mut dyn Reflect>;
fn get_at_mut<T>(&mut self, key_path: &KeyPath) -> Option<&mut T>
where
T: Reflect,
{
self.at_mut(key_path)?.downcast_mut()
}
}
pub trait GetTypePath<'a> {
fn type_at(self, key_path: &KeyPath) -> Option<TypeAtPath<'a>>;
}
impl<R> GetPath for R
where
R: Reflect + ?Sized,
{
fn at(&self, key_path: &KeyPath) -> Option<&dyn Reflect> {
fn go<'a, 'b, R>(
value: &'a R,
mut stack: Peekable<impl Iterator<Item = &'b Key>>,
) -> Option<&'a dyn Reflect>
where
R: Reflect + ?Sized,
{
let head = stack.next()?;
let value_at_key = match head {
Key::Field(NamedOrNumbered::Named(key)) => match value.reflect_ref() {
ReflectRef::Struct(inner) => inner.field(key)?,
ReflectRef::Enum(inner) => match inner.variant_kind() {
VariantKind::Struct => inner.field(key)?,
VariantKind::Tuple | VariantKind::Unit => return None,
},
ReflectRef::TupleStruct(_)
| ReflectRef::Tuple(_)
| ReflectRef::Array(_)
| ReflectRef::List(_)
| ReflectRef::Map(_)
| ReflectRef::Scalar(_)
| ReflectRef::Opaque(_) => return None,
},
Key::Field(NamedOrNumbered::Numbered(index)) => match value.reflect_ref() {
ReflectRef::TupleStruct(inner) => inner.field_at(*index)?,
ReflectRef::Tuple(inner) => inner.field_at(*index)?,
ReflectRef::Enum(inner) => match inner.variant_kind() {
VariantKind::Tuple => inner.field_at(*index)?,
VariantKind::Struct | VariantKind::Unit => return None,
},
ReflectRef::Map(_)
| ReflectRef::Struct(_)
| ReflectRef::Array(_)
| ReflectRef::List(_)
| ReflectRef::Scalar(_)
| ReflectRef::Opaque(_) => return None,
},
Key::Get(key) => match value.reflect_ref() {
ReflectRef::Map(inner) => inner.get(key)?,
ReflectRef::Array(inner) => inner.get(value_to_usize(key)?)?,
ReflectRef::List(inner) => inner.get(value_to_usize(key)?)?,
ReflectRef::Struct(_)
| ReflectRef::TupleStruct(_)
| ReflectRef::Tuple(_)
| ReflectRef::Enum(_)
| ReflectRef::Scalar(_)
| ReflectRef::Opaque(_) => return None,
},
Key::Variant(variant) => match value.reflect_ref() {
ReflectRef::Enum(enum_) => {
if enum_.variant_name() == variant {
enum_.as_reflect()
} else {
return None;
}
}
ReflectRef::Struct(_)
| ReflectRef::TupleStruct(_)
| ReflectRef::Tuple(_)
| ReflectRef::List(_)
| ReflectRef::Array(_)
| ReflectRef::Map(_)
| ReflectRef::Opaque(_)
| ReflectRef::Scalar(_) => return None,
},
};
if stack.peek().is_none() {
Some(value_at_key)
} else {
go(value_at_key, stack)
}
}
if key_path.is_empty() {
return Some(self.as_reflect());
}
go(self, key_path.path.iter().peekable())
}
fn at_mut(&mut self, key_path: &KeyPath) -> Option<&mut dyn Reflect> {
fn go<'a, 'b, R>(
value: &'a mut R,
mut stack: Peekable<impl Iterator<Item = &'b Key>>,
) -> Option<&'a mut dyn Reflect>
where
R: Reflect + ?Sized,
{
let head = stack.next()?;
let value_at_key = match head {
Key::Field(NamedOrNumbered::Named(key)) => match value.reflect_mut() {
ReflectMut::Struct(inner) => inner.field_mut(key)?,
ReflectMut::Enum(inner) => match inner.variant_kind() {
VariantKind::Struct => inner.field_mut(key)?,
VariantKind::Tuple | VariantKind::Unit => return None,
},
ReflectMut::TupleStruct(_)
| ReflectMut::Tuple(_)
| ReflectMut::Array(_)
| ReflectMut::List(_)
| ReflectMut::Map(_)
| ReflectMut::Scalar(_)
| ReflectMut::Opaque(_) => return None,
},
Key::Field(NamedOrNumbered::Numbered(index)) => match value.reflect_mut() {
ReflectMut::TupleStruct(inner) => inner.field_at_mut(*index)?,
ReflectMut::Tuple(inner) => inner.field_at_mut(*index)?,
ReflectMut::Enum(inner) => match inner.variant_kind() {
VariantKind::Tuple => inner.field_at_mut(*index)?,
VariantKind::Struct | VariantKind::Unit => return None,
},
ReflectMut::Map(_)
| ReflectMut::Struct(_)
| ReflectMut::Array(_)
| ReflectMut::List(_)
| ReflectMut::Scalar(_)
| ReflectMut::Opaque(_) => return None,
},
Key::Get(key) => match value.reflect_mut() {
ReflectMut::Array(inner) => inner.get_mut(value_to_usize(key)?)?,
ReflectMut::List(inner) => inner.get_mut(value_to_usize(key)?)?,
ReflectMut::Map(inner) => inner.get_mut(key)?,
ReflectMut::Struct(_)
| ReflectMut::TupleStruct(_)
| ReflectMut::Tuple(_)
| ReflectMut::Enum(_)
| ReflectMut::Scalar(_)
| ReflectMut::Opaque(_) => return None,
},
Key::Variant(variant) => match value.reflect_mut() {
ReflectMut::Enum(enum_) => {
if enum_.variant_name() == variant {
enum_.as_reflect_mut()
} else {
return None;
}
}
ReflectMut::Struct(_)
| ReflectMut::TupleStruct(_)
| ReflectMut::Tuple(_)
| ReflectMut::List(_)
| ReflectMut::Array(_)
| ReflectMut::Map(_)
| ReflectMut::Opaque(_)
| ReflectMut::Scalar(_) => return None,
},
};
if stack.peek().is_none() {
Some(value_at_key)
} else {
go(value_at_key, stack)
}
}
if key_path.is_empty() {
return Some(self.as_reflect_mut());
}
go(self, key_path.path.iter().peekable())
}
}
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct KeyPath {
pub(crate) path: Vec<Key>,
}
impl KeyPath {
pub fn field(mut self, field: impl IntoKeyOrIndex) -> Self {
self.push_field(field);
self
}
pub fn push_field(&mut self, field: impl IntoKeyOrIndex) {
self.push(Key::Field(field.into_key_or_index()));
}
pub fn get(mut self, field: impl Into<Value>) -> Self {
self.push_get(field);
self
}
pub fn push_get(&mut self, field: impl Into<Value>) {
self.push(Key::Get(field.into()))
}
pub fn variant(mut self, variant: impl Into<String>) -> Self {
self.push_variant(variant);
self
}
pub fn push_variant(&mut self, variant: impl Into<String>) {
self.push(Key::Variant(variant.into()));
}
pub fn push(&mut self, key: Key) {
self.path.push(key);
}
pub fn len(&self) -> usize {
self.path.len()
}
pub fn is_empty(&self) -> bool {
self.path.is_empty()
}
pub fn pop(&mut self) {
self.path.pop();
}
pub fn iter(&self) -> Iter<'_> {
self.into_iter()
}
pub fn breadcrumbs(&self) -> Breadcrumbs<'_> {
Breadcrumbs {
key_path: self,
index: 1,
}
}
}
impl From<Key> for KeyPath {
fn from(key: Key) -> Self {
let mut key_path = KeyPath::default();
key_path.push(key);
key_path
}
}
impl Extend<Key> for KeyPath {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = Key>,
{
self.path.extend(iter);
}
}
impl IntoIterator for KeyPath {
type Item = Key;
type IntoIter = IntoIter;
fn into_iter(self) -> Self::IntoIter {
IntoIter(self.path.into_iter())
}
}
#[derive(Debug)]
pub struct IntoIter(alloc::vec::IntoIter<Key>);
impl Iterator for IntoIter {
type Item = Key;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl DoubleEndedIterator for IntoIter {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl ExactSizeIterator for IntoIter {
fn len(&self) -> usize {
self.0.len()
}
}
impl FusedIterator for IntoIter {}
impl<'a> IntoIterator for &'a KeyPath {
type Item = &'a Key;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Self::IntoIter {
Iter(self.path.iter())
}
}
#[derive(Debug)]
pub struct Iter<'a>(alloc::slice::Iter<'a, Key>);
impl<'a> Iterator for Iter<'a> {
type Item = &'a Key;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}
impl<'a> DoubleEndedIterator for Iter<'a> {
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<'a> ExactSizeIterator for Iter<'a> {
fn len(&self) -> usize {
self.0.len()
}
}
impl<'a> FusedIterator for Iter<'a> {}
mod private {
use super::*;
pub trait Sealed {}
impl Sealed for &str {}
impl Sealed for &String {}
impl Sealed for String {}
impl Sealed for usize {}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Key {
Field(NamedOrNumbered),
Get(Value),
Variant(String),
}
impl Key {
pub fn named_field(name: impl Into<String>) -> Self {
Self::Field(NamedOrNumbered::Named(name.into()))
}
pub fn numbered_field(index: usize) -> Self {
Self::Field(NamedOrNumbered::Numbered(index))
}
pub fn get(value: impl Into<Value>) -> Self {
Self::Get(value.into())
}
pub fn variant(name: impl Into<String>) -> Self {
Self::Variant(name.into())
}
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Key::Field(key) => write!(f, "{key}"),
Key::Get(value) => write!(f, "[{:?}]", value.as_reflect()),
Key::Variant(variant) => write!(f, "::{variant}"),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "speedy", derive(speedy::Readable, speedy::Writable))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NamedOrNumbered {
Named(String),
Numbered(usize),
}
impl fmt::Display for NamedOrNumbered {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NamedOrNumbered::Named(field) => write!(f, ".{field}"),
NamedOrNumbered::Numbered(index) => write!(f, ".{index}"),
}
}
}
pub trait IntoKeyOrIndex: private::Sealed {
fn into_key_or_index(self) -> NamedOrNumbered;
}
impl IntoKeyOrIndex for &str {
fn into_key_or_index(self) -> NamedOrNumbered {
NamedOrNumbered::Named(self.to_owned())
}
}
impl IntoKeyOrIndex for &String {
fn into_key_or_index(self) -> NamedOrNumbered {
NamedOrNumbered::Named(self.to_owned())
}
}
impl IntoKeyOrIndex for String {
fn into_key_or_index(self) -> NamedOrNumbered {
NamedOrNumbered::Named(self)
}
}
impl IntoKeyOrIndex for usize {
fn into_key_or_index(self) -> NamedOrNumbered {
NamedOrNumbered::Numbered(self)
}
}
pub fn field(field: impl IntoKeyOrIndex) -> KeyPath {
KeyPath::default().field(field)
}
pub fn get(field: impl Into<Value>) -> KeyPath {
KeyPath::default().get(field)
}
pub fn variant(variant: impl Into<String>) -> KeyPath {
KeyPath::default().variant(variant)
}
#[macro_export]
macro_rules! key_path {
(
@go:
$path:expr,
[],
) => {
$path
};
(
@go:
$path:expr,
[ . $field:ident $($tt:tt)*],
) => {
$crate::key_path!(
@go:
$path.field(stringify!($field)),
[$($tt)*],
)
};
(
@go:
$path:expr,
[ . $field:literal $($tt:tt)*],
) => {
$crate::key_path!(
@go:
$path.field($field),
[$($tt)*],
)
};
(
@go:
$path:expr,
[ [$field:expr] $($tt:tt)*],
) => {
$crate::key_path!(
@go:
$path.get($field),
[$($tt)*],
)
};
(
@go:
$path:expr,
[ :: $variant:ident $($tt:tt)*],
) => {
$crate::key_path!(
@go:
$path.variant(stringify!($variant)),
[$($tt)*],
)
};
(
@go:
$path:expr,
[$($tt:tt)*],
) => {
compile_error!(concat!("Unexpected tokens ", stringify!($($tt)*)))
};
( $($tt:tt)* ) => {
$crate::key_path!(
@go:
$crate::key_path::KeyPath::default(),
[$($tt)*],
)
};
}
impl fmt::Display for KeyPath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for key in &self.path {
write!(f, "{key}")?;
}
Ok(())
}
}
pub(crate) fn value_to_usize(value: &Value) -> Option<usize> {
match value {
Value::usize(n) => Some(*n),
Value::u8(n) => Some(*n as usize),
Value::u16(n) => Some(*n as usize),
Value::u32(n) => Some(*n as usize),
Value::u64(n) => Some(*n as usize),
Value::u128(n) => Some(*n as usize),
Value::i8(n) => Some(*n as usize),
Value::i16(n) => Some(*n as usize),
Value::i32(n) => Some(*n as usize),
Value::i64(n) => Some(*n as usize),
Value::i128(n) => Some(*n as usize),
Value::bool(_)
| Value::char(_)
| Value::f32(_)
| Value::f64(_)
| Value::String(_)
| Value::StructValue(_)
| Value::EnumValue(_)
| Value::TupleStructValue(_)
| Value::TupleValue(_)
| Value::List(_)
| Value::Map(_) => None,
}
}
impl FromIterator<Key> for KeyPath {
fn from_iter<T>(iter: T) -> Self
where
T: IntoIterator<Item = Key>,
{
Self {
path: Vec::from_iter(iter),
}
}
}
#[derive(Debug)]
pub struct Breadcrumbs<'a> {
key_path: &'a KeyPath,
index: usize,
}
impl<'a> Iterator for Breadcrumbs<'a> {
type Item = &'a [Key];
fn next(&mut self) -> Option<Self::Item> {
let keys = self.key_path.path.get(0..self.index)?;
self.index += 1;
Some(keys)
}
}