mirror of
https://github.com/FyroxEngine/Fyrox.git
synced 2026-10-12 02:02:20 +00:00
continue splitting reflect module
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::reflect::{CastError, Reflect};
|
||||
use std::any::{Any, TypeId};
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// A value of a field..
|
||||
pub trait FieldValue: Any + 'static {
|
||||
/// Casts `self` to a `&dyn Any`
|
||||
fn field_value_as_any_ref(&self) -> &dyn Any;
|
||||
|
||||
/// Casts `self` to a `&mut dyn Any`
|
||||
fn field_value_as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
fn field_value_as_reflect(&self) -> &dyn Reflect;
|
||||
fn field_value_as_reflect_mut(&mut self) -> &mut dyn Reflect;
|
||||
|
||||
fn type_name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
impl<T: Reflect> FieldValue for T {
|
||||
fn field_value_as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn field_value_as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn field_value_as_reflect(&self) -> &dyn Reflect {
|
||||
self
|
||||
}
|
||||
|
||||
fn field_value_as_reflect_mut(&mut self) -> &mut dyn Reflect {
|
||||
self
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
std::any::type_name::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FieldMetadata<'s> {
|
||||
/// A name of the property.
|
||||
pub name: &'s str,
|
||||
|
||||
/// A human-readable name of the property.
|
||||
pub display_name: &'s str,
|
||||
|
||||
/// Tag of the property. Could be used to group properties by a certain criteria or to find a
|
||||
/// specific property by its tag.
|
||||
pub tag: &'s str,
|
||||
|
||||
/// Doc comment content.
|
||||
pub doc: &'s str,
|
||||
|
||||
/// A property is not meant to be edited.
|
||||
pub read_only: bool,
|
||||
|
||||
/// Only for dynamic collections (Vec, etc) - means that its size cannot be changed, however the
|
||||
/// _items_ of the collection can still be changed.
|
||||
pub immutable_collection: bool,
|
||||
|
||||
/// A minimal value of the property. Works only with numeric properties!
|
||||
pub min_value: Option<f64>,
|
||||
|
||||
/// A minimal value of the property. Works only with numeric properties!
|
||||
pub max_value: Option<f64>,
|
||||
|
||||
/// A minimal value of the property. Works only with numeric properties!
|
||||
pub step: Option<f64>,
|
||||
|
||||
/// Maximum amount of decimal places for a numeric property.
|
||||
pub precision: Option<usize>,
|
||||
}
|
||||
|
||||
pub struct FieldRef<'a, 'b> {
|
||||
/// A reference to field's metadata.
|
||||
pub metadata: &'a FieldMetadata<'b>,
|
||||
|
||||
/// An reference to the actual value of the property. This is "non-mangled" reference, which
|
||||
/// means that while `field/fields/field_mut/fields_mut` might return a reference to other value,
|
||||
/// than the actual field, the `value` is guaranteed to be a reference to the real value.
|
||||
pub value: &'a dyn FieldValue,
|
||||
}
|
||||
|
||||
impl<'b> Deref for FieldRef<'_, 'b> {
|
||||
type Target = FieldMetadata<'b>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldRef<'_, '_> {
|
||||
/// Tries to cast a value to a given type.
|
||||
pub fn cast_value<T: 'static>(&self) -> Result<&T, CastError> {
|
||||
match self.value.field_value_as_any_ref().downcast_ref::<T>() {
|
||||
Some(value) => Ok(value),
|
||||
None => Err(CastError::TypeMismatch {
|
||||
property_name: self.metadata.name.to_string(),
|
||||
expected_type_id: TypeId::of::<T>(),
|
||||
actual_type_id: self.value.type_id(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FieldRef<'_, '_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("FieldInfo")
|
||||
.field("metadata", &self.metadata)
|
||||
.field("value", &format_args!("{:?}", self.value as *const _))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Self> for FieldRef<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let value_ptr_a = self.value as *const _ as *const ();
|
||||
let value_ptr_b = other.value as *const _ as *const ();
|
||||
|
||||
std::ptr::eq(value_ptr_a, value_ptr_b)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldMut<'a, 'b> {
|
||||
/// A reference to field's metadata.
|
||||
pub metadata: &'a FieldMetadata<'b>,
|
||||
|
||||
/// An reference to the actual value of the property. This is "non-mangled" reference, which
|
||||
/// means that while `field/fields/field_mut/fields_mut` might return a reference to other value,
|
||||
/// than the actual field, the `value` is guaranteed to be a reference to the real value.
|
||||
pub value: &'a mut dyn FieldValue,
|
||||
}
|
||||
|
||||
impl<'b> Deref for FieldMut<'_, 'b> {
|
||||
type Target = FieldMetadata<'b>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FieldMut<'_, '_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("FieldInfo")
|
||||
.field("metadata", &self.metadata)
|
||||
.field("value", &format_args!("{:?}", self.value as *const _))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Self> for FieldMut<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let value_ptr_a = self.value as *const _ as *const ();
|
||||
let value_ptr_b = other.value as *const _ as *const ();
|
||||
|
||||
std::ptr::eq(value_ptr_a, value_ptr_b)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::pool::ErasedHandle;
|
||||
use crate::reflect::Reflect;
|
||||
use std::any::TypeId;
|
||||
|
||||
pub trait ReflectHandle: Reflect {
|
||||
fn reflect_inner_type_id(&self) -> TypeId;
|
||||
fn reflect_inner_type_name(&self) -> &'static str;
|
||||
fn reflect_is_some(&self) -> bool;
|
||||
fn reflect_set_index(&mut self, index: u32);
|
||||
fn reflect_index(&self) -> u32;
|
||||
fn reflect_set_generation(&mut self, generation: u32);
|
||||
fn reflect_generation(&self) -> u32;
|
||||
fn reflect_as_erased(&self) -> ErasedHandle;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
use crate::reflect::Reflect;
|
||||
use crate::variable::{InheritError, VariableFlags};
|
||||
use std::any::TypeId;
|
||||
|
||||
pub trait ReflectInheritableVariable: Reflect {
|
||||
/// Tries to inherit a value from parent. It will succeed only if the current variable is
|
||||
/// not marked as modified.
|
||||
fn try_inherit(
|
||||
&mut self,
|
||||
parent: &dyn ReflectInheritableVariable,
|
||||
ignored_types: &[TypeId],
|
||||
) -> Result<Option<Box<dyn Reflect>>, InheritError>;
|
||||
|
||||
/// Resets modified flag from the variable.
|
||||
fn reset_modified_flag(&mut self);
|
||||
|
||||
/// Returns current variable flags.
|
||||
fn flags(&self) -> VariableFlags;
|
||||
|
||||
fn set_flags(&mut self, flags: VariableFlags);
|
||||
|
||||
/// Returns true if value was modified.
|
||||
fn is_modified(&self) -> bool;
|
||||
|
||||
/// Returns true if value equals to other's value.
|
||||
fn value_equals(&self, other: &dyn ReflectInheritableVariable) -> bool;
|
||||
|
||||
/// Clones self value.
|
||||
fn clone_value_box(&self) -> Box<dyn Reflect>;
|
||||
|
||||
/// Marks value as modified, so its value won't be overwritten during property inheritance.
|
||||
fn mark_modified(&mut self);
|
||||
|
||||
/// Returns a mutable reference to wrapped value without marking the variable itself as modified.
|
||||
fn inner_value_mut(&mut self) -> &mut dyn Reflect;
|
||||
|
||||
/// Returns a shared reference to wrapped value without marking the variable itself as modified.
|
||||
fn inner_value_ref(&self) -> &dyn Reflect;
|
||||
}
|
||||
+321
-524
@@ -23,26 +23,27 @@
|
||||
mod array;
|
||||
mod error;
|
||||
mod external_impls;
|
||||
mod field;
|
||||
mod handle;
|
||||
mod inherit;
|
||||
mod macros;
|
||||
mod map;
|
||||
mod std_impls;
|
||||
|
||||
use crate::{
|
||||
pool::ErasedHandle,
|
||||
sstorage::ImmutableString,
|
||||
variable::{InheritError, VariableFlags},
|
||||
};
|
||||
use crate::sstorage::ImmutableString;
|
||||
|
||||
pub use fyrox_core_derive::Reflect;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::{self, Debug},
|
||||
fmt::Debug,
|
||||
mem::ManuallyDrop,
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
pub use array::*;
|
||||
pub use error::*;
|
||||
pub use field::*;
|
||||
pub use handle::*;
|
||||
pub use inherit::*;
|
||||
pub use macros::*;
|
||||
pub use map::*;
|
||||
|
||||
@@ -53,163 +54,6 @@ pub mod prelude {
|
||||
};
|
||||
}
|
||||
|
||||
/// A value of a field..
|
||||
pub trait FieldValue: Any + 'static {
|
||||
/// Casts `self` to a `&dyn Any`
|
||||
fn field_value_as_any_ref(&self) -> &dyn Any;
|
||||
|
||||
/// Casts `self` to a `&mut dyn Any`
|
||||
fn field_value_as_any_mut(&mut self) -> &mut dyn Any;
|
||||
|
||||
fn field_value_as_reflect(&self) -> &dyn Reflect;
|
||||
fn field_value_as_reflect_mut(&mut self) -> &mut dyn Reflect;
|
||||
|
||||
fn type_name(&self) -> &'static str;
|
||||
}
|
||||
|
||||
impl<T: Reflect> FieldValue for T {
|
||||
fn field_value_as_any_ref(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn field_value_as_any_mut(&mut self) -> &mut dyn Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn field_value_as_reflect(&self) -> &dyn Reflect {
|
||||
self
|
||||
}
|
||||
|
||||
fn field_value_as_reflect_mut(&mut self) -> &mut dyn Reflect {
|
||||
self
|
||||
}
|
||||
|
||||
fn type_name(&self) -> &'static str {
|
||||
std::any::type_name::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FieldMetadata<'s> {
|
||||
/// A name of the property.
|
||||
pub name: &'s str,
|
||||
|
||||
/// A human-readable name of the property.
|
||||
pub display_name: &'s str,
|
||||
|
||||
/// Tag of the property. Could be used to group properties by a certain criteria or to find a
|
||||
/// specific property by its tag.
|
||||
pub tag: &'s str,
|
||||
|
||||
/// Doc comment content.
|
||||
pub doc: &'s str,
|
||||
|
||||
/// A property is not meant to be edited.
|
||||
pub read_only: bool,
|
||||
|
||||
/// Only for dynamic collections (Vec, etc) - means that its size cannot be changed, however the
|
||||
/// _items_ of the collection can still be changed.
|
||||
pub immutable_collection: bool,
|
||||
|
||||
/// A minimal value of the property. Works only with numeric properties!
|
||||
pub min_value: Option<f64>,
|
||||
|
||||
/// A minimal value of the property. Works only with numeric properties!
|
||||
pub max_value: Option<f64>,
|
||||
|
||||
/// A minimal value of the property. Works only with numeric properties!
|
||||
pub step: Option<f64>,
|
||||
|
||||
/// Maximum amount of decimal places for a numeric property.
|
||||
pub precision: Option<usize>,
|
||||
}
|
||||
|
||||
pub struct FieldRef<'a, 'b> {
|
||||
/// A reference to field's metadata.
|
||||
pub metadata: &'a FieldMetadata<'b>,
|
||||
|
||||
/// An reference to the actual value of the property. This is "non-mangled" reference, which
|
||||
/// means that while `field/fields/field_mut/fields_mut` might return a reference to other value,
|
||||
/// than the actual field, the `value` is guaranteed to be a reference to the real value.
|
||||
pub value: &'a dyn FieldValue,
|
||||
}
|
||||
|
||||
impl<'b> Deref for FieldRef<'_, 'b> {
|
||||
type Target = FieldMetadata<'b>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl FieldRef<'_, '_> {
|
||||
/// Tries to cast a value to a given type.
|
||||
pub fn cast_value<T: 'static>(&self) -> Result<&T, CastError> {
|
||||
match self.value.field_value_as_any_ref().downcast_ref::<T>() {
|
||||
Some(value) => Ok(value),
|
||||
None => Err(CastError::TypeMismatch {
|
||||
property_name: self.metadata.name.to_string(),
|
||||
expected_type_id: TypeId::of::<T>(),
|
||||
actual_type_id: self.value.type_id(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FieldRef<'_, '_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("FieldInfo")
|
||||
.field("metadata", &self.metadata)
|
||||
.field("value", &format_args!("{:?}", self.value as *const _))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Self> for FieldRef<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let value_ptr_a = self.value as *const _ as *const ();
|
||||
let value_ptr_b = other.value as *const _ as *const ();
|
||||
|
||||
std::ptr::eq(value_ptr_a, value_ptr_b)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FieldMut<'a, 'b> {
|
||||
/// A reference to field's metadata.
|
||||
pub metadata: &'a FieldMetadata<'b>,
|
||||
|
||||
/// An reference to the actual value of the property. This is "non-mangled" reference, which
|
||||
/// means that while `field/fields/field_mut/fields_mut` might return a reference to other value,
|
||||
/// than the actual field, the `value` is guaranteed to be a reference to the real value.
|
||||
pub value: &'a mut dyn FieldValue,
|
||||
}
|
||||
|
||||
impl<'b> Deref for FieldMut<'_, 'b> {
|
||||
type Target = FieldMetadata<'b>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for FieldMut<'_, '_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("FieldInfo")
|
||||
.field("metadata", &self.metadata)
|
||||
.field("value", &format_args!("{:?}", self.value as *const _))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Self> for FieldMut<'_, '_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let value_ptr_a = self.value as *const _ as *const ();
|
||||
let value_ptr_b = other.value as *const _ as *const ();
|
||||
|
||||
std::ptr::eq(value_ptr_a, value_ptr_b)
|
||||
}
|
||||
}
|
||||
|
||||
/// A trait for runtime reflection.
|
||||
///
|
||||
/// ## Code Generation
|
||||
@@ -408,366 +252,6 @@ pub trait Reflect: Any + Debug {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReflectHandle: Reflect {
|
||||
fn reflect_inner_type_id(&self) -> TypeId;
|
||||
fn reflect_inner_type_name(&self) -> &'static str;
|
||||
fn reflect_is_some(&self) -> bool;
|
||||
fn reflect_set_index(&mut self, index: u32);
|
||||
fn reflect_index(&self) -> u32;
|
||||
fn reflect_set_generation(&mut self, generation: u32);
|
||||
fn reflect_generation(&self) -> u32;
|
||||
fn reflect_as_erased(&self) -> ErasedHandle;
|
||||
}
|
||||
|
||||
pub trait ReflectInheritableVariable: Reflect {
|
||||
/// Tries to inherit a value from parent. It will succeed only if the current variable is
|
||||
/// not marked as modified.
|
||||
fn try_inherit(
|
||||
&mut self,
|
||||
parent: &dyn ReflectInheritableVariable,
|
||||
ignored_types: &[TypeId],
|
||||
) -> Result<Option<Box<dyn Reflect>>, InheritError>;
|
||||
|
||||
/// Resets modified flag from the variable.
|
||||
fn reset_modified_flag(&mut self);
|
||||
|
||||
/// Returns current variable flags.
|
||||
fn flags(&self) -> VariableFlags;
|
||||
|
||||
fn set_flags(&mut self, flags: VariableFlags);
|
||||
|
||||
/// Returns true if value was modified.
|
||||
fn is_modified(&self) -> bool;
|
||||
|
||||
/// Returns true if value equals to other's value.
|
||||
fn value_equals(&self, other: &dyn ReflectInheritableVariable) -> bool;
|
||||
|
||||
/// Clones self value.
|
||||
fn clone_value_box(&self) -> Box<dyn Reflect>;
|
||||
|
||||
/// Marks value as modified, so its value won't be overwritten during property inheritance.
|
||||
fn mark_modified(&mut self);
|
||||
|
||||
/// Returns a mutable reference to wrapped value without marking the variable itself as modified.
|
||||
fn inner_value_mut(&mut self) -> &mut dyn Reflect;
|
||||
|
||||
/// Returns a shared reference to wrapped value without marking the variable itself as modified.
|
||||
fn inner_value_ref(&self) -> &dyn Reflect;
|
||||
}
|
||||
|
||||
pub trait ResolvePath {
|
||||
fn resolve_path<'p>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
);
|
||||
|
||||
fn resolve_path_mut<'p>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
);
|
||||
|
||||
fn get_resolve_path<'p, T: Reflect>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&T, ReflectPathError<'p>>),
|
||||
) {
|
||||
self.resolve_path(path, &mut |resolve_result| {
|
||||
match resolve_result {
|
||||
Ok(value) => {
|
||||
value.downcast_ref(&mut |result| {
|
||||
match result {
|
||||
Some(value) => {
|
||||
func(Ok(value));
|
||||
}
|
||||
None => {
|
||||
func(Err(ReflectPathError::InvalidDowncast));
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
func(Err(err));
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn get_resolve_path_mut<'p, T: Reflect>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut T, ReflectPathError<'p>>),
|
||||
) {
|
||||
self.resolve_path_mut(path, &mut |result| match result {
|
||||
Ok(value) => value.downcast_mut(&mut |result| match result {
|
||||
Some(value) => func(Ok(value)),
|
||||
None => func(Err(ReflectPathError::InvalidDowncast)),
|
||||
}),
|
||||
Err(err) => func(Err(err)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Reflect> ResolvePath for T {
|
||||
fn resolve_path<'p>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
(self as &dyn Reflect).resolve_path(path, func)
|
||||
}
|
||||
|
||||
fn resolve_path_mut<'p>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
(self as &mut dyn Reflect).resolve_path_mut(path, func)
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits property path into individual components.
|
||||
pub fn path_to_components(path: &str) -> Vec<Component> {
|
||||
let mut components = Vec::new();
|
||||
let mut current_path = path;
|
||||
while let Ok((component, sub_path)) = Component::next(current_path) {
|
||||
if let Component::Field(field) = component {
|
||||
if field.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
current_path = sub_path;
|
||||
components.push(component);
|
||||
}
|
||||
components
|
||||
}
|
||||
|
||||
/// Helper methods over [`Reflect`] types
|
||||
pub trait GetField {
|
||||
fn get_field<T: 'static>(&self, name: &str, func: &mut dyn FnMut(Option<&T>));
|
||||
|
||||
fn get_field_mut<T: 'static>(&mut self, _name: &str, func: &mut dyn FnMut(Option<&mut T>));
|
||||
}
|
||||
|
||||
impl<R: Reflect> GetField for R {
|
||||
fn get_field<T: 'static>(&self, name: &str, func: &mut dyn FnMut(Option<&T>)) {
|
||||
self.field(name, &mut |field| match field {
|
||||
None => func(None),
|
||||
Some(reflect) => reflect.as_any(&mut |any| func(any.downcast_ref())),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_field_mut<T: 'static>(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut T>)) {
|
||||
self.field_mut(name, &mut |field| match field {
|
||||
None => func(None),
|
||||
Some(reflect) => reflect.as_any_mut(&mut |any| func(any.downcast_mut())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// impl dyn Trait
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// SAFETY: String usage is safe in immutable contexts only. Calling `ManuallyDrop::drop`
|
||||
// (running strings destructor) on the returned value will cause crash!
|
||||
unsafe fn make_fake_string_from_slice(string: &str) -> ManuallyDrop<String> {
|
||||
ManuallyDrop::new(String::from_utf8_unchecked(Vec::from_raw_parts(
|
||||
string.as_bytes().as_ptr() as *mut _,
|
||||
string.len(),
|
||||
string.len(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn try_fetch_by_str_path_ref(
|
||||
hash_map: &dyn ReflectHashMap,
|
||||
path: &str,
|
||||
func: &mut dyn FnMut(Option<&dyn Reflect>),
|
||||
) {
|
||||
// Create fake string here first, this is needed to avoid memory allocations..
|
||||
// SAFETY: We won't drop the fake string or mutate it.
|
||||
let fake_string_key = unsafe { make_fake_string_from_slice(path) };
|
||||
|
||||
hash_map.reflect_get(&*fake_string_key, &mut |result| match result {
|
||||
Some(value) => func(Some(value)),
|
||||
None => hash_map.reflect_get(&ImmutableString::new(path) as &dyn Reflect, func),
|
||||
});
|
||||
}
|
||||
|
||||
fn try_fetch_by_str_path_mut(
|
||||
hash_map: &mut dyn ReflectHashMap,
|
||||
path: &str,
|
||||
func: &mut dyn FnMut(Option<&mut dyn Reflect>),
|
||||
) {
|
||||
// Create fake string here first, this is needed to avoid memory allocations..
|
||||
// SAFETY: We won't drop the fake string or mutate it.
|
||||
let fake_string_key = unsafe { make_fake_string_from_slice(path) };
|
||||
|
||||
let mut succeeded = true;
|
||||
|
||||
hash_map.reflect_get_mut(&*fake_string_key, &mut |result| match result {
|
||||
Some(value) => func(Some(value)),
|
||||
None => succeeded = false,
|
||||
});
|
||||
|
||||
if !succeeded {
|
||||
hash_map.reflect_get_mut(&ImmutableString::new(path) as &dyn Reflect, func)
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple path parser / reflect path component
|
||||
pub enum Component<'p> {
|
||||
Field(&'p str),
|
||||
Index(&'p str),
|
||||
}
|
||||
|
||||
impl<'p> Component<'p> {
|
||||
fn next(mut path: &'p str) -> Result<(Self, &'p str), ReflectPathError<'p>> {
|
||||
// Discard the first comma:
|
||||
if path.bytes().next() == Some(b'.') {
|
||||
path = &path[1..];
|
||||
}
|
||||
|
||||
let mut bytes = path.bytes().enumerate();
|
||||
while let Some((i, b)) = bytes.next() {
|
||||
if b == b'.' {
|
||||
let (l, r) = path.split_at(i);
|
||||
return Ok((Self::Field(l), &r[1..]));
|
||||
}
|
||||
|
||||
if b == b'[' {
|
||||
if i != 0 {
|
||||
// delimit the field access
|
||||
let (l, r) = path.split_at(i);
|
||||
return Ok((Self::Field(l), r));
|
||||
}
|
||||
|
||||
// find ']'
|
||||
if let Some((end, _)) = bytes.find(|(_, b)| *b == b']') {
|
||||
let l = &path[1..end];
|
||||
let r = &path[end + 1..];
|
||||
return Ok((Self::Index(l), r));
|
||||
} else {
|
||||
return Err(ReflectPathError::UnclosedBrackets { s: path });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: the `path` can be empty
|
||||
Ok((Self::Field(path), ""))
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
reflect: &dyn Reflect,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match self {
|
||||
Self::Field(path) => reflect.field(path, &mut |field| {
|
||||
func(field.ok_or(ReflectPathError::UnknownField { s: path }))
|
||||
}),
|
||||
Self::Index(path) => {
|
||||
reflect.as_array(&mut |result| match result {
|
||||
Some(array) => match path.parse::<usize>() {
|
||||
Ok(index) => match array.reflect_index(index) {
|
||||
None => func(Err(ReflectPathError::NoItemForIndex { s: path })),
|
||||
Some(value) => func(Ok(value)),
|
||||
},
|
||||
Err(_) => func(Err(ReflectPathError::InvalidIndexSyntax { s: path })),
|
||||
},
|
||||
None => reflect.as_hash_map(&mut |result| match result {
|
||||
Some(hash_map) => {
|
||||
try_fetch_by_str_path_ref(hash_map, path, &mut |result| {
|
||||
func(result.ok_or(ReflectPathError::NoItemForIndex { s: path }))
|
||||
})
|
||||
}
|
||||
None => func(Err(ReflectPathError::NotAnArray)),
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_mut(
|
||||
&self,
|
||||
reflect: &mut dyn Reflect,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match self {
|
||||
Self::Field(path) => reflect.field_mut(path, &mut |field| {
|
||||
func(field.ok_or(ReflectPathError::UnknownField { s: path }))
|
||||
}),
|
||||
Self::Index(path) => {
|
||||
let mut succeeded = true;
|
||||
reflect.as_array_mut(&mut |array| match array {
|
||||
Some(list) => match path.parse::<usize>() {
|
||||
Ok(index) => match list.reflect_index_mut(index) {
|
||||
None => func(Err(ReflectPathError::NoItemForIndex { s: path })),
|
||||
Some(value) => func(Ok(value)),
|
||||
},
|
||||
Err(_) => func(Err(ReflectPathError::InvalidIndexSyntax { s: path })),
|
||||
},
|
||||
None => succeeded = false,
|
||||
});
|
||||
|
||||
if !succeeded {
|
||||
reflect.as_hash_map_mut(&mut |result| match result {
|
||||
Some(hash_map) => {
|
||||
try_fetch_by_str_path_mut(hash_map, path, &mut |result| {
|
||||
func(result.ok_or(ReflectPathError::NoItemForIndex { s: path }))
|
||||
})
|
||||
}
|
||||
None => func(Err(ReflectPathError::NotAnArray)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvePath for dyn Reflect {
|
||||
fn resolve_path<'p>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match Component::next(path) {
|
||||
Ok((component, r)) => component.resolve(self, &mut |result| match result {
|
||||
Ok(child) => {
|
||||
if r.is_empty() {
|
||||
func(Ok(child))
|
||||
} else {
|
||||
child.resolve_path(r, func)
|
||||
}
|
||||
}
|
||||
Err(err) => func(Err(err)),
|
||||
}),
|
||||
Err(err) => func(Err(err)),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_path_mut<'p>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match Component::next(path) {
|
||||
Ok((component, r)) => component.resolve_mut(self, &mut |result| match result {
|
||||
Ok(child) => {
|
||||
if r.is_empty() {
|
||||
func(Ok(child))
|
||||
} else {
|
||||
child.resolve_path_mut(r, func)
|
||||
}
|
||||
}
|
||||
Err(err) => func(Err(err)),
|
||||
}),
|
||||
Err(err) => func(Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Type-erased API
|
||||
impl dyn Reflect {
|
||||
pub fn downcast<T: Reflect>(self: Box<dyn Reflect>) -> Result<Box<T>, Box<dyn Reflect>> {
|
||||
@@ -1096,6 +580,319 @@ impl dyn Reflect {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ResolvePath {
|
||||
fn resolve_path<'p>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
);
|
||||
|
||||
fn resolve_path_mut<'p>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
);
|
||||
|
||||
fn get_resolve_path<'p, T: Reflect>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&T, ReflectPathError<'p>>),
|
||||
) {
|
||||
self.resolve_path(path, &mut |resolve_result| {
|
||||
match resolve_result {
|
||||
Ok(value) => {
|
||||
value.downcast_ref(&mut |result| {
|
||||
match result {
|
||||
Some(value) => {
|
||||
func(Ok(value));
|
||||
}
|
||||
None => {
|
||||
func(Err(ReflectPathError::InvalidDowncast));
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
Err(err) => {
|
||||
func(Err(err));
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn get_resolve_path_mut<'p, T: Reflect>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut T, ReflectPathError<'p>>),
|
||||
) {
|
||||
self.resolve_path_mut(path, &mut |result| match result {
|
||||
Ok(value) => value.downcast_mut(&mut |result| match result {
|
||||
Some(value) => func(Ok(value)),
|
||||
None => func(Err(ReflectPathError::InvalidDowncast)),
|
||||
}),
|
||||
Err(err) => func(Err(err)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Reflect> ResolvePath for T {
|
||||
fn resolve_path<'p>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
(self as &dyn Reflect).resolve_path(path, func)
|
||||
}
|
||||
|
||||
fn resolve_path_mut<'p>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
(self as &mut dyn Reflect).resolve_path_mut(path, func)
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits property path into individual components.
|
||||
pub fn path_to_components(path: &str) -> Vec<Component> {
|
||||
let mut components = Vec::new();
|
||||
let mut current_path = path;
|
||||
while let Ok((component, sub_path)) = Component::next(current_path) {
|
||||
if let Component::Field(field) = component {
|
||||
if field.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
current_path = sub_path;
|
||||
components.push(component);
|
||||
}
|
||||
components
|
||||
}
|
||||
|
||||
/// Helper methods over [`Reflect`] types
|
||||
pub trait GetField {
|
||||
fn get_field<T: 'static>(&self, name: &str, func: &mut dyn FnMut(Option<&T>));
|
||||
|
||||
fn get_field_mut<T: 'static>(&mut self, _name: &str, func: &mut dyn FnMut(Option<&mut T>));
|
||||
}
|
||||
|
||||
impl<R: Reflect> GetField for R {
|
||||
fn get_field<T: 'static>(&self, name: &str, func: &mut dyn FnMut(Option<&T>)) {
|
||||
self.field(name, &mut |field| match field {
|
||||
None => func(None),
|
||||
Some(reflect) => reflect.as_any(&mut |any| func(any.downcast_ref())),
|
||||
})
|
||||
}
|
||||
|
||||
fn get_field_mut<T: 'static>(&mut self, name: &str, func: &mut dyn FnMut(Option<&mut T>)) {
|
||||
self.field_mut(name, &mut |field| match field {
|
||||
None => func(None),
|
||||
Some(reflect) => reflect.as_any_mut(&mut |any| func(any.downcast_mut())),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// impl dyn Trait
|
||||
// --------------------------------------------------------------------------------
|
||||
|
||||
// SAFETY: String usage is safe in immutable contexts only. Calling `ManuallyDrop::drop`
|
||||
// (running strings destructor) on the returned value will cause crash!
|
||||
unsafe fn make_fake_string_from_slice(string: &str) -> ManuallyDrop<String> {
|
||||
ManuallyDrop::new(String::from_utf8_unchecked(Vec::from_raw_parts(
|
||||
string.as_bytes().as_ptr() as *mut _,
|
||||
string.len(),
|
||||
string.len(),
|
||||
)))
|
||||
}
|
||||
|
||||
fn try_fetch_by_str_path_ref(
|
||||
hash_map: &dyn ReflectHashMap,
|
||||
path: &str,
|
||||
func: &mut dyn FnMut(Option<&dyn Reflect>),
|
||||
) {
|
||||
// Create fake string here first, this is needed to avoid memory allocations..
|
||||
// SAFETY: We won't drop the fake string or mutate it.
|
||||
let fake_string_key = unsafe { make_fake_string_from_slice(path) };
|
||||
|
||||
hash_map.reflect_get(&*fake_string_key, &mut |result| match result {
|
||||
Some(value) => func(Some(value)),
|
||||
None => hash_map.reflect_get(&ImmutableString::new(path) as &dyn Reflect, func),
|
||||
});
|
||||
}
|
||||
|
||||
fn try_fetch_by_str_path_mut(
|
||||
hash_map: &mut dyn ReflectHashMap,
|
||||
path: &str,
|
||||
func: &mut dyn FnMut(Option<&mut dyn Reflect>),
|
||||
) {
|
||||
// Create fake string here first, this is needed to avoid memory allocations..
|
||||
// SAFETY: We won't drop the fake string or mutate it.
|
||||
let fake_string_key = unsafe { make_fake_string_from_slice(path) };
|
||||
|
||||
let mut succeeded = true;
|
||||
|
||||
hash_map.reflect_get_mut(&*fake_string_key, &mut |result| match result {
|
||||
Some(value) => func(Some(value)),
|
||||
None => succeeded = false,
|
||||
});
|
||||
|
||||
if !succeeded {
|
||||
hash_map.reflect_get_mut(&ImmutableString::new(path) as &dyn Reflect, func)
|
||||
}
|
||||
}
|
||||
|
||||
/// Simple path parser / reflect path component
|
||||
pub enum Component<'p> {
|
||||
Field(&'p str),
|
||||
Index(&'p str),
|
||||
}
|
||||
|
||||
impl<'p> Component<'p> {
|
||||
fn next(mut path: &'p str) -> Result<(Self, &'p str), ReflectPathError<'p>> {
|
||||
// Discard the first comma:
|
||||
if path.bytes().next() == Some(b'.') {
|
||||
path = &path[1..];
|
||||
}
|
||||
|
||||
let mut bytes = path.bytes().enumerate();
|
||||
while let Some((i, b)) = bytes.next() {
|
||||
if b == b'.' {
|
||||
let (l, r) = path.split_at(i);
|
||||
return Ok((Self::Field(l), &r[1..]));
|
||||
}
|
||||
|
||||
if b == b'[' {
|
||||
if i != 0 {
|
||||
// delimit the field access
|
||||
let (l, r) = path.split_at(i);
|
||||
return Ok((Self::Field(l), r));
|
||||
}
|
||||
|
||||
// find ']'
|
||||
if let Some((end, _)) = bytes.find(|(_, b)| *b == b']') {
|
||||
let l = &path[1..end];
|
||||
let r = &path[end + 1..];
|
||||
return Ok((Self::Index(l), r));
|
||||
} else {
|
||||
return Err(ReflectPathError::UnclosedBrackets { s: path });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: the `path` can be empty
|
||||
Ok((Self::Field(path), ""))
|
||||
}
|
||||
|
||||
fn resolve(
|
||||
&self,
|
||||
reflect: &dyn Reflect,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match self {
|
||||
Self::Field(path) => reflect.field(path, &mut |field| {
|
||||
func(field.ok_or(ReflectPathError::UnknownField { s: path }))
|
||||
}),
|
||||
Self::Index(path) => {
|
||||
reflect.as_array(&mut |result| match result {
|
||||
Some(array) => match path.parse::<usize>() {
|
||||
Ok(index) => match array.reflect_index(index) {
|
||||
None => func(Err(ReflectPathError::NoItemForIndex { s: path })),
|
||||
Some(value) => func(Ok(value)),
|
||||
},
|
||||
Err(_) => func(Err(ReflectPathError::InvalidIndexSyntax { s: path })),
|
||||
},
|
||||
None => reflect.as_hash_map(&mut |result| match result {
|
||||
Some(hash_map) => {
|
||||
try_fetch_by_str_path_ref(hash_map, path, &mut |result| {
|
||||
func(result.ok_or(ReflectPathError::NoItemForIndex { s: path }))
|
||||
})
|
||||
}
|
||||
None => func(Err(ReflectPathError::NotAnArray)),
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_mut(
|
||||
&self,
|
||||
reflect: &mut dyn Reflect,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match self {
|
||||
Self::Field(path) => reflect.field_mut(path, &mut |field| {
|
||||
func(field.ok_or(ReflectPathError::UnknownField { s: path }))
|
||||
}),
|
||||
Self::Index(path) => {
|
||||
let mut succeeded = true;
|
||||
reflect.as_array_mut(&mut |array| match array {
|
||||
Some(list) => match path.parse::<usize>() {
|
||||
Ok(index) => match list.reflect_index_mut(index) {
|
||||
None => func(Err(ReflectPathError::NoItemForIndex { s: path })),
|
||||
Some(value) => func(Ok(value)),
|
||||
},
|
||||
Err(_) => func(Err(ReflectPathError::InvalidIndexSyntax { s: path })),
|
||||
},
|
||||
None => succeeded = false,
|
||||
});
|
||||
|
||||
if !succeeded {
|
||||
reflect.as_hash_map_mut(&mut |result| match result {
|
||||
Some(hash_map) => {
|
||||
try_fetch_by_str_path_mut(hash_map, path, &mut |result| {
|
||||
func(result.ok_or(ReflectPathError::NoItemForIndex { s: path }))
|
||||
})
|
||||
}
|
||||
None => func(Err(ReflectPathError::NotAnArray)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ResolvePath for dyn Reflect {
|
||||
fn resolve_path<'p>(
|
||||
&self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match Component::next(path) {
|
||||
Ok((component, r)) => component.resolve(self, &mut |result| match result {
|
||||
Ok(child) => {
|
||||
if r.is_empty() {
|
||||
func(Ok(child))
|
||||
} else {
|
||||
child.resolve_path(r, func)
|
||||
}
|
||||
}
|
||||
Err(err) => func(Err(err)),
|
||||
}),
|
||||
Err(err) => func(Err(err)),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_path_mut<'p>(
|
||||
&mut self,
|
||||
path: &'p str,
|
||||
func: &mut dyn FnMut(Result<&mut dyn Reflect, ReflectPathError<'p>>),
|
||||
) {
|
||||
match Component::next(path) {
|
||||
Ok((component, r)) => component.resolve_mut(self, &mut |result| match result {
|
||||
Ok(child) => {
|
||||
if r.is_empty() {
|
||||
func(Ok(child))
|
||||
} else {
|
||||
child.resolve_path_mut(r, func)
|
||||
}
|
||||
}
|
||||
Err(err) => func(Err(err)),
|
||||
}),
|
||||
Err(err) => func(Err(err)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_path_to_array_element(path: &str) -> bool {
|
||||
path.ends_with(']')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user