mirror of
https://github.com/bevyengine/bevy
synced 2024-12-21 02:23:08 +00:00
Add and clean up internal representation
This commit is contained in:
parent
45803de41b
commit
0a50c2a0cb
4 changed files with 242 additions and 210 deletions
|
@ -2,9 +2,9 @@ use crate::{
|
|||
self as bevy_reflect,
|
||||
__macro_exports::RegisterForReflection,
|
||||
func::{
|
||||
args::ArgList, function_map::FunctionMap, info::FunctionInfoType,
|
||||
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionError,
|
||||
FunctionOverloadError, FunctionResult, IntoFunction, IntoFunctionMut,
|
||||
args::ArgList, dynamic_function_internal::DynamicFunctionInternal, info::FunctionInfoType,
|
||||
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionOverloadError,
|
||||
FunctionResult, IntoFunction, IntoFunctionMut,
|
||||
},
|
||||
serde::Serializable,
|
||||
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
|
||||
|
@ -66,9 +66,9 @@ type ArcFn<'env> = Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send
|
|||
///
|
||||
/// [`ReflectFn`]: crate::func::ReflectFn
|
||||
/// [module-level documentation]: crate::func
|
||||
#[derive(Clone)]
|
||||
pub struct DynamicFunction<'env> {
|
||||
pub(super) name: Option<Cow<'static, str>>,
|
||||
pub(super) function_map: FunctionMap<ArcFn<'env>>,
|
||||
pub(super) internal: DynamicFunctionInternal<ArcFn<'env>>,
|
||||
}
|
||||
|
||||
impl<'env> DynamicFunction<'env> {
|
||||
|
@ -92,25 +92,8 @@ impl<'env> DynamicFunction<'env> {
|
|||
func: F,
|
||||
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
||||
) -> Self {
|
||||
let info = info.try_into().unwrap();
|
||||
|
||||
let func: ArcFn = Arc::new(func);
|
||||
|
||||
Self {
|
||||
name: match &info {
|
||||
FunctionInfoType::Standard(info) => info.name().cloned(),
|
||||
FunctionInfoType::Overloaded(_) => None,
|
||||
},
|
||||
function_map: match info {
|
||||
FunctionInfoType::Standard(info) => FunctionMap::Single(func, info.into_owned()),
|
||||
FunctionInfoType::Overloaded(infos) => {
|
||||
let indices = infos
|
||||
.iter()
|
||||
.map(|info| (ArgumentSignature::from(info), 0))
|
||||
.collect();
|
||||
FunctionMap::Overloaded(vec![func], infos.into_owned(), indices)
|
||||
}
|
||||
},
|
||||
internal: DynamicFunctionInternal::new(Arc::new(func), info.try_into().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +106,7 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// [`DynamicFunctions`]: DynamicFunction
|
||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.name = Some(name.into());
|
||||
self.internal.set_name(Some(name.into()));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -233,16 +216,14 @@ impl<'env> DynamicFunction<'env> {
|
|||
'env: 'a,
|
||||
{
|
||||
let function = function.into_function();
|
||||
|
||||
let name = self.name.clone();
|
||||
let function_map = self
|
||||
.function_map
|
||||
.merge(function.function_map)
|
||||
let internal = self
|
||||
.internal
|
||||
.merge(function.internal)
|
||||
.unwrap_or_else(|(_, err)| {
|
||||
panic!("{}", err);
|
||||
});
|
||||
|
||||
DynamicFunction { name, function_map }
|
||||
DynamicFunction { internal }
|
||||
}
|
||||
|
||||
/// Attempt to add an overload to this function.
|
||||
|
@ -259,14 +240,11 @@ impl<'env> DynamicFunction<'env> {
|
|||
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||
let function = function.into_function();
|
||||
|
||||
let name = self.name.clone();
|
||||
|
||||
match self.function_map.merge(function.function_map) {
|
||||
Ok(function_map) => Ok(Self { name, function_map }),
|
||||
Err((function_map, err)) => Err((
|
||||
match self.internal.merge(function.internal) {
|
||||
Ok(internal) => Ok(Self { internal }),
|
||||
Err((internal, err)) => Err((
|
||||
Box::new(Self {
|
||||
name,
|
||||
function_map: *function_map,
|
||||
internal: *internal,
|
||||
}),
|
||||
err,
|
||||
)),
|
||||
|
@ -297,23 +275,14 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// The function itself may also return any errors it needs to.
|
||||
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
|
||||
let expected_arg_count = self.function_map.info().arg_count();
|
||||
let received_arg_count = args.len();
|
||||
|
||||
if !expected_arg_count.contains(&received_arg_count) {
|
||||
Err(FunctionError::ArgCountMismatch {
|
||||
expected: expected_arg_count,
|
||||
received: received_arg_count,
|
||||
})
|
||||
} else {
|
||||
let func = self.function_map.get(&args)?;
|
||||
self.internal.validate_args(&args)?;
|
||||
let func = self.internal.get(&args)?;
|
||||
func(args)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the function info.
|
||||
pub fn info(&self) -> FunctionInfoType {
|
||||
self.function_map.info()
|
||||
self.internal.info()
|
||||
}
|
||||
|
||||
/// The name of the function.
|
||||
|
@ -331,7 +300,7 @@ impl<'env> DynamicFunction<'env> {
|
|||
/// [`with_name`]: Self::with_name
|
||||
/// [overloaded]: Self::with_overload
|
||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||
self.name.as_ref()
|
||||
self.internal.name()
|
||||
}
|
||||
|
||||
/// Returns `true` if the function is [overloaded].
|
||||
|
@ -349,7 +318,7 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// [overloaded]: Self::with_overload
|
||||
pub fn is_overloaded(&self) -> bool {
|
||||
self.function_map.is_overloaded()
|
||||
self.internal.is_overloaded()
|
||||
}
|
||||
|
||||
/// Returns the number of arguments the function expects.
|
||||
|
@ -372,17 +341,17 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// [overloaded]: Self::with_overload
|
||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
||||
self.function_map.arg_count()
|
||||
self.internal.arg_count()
|
||||
}
|
||||
}
|
||||
|
||||
impl Function for DynamicFunction<'static> {
|
||||
fn name(&self) -> Option<&Cow<'static, str>> {
|
||||
self.name.as_ref()
|
||||
self.internal.name()
|
||||
}
|
||||
|
||||
fn info(&self) -> FunctionInfoType {
|
||||
self.function_map.info()
|
||||
self.internal.info()
|
||||
}
|
||||
|
||||
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
|
||||
|
@ -494,19 +463,7 @@ impl_type_path!((in bevy_reflect) DynamicFunction<'env>);
|
|||
/// [overloaded]: DynamicFunction::with_overload
|
||||
impl<'env> Debug for DynamicFunction<'env> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
let name = self.name().unwrap_or(&Cow::Borrowed("_"));
|
||||
write!(f, "DynamicFunction(fn {name}")?;
|
||||
self.function_map.debug(f)?;
|
||||
write!(f, ")")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'env> Clone for DynamicFunction<'env> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
name: self.name.clone(),
|
||||
function_map: self.function_map.clone(),
|
||||
}
|
||||
write!(f, "DynamicFunction({:?})", &self.internal)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,199 @@ use bevy_utils::hashbrown::HashMap;
|
|||
use core::fmt::{Debug, Formatter};
|
||||
use core::ops::RangeInclusive;
|
||||
|
||||
/// An internal structure for storing a function and its corresponding [function information].
|
||||
///
|
||||
/// This is used to facilitate the sharing of functionality between [`DynamicFunction`]
|
||||
/// and [`DynamicFunctionMut`].
|
||||
///
|
||||
/// [function information]: FunctionInfo
|
||||
/// [`DynamicFunction`]: crate::func::DynamicFunction
|
||||
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
|
||||
#[derive(Clone)]
|
||||
pub(super) struct DynamicFunctionInternal<F> {
|
||||
name: Option<Cow<'static, str>>,
|
||||
map: FunctionMap<F>,
|
||||
}
|
||||
|
||||
impl<F> DynamicFunctionInternal<F> {
|
||||
/// Create a new instance of [`DynamicFunctionInternal`] with the given function
|
||||
/// and its corresponding information.
|
||||
pub fn new(func: F, info: FunctionInfoType<'static>) -> Self {
|
||||
Self {
|
||||
name: match &info {
|
||||
FunctionInfoType::Standard(info) => info.name().cloned(),
|
||||
FunctionInfoType::Overloaded(_) => None,
|
||||
},
|
||||
map: match info {
|
||||
FunctionInfoType::Standard(info) => FunctionMap::Single(func, info.into_owned()),
|
||||
FunctionInfoType::Overloaded(infos) => {
|
||||
let indices = infos
|
||||
.iter()
|
||||
.map(|info| (ArgumentSignature::from(info), 0))
|
||||
.collect();
|
||||
FunctionMap::Overloaded(vec![func], infos.into_owned(), indices)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the name of the function.
|
||||
pub fn set_name(&mut self, name: Option<Cow<'static, str>>) {
|
||||
self.name = name;
|
||||
}
|
||||
|
||||
/// The name of the function.
|
||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||
self.name.as_ref()
|
||||
}
|
||||
|
||||
/// Returns `true` if the function is overloaded.
|
||||
pub fn is_overloaded(&self) -> bool {
|
||||
matches!(self.map, FunctionMap::Overloaded(..))
|
||||
}
|
||||
|
||||
/// Get an immutable reference to the function.
|
||||
///
|
||||
/// If the function is not overloaded, it will always be returned regardless of the arguments.
|
||||
/// Otherwise, the function will be selected based on the arguments provided.
|
||||
///
|
||||
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
|
||||
pub fn get(&self, args: &ArgList) -> Result<&F, FunctionError> {
|
||||
match &self.map {
|
||||
FunctionMap::Single(function, _) => Ok(function),
|
||||
FunctionMap::Overloaded(functions, _, indices) => {
|
||||
let signature = ArgumentSignature::from(args);
|
||||
indices
|
||||
.get(&signature)
|
||||
.map(|index| &functions[*index])
|
||||
.ok_or_else(|| FunctionError::NoOverload {
|
||||
expected: indices.keys().cloned().collect(),
|
||||
received: signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an mutable reference to the function.
|
||||
///
|
||||
/// If the function is not overloaded, it will always be returned regardless of the arguments.
|
||||
/// Otherwise, the function will be selected based on the arguments provided.
|
||||
///
|
||||
/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].
|
||||
pub fn get_mut(&mut self, args: &ArgList) -> Result<&mut F, FunctionError> {
|
||||
match &mut self.map {
|
||||
FunctionMap::Single(function, _) => Ok(function),
|
||||
FunctionMap::Overloaded(functions, _, indices) => {
|
||||
let signature = ArgumentSignature::from(args);
|
||||
indices
|
||||
.get(&signature)
|
||||
.map(|index| &mut functions[*index])
|
||||
.ok_or_else(|| FunctionError::NoOverload {
|
||||
expected: indices.keys().cloned().collect(),
|
||||
received: signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the function information contained in the map.
|
||||
#[inline]
|
||||
pub fn info(&self) -> FunctionInfoType {
|
||||
match &self.map {
|
||||
FunctionMap::Single(_, info) => FunctionInfoType::Standard(Cow::Borrowed(info)),
|
||||
FunctionMap::Overloaded(_, info, _) => {
|
||||
FunctionInfoType::Overloaded(Cow::Borrowed(info))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of arguments the function expects.
|
||||
///
|
||||
/// For[overloaded functions that can have a variable number of arguments,
|
||||
/// this will return the minimum and maximum number of arguments.
|
||||
///
|
||||
/// Otherwise, the range will have the same start and end.
|
||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
||||
self.info().arg_count()
|
||||
}
|
||||
|
||||
/// Helper method for validating that a given set of arguments are _potentially_ valid for this function.
|
||||
///
|
||||
/// Currently, this validates:
|
||||
/// - The number of arguments is within the expected range
|
||||
pub fn validate_args(&self, args: &ArgList) -> Result<(), FunctionError> {
|
||||
let expected_arg_count = self.arg_count();
|
||||
let received_arg_count = args.len();
|
||||
|
||||
if !expected_arg_count.contains(&received_arg_count) {
|
||||
Err(FunctionError::ArgCountMismatch {
|
||||
expected: expected_arg_count,
|
||||
received: received_arg_count,
|
||||
})
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Merge another [`DynamicFunctionInternal`] into this one.
|
||||
///
|
||||
/// If `other` contains any functions with the same signature as this one,
|
||||
/// an error will be returned along with the original, unchanged instance.
|
||||
///
|
||||
/// Therefore, this method should always return an overloaded function if the merge is successful.
|
||||
///
|
||||
/// Additionally, if the merge succeeds, it should be guaranteed that the order
|
||||
/// of the functions in the map will be preserved.
|
||||
/// For example, merging `[func_a, func_b]` (self) with `[func_c, func_d]` (other) should result in
|
||||
/// `[func_a, func_b, func_c, func_d]`.
|
||||
/// And merging `[func_c, func_d]` (self) with `[func_a, func_b]` (other) should result in
|
||||
/// `[func_c, func_d, func_a, func_b]`.
|
||||
pub fn merge(self, other: Self) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||
let map = self.map.merge(other.map).map_err(|(map, err)| {
|
||||
(
|
||||
Box::new(Self {
|
||||
name: self.name.clone(),
|
||||
map: *map,
|
||||
}),
|
||||
err,
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(Self {
|
||||
name: self.name,
|
||||
map,
|
||||
})
|
||||
}
|
||||
|
||||
/// Convert the inner [`FunctionMap`] from holding `F` to holding `G`.
|
||||
pub fn convert<G>(self, f: fn(FunctionMap<F>) -> FunctionMap<G>) -> DynamicFunctionInternal<G> {
|
||||
DynamicFunctionInternal {
|
||||
name: self.name,
|
||||
map: f(self.map),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Debug for DynamicFunctionInternal<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
let name = self.name.as_deref().unwrap_or("_");
|
||||
write!(f, "fn {name}")?;
|
||||
|
||||
match &self.map {
|
||||
// `(arg0: i32, arg1: i32) -> ()`
|
||||
FunctionMap::Single(_, info) => PrettyPrintFunctionInfo::new(info).fmt(f),
|
||||
// `{(arg0: i32, arg1: i32) -> (), (arg0: f32, arg1: f32) -> ()}`
|
||||
FunctionMap::Overloaded(_, infos, _) => {
|
||||
let mut set = f.debug_set();
|
||||
for info in infos.iter() {
|
||||
set.entry(&PrettyPrintFunctionInfo::new(info));
|
||||
}
|
||||
set.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A helper type for storing a mapping of overloaded functions
|
||||
/// along with the corresponding [function information].
|
||||
///
|
||||
|
@ -36,75 +229,6 @@ pub(super) enum FunctionMap<F> {
|
|||
}
|
||||
|
||||
impl<F> FunctionMap<F> {
|
||||
/// Returns `true` if the map contains an overloaded function.
|
||||
pub fn is_overloaded(&self) -> bool {
|
||||
matches!(self, Self::Overloaded(..))
|
||||
}
|
||||
|
||||
/// Get a reference to a function in the map.
|
||||
///
|
||||
/// If there is only one function in the map, it will be returned.
|
||||
/// Otherwise, the function will be selected based on the arguments provided.
|
||||
///
|
||||
/// If no overload matches the provided arguments, an error will be returned.
|
||||
pub fn get(&self, args: &ArgList) -> Result<&F, FunctionError> {
|
||||
match self {
|
||||
Self::Single(function, _) => Ok(function),
|
||||
Self::Overloaded(functions, _, indices) => {
|
||||
let signature = ArgumentSignature::from(args);
|
||||
indices
|
||||
.get(&signature)
|
||||
.map(|index| &functions[*index])
|
||||
.ok_or_else(|| FunctionError::NoOverload {
|
||||
expected: indices.keys().cloned().collect(),
|
||||
received: signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a mutable reference to a function in the map.
|
||||
///
|
||||
/// If there is only one function in the map, it will be returned.
|
||||
/// Otherwise, the function will be selected based on the arguments provided.
|
||||
///
|
||||
/// If no overload matches the provided arguments, an error will be returned.
|
||||
pub fn get_mut(&mut self, args: &ArgList) -> Result<&mut F, FunctionError> {
|
||||
match self {
|
||||
Self::Single(function, _) => Ok(function),
|
||||
Self::Overloaded(functions, _, indices) => {
|
||||
let signature = ArgumentSignature::from(args);
|
||||
indices
|
||||
.get(&signature)
|
||||
.map(|index| &mut functions[*index])
|
||||
.ok_or_else(|| FunctionError::NoOverload {
|
||||
expected: indices.keys().cloned().collect(),
|
||||
received: signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the function information contained in the map.
|
||||
pub fn info(&self) -> FunctionInfoType {
|
||||
match self {
|
||||
Self::Single(_, info) => FunctionInfoType::Standard(Cow::Borrowed(info)),
|
||||
Self::Overloaded(_, info, _) => FunctionInfoType::Overloaded(Cow::Borrowed(info)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of arguments the function expects.
|
||||
///
|
||||
/// For [overloaded] functions that can have a variable number of arguments,
|
||||
/// this will return the minimum and maximum number of arguments.
|
||||
///
|
||||
/// Otherwise, the range will have the same start and end.
|
||||
///
|
||||
/// [overloaded]: Self::Overloaded
|
||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
||||
self.info().arg_count()
|
||||
}
|
||||
|
||||
/// Merge another [`FunctionMap`] into this one.
|
||||
///
|
||||
/// If the other map contains any functions with the same signature as this one,
|
||||
|
@ -220,21 +344,6 @@ impl<F> FunctionMap<F> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
// `(arg0: i32, arg1: i32) -> ()`
|
||||
Self::Single(_, info) => PrettyPrintFunctionInfo::new(info).fmt(f),
|
||||
// `{(arg0: i32, arg1: i32) -> (), (arg0: f32, arg1: f32) -> ()}`
|
||||
Self::Overloaded(_, infos, _) => {
|
||||
let mut set = f.debug_set();
|
||||
for info in infos.iter() {
|
||||
set.entry(&PrettyPrintFunctionInfo::new(info));
|
||||
}
|
||||
set.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
|
@ -5,8 +5,9 @@ use core::ops::RangeInclusive;
|
|||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{boxed::Box, format, vec};
|
||||
|
||||
use crate::func::dynamic_function_internal::FunctionMap;
|
||||
use crate::func::{
|
||||
args::ArgList, function_map::FunctionMap, signature::ArgumentSignature, DynamicFunction,
|
||||
args::ArgList, dynamic_function_internal::DynamicFunctionInternal, DynamicFunction,
|
||||
FunctionError, FunctionInfoType, FunctionOverloadError, FunctionResult, IntoFunctionMut,
|
||||
};
|
||||
|
||||
|
@ -70,8 +71,7 @@ type BoxFnMut<'env> = Box<dyn for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> +
|
|||
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
|
||||
/// [module-level documentation]: crate::func
|
||||
pub struct DynamicFunctionMut<'env> {
|
||||
name: Option<Cow<'static, str>>,
|
||||
function_map: FunctionMap<BoxFnMut<'env>>,
|
||||
internal: DynamicFunctionInternal<BoxFnMut<'env>>,
|
||||
}
|
||||
|
||||
impl<'env> DynamicFunctionMut<'env> {
|
||||
|
@ -95,25 +95,8 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
func: F,
|
||||
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
||||
) -> Self {
|
||||
let info = info.try_into().unwrap();
|
||||
|
||||
let func: BoxFnMut = Box::new(func);
|
||||
|
||||
Self {
|
||||
name: match &info {
|
||||
FunctionInfoType::Standard(info) => info.name().cloned(),
|
||||
FunctionInfoType::Overloaded(_) => None,
|
||||
},
|
||||
function_map: match info {
|
||||
FunctionInfoType::Standard(info) => FunctionMap::Single(func, info.into_owned()),
|
||||
FunctionInfoType::Overloaded(infos) => {
|
||||
let indices = infos
|
||||
.iter()
|
||||
.map(|info| (ArgumentSignature::from(info), 0))
|
||||
.collect();
|
||||
FunctionMap::Overloaded(vec![func], infos.into_owned(), indices)
|
||||
}
|
||||
},
|
||||
internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,7 +109,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.name = Some(name.into());
|
||||
self.internal.set_name(Some(name.into()));
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -196,15 +179,14 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
{
|
||||
let function = function.into_function_mut();
|
||||
|
||||
let name = self.name.clone();
|
||||
let function_map = self
|
||||
.function_map
|
||||
.merge(function.function_map)
|
||||
let internal = self
|
||||
.internal
|
||||
.merge(function.internal)
|
||||
.unwrap_or_else(|(_, err)| {
|
||||
panic!("{}", err);
|
||||
});
|
||||
|
||||
DynamicFunctionMut { name, function_map }
|
||||
DynamicFunctionMut { internal }
|
||||
}
|
||||
|
||||
/// Attempt to add an overload to this function.
|
||||
|
@ -221,14 +203,11 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||
let function = function.into_function_mut();
|
||||
|
||||
let name = self.name.clone();
|
||||
|
||||
match self.function_map.merge(function.function_map) {
|
||||
Ok(function_map) => Ok(Self { name, function_map }),
|
||||
Err((function_map, err)) => Err((
|
||||
match self.internal.merge(function.internal) {
|
||||
Ok(internal) => Ok(Self { internal }),
|
||||
Err((internal, err)) => Err((
|
||||
Box::new(Self {
|
||||
name,
|
||||
function_map: *function_map,
|
||||
internal: *internal,
|
||||
}),
|
||||
err,
|
||||
)),
|
||||
|
@ -267,19 +246,10 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// [`call_once`]: DynamicFunctionMut::call_once
|
||||
pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {
|
||||
let expected_arg_count = self.function_map.info().arg_count();
|
||||
let received_arg_count = args.len();
|
||||
|
||||
if !expected_arg_count.contains(&received_arg_count) {
|
||||
Err(FunctionError::ArgCountMismatch {
|
||||
expected: expected_arg_count,
|
||||
received: received_arg_count,
|
||||
})
|
||||
} else {
|
||||
let func = self.function_map.get_mut(&args)?;
|
||||
self.internal.validate_args(&args)?;
|
||||
let func = self.internal.get_mut(&args)?;
|
||||
func(args)
|
||||
}
|
||||
}
|
||||
|
||||
/// Call the function with the given arguments and consume it.
|
||||
///
|
||||
|
@ -315,7 +285,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
|
||||
/// Returns the function info.
|
||||
pub fn info(&self) -> FunctionInfoType {
|
||||
self.function_map.info()
|
||||
self.internal.info()
|
||||
}
|
||||
|
||||
/// The name of the function.
|
||||
|
@ -330,7 +300,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
||||
/// [`with_name`]: Self::with_name
|
||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||
self.name.as_ref()
|
||||
self.internal.name()
|
||||
}
|
||||
|
||||
/// Returns `true` if the function is [overloaded].
|
||||
|
@ -350,7 +320,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// [overloaded]: Self::with_overload
|
||||
pub fn is_overloaded(&self) -> bool {
|
||||
self.function_map.is_overloaded()
|
||||
self.internal.is_overloaded()
|
||||
}
|
||||
|
||||
/// Returns the number of arguments the function expects.
|
||||
|
@ -373,7 +343,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// [overloaded]: Self::with_overload
|
||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
||||
self.function_map.arg_count()
|
||||
self.internal.arg_count()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,10 +359,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
/// [overloaded]: DynamicFunctionMut::with_overload
|
||||
impl<'env> Debug for DynamicFunctionMut<'env> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
let name = self.name().unwrap_or(&Cow::Borrowed("_"));
|
||||
write!(f, "DynamicFunctionMut(fn {name}")?;
|
||||
self.function_map.debug(f)?;
|
||||
write!(f, ")")
|
||||
write!(f, "DynamicFunctionMut({:?})", &self.internal)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,15 +367,14 @@ impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {
|
|||
#[inline]
|
||||
fn from(function: DynamicFunction<'env>) -> Self {
|
||||
Self {
|
||||
name: function.name,
|
||||
function_map: match function.function_map {
|
||||
internal: function.internal.convert(|map| match map {
|
||||
FunctionMap::Single(func, info) => FunctionMap::Single(arc_to_box(func), info),
|
||||
FunctionMap::Overloaded(funcs, infos, indices) => FunctionMap::Overloaded(
|
||||
funcs.into_iter().map(arc_to_box).collect(),
|
||||
infos,
|
||||
indices,
|
||||
),
|
||||
},
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,10 +173,10 @@ pub use return_type::*;
|
|||
|
||||
pub mod args;
|
||||
mod dynamic_function;
|
||||
mod dynamic_function_internal;
|
||||
mod dynamic_function_mut;
|
||||
mod error;
|
||||
mod function;
|
||||
mod function_map;
|
||||
mod info;
|
||||
mod into_function;
|
||||
mod into_function_mut;
|
||||
|
|
Loading…
Reference in a new issue