mirror of
https://github.com/bevyengine/bevy
synced 2024-12-30 06:53:13 +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,
|
self as bevy_reflect,
|
||||||
__macro_exports::RegisterForReflection,
|
__macro_exports::RegisterForReflection,
|
||||||
func::{
|
func::{
|
||||||
args::ArgList, function_map::FunctionMap, info::FunctionInfoType,
|
args::ArgList, dynamic_function_internal::DynamicFunctionInternal, info::FunctionInfoType,
|
||||||
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionError,
|
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionOverloadError,
|
||||||
FunctionOverloadError, FunctionResult, IntoFunction, IntoFunctionMut,
|
FunctionResult, IntoFunction, IntoFunctionMut,
|
||||||
},
|
},
|
||||||
serde::Serializable,
|
serde::Serializable,
|
||||||
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
|
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
|
/// [`ReflectFn`]: crate::func::ReflectFn
|
||||||
/// [module-level documentation]: crate::func
|
/// [module-level documentation]: crate::func
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct DynamicFunction<'env> {
|
pub struct DynamicFunction<'env> {
|
||||||
pub(super) name: Option<Cow<'static, str>>,
|
pub(super) internal: DynamicFunctionInternal<ArcFn<'env>>,
|
||||||
pub(super) function_map: FunctionMap<ArcFn<'env>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'env> DynamicFunction<'env> {
|
impl<'env> DynamicFunction<'env> {
|
||||||
|
@ -92,25 +92,8 @@ impl<'env> DynamicFunction<'env> {
|
||||||
func: F,
|
func: F,
|
||||||
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let info = info.try_into().unwrap();
|
|
||||||
|
|
||||||
let func: ArcFn = Arc::new(func);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name: match &info {
|
internal: DynamicFunctionInternal::new(Arc::new(func), info.try_into().unwrap()),
|
||||||
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)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +106,7 @@ impl<'env> DynamicFunction<'env> {
|
||||||
///
|
///
|
||||||
/// [`DynamicFunctions`]: DynamicFunction
|
/// [`DynamicFunctions`]: DynamicFunction
|
||||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,16 +216,14 @@ impl<'env> DynamicFunction<'env> {
|
||||||
'env: 'a,
|
'env: 'a,
|
||||||
{
|
{
|
||||||
let function = function.into_function();
|
let function = function.into_function();
|
||||||
|
let internal = self
|
||||||
let name = self.name.clone();
|
.internal
|
||||||
let function_map = self
|
.merge(function.internal)
|
||||||
.function_map
|
|
||||||
.merge(function.function_map)
|
|
||||||
.unwrap_or_else(|(_, err)| {
|
.unwrap_or_else(|(_, err)| {
|
||||||
panic!("{}", err);
|
panic!("{}", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
DynamicFunction { name, function_map }
|
DynamicFunction { internal }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to add an overload to this function.
|
/// Attempt to add an overload to this function.
|
||||||
|
@ -259,14 +240,11 @@ impl<'env> DynamicFunction<'env> {
|
||||||
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||||
let function = function.into_function();
|
let function = function.into_function();
|
||||||
|
|
||||||
let name = self.name.clone();
|
match self.internal.merge(function.internal) {
|
||||||
|
Ok(internal) => Ok(Self { internal }),
|
||||||
match self.function_map.merge(function.function_map) {
|
Err((internal, err)) => Err((
|
||||||
Ok(function_map) => Ok(Self { name, function_map }),
|
|
||||||
Err((function_map, err)) => Err((
|
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
name,
|
internal: *internal,
|
||||||
function_map: *function_map,
|
|
||||||
}),
|
}),
|
||||||
err,
|
err,
|
||||||
)),
|
)),
|
||||||
|
@ -297,23 +275,14 @@ impl<'env> DynamicFunction<'env> {
|
||||||
///
|
///
|
||||||
/// The function itself may also return any errors it needs to.
|
/// The function itself may also return any errors it needs to.
|
||||||
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
|
pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
|
||||||
let expected_arg_count = self.function_map.info().arg_count();
|
self.internal.validate_args(&args)?;
|
||||||
let received_arg_count = args.len();
|
let func = self.internal.get(&args)?;
|
||||||
|
func(args)
|
||||||
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)?;
|
|
||||||
func(args)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the function info.
|
/// Returns the function info.
|
||||||
pub fn info(&self) -> FunctionInfoType {
|
pub fn info(&self) -> FunctionInfoType {
|
||||||
self.function_map.info()
|
self.internal.info()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
|
@ -331,7 +300,7 @@ impl<'env> DynamicFunction<'env> {
|
||||||
/// [`with_name`]: Self::with_name
|
/// [`with_name`]: Self::with_name
|
||||||
/// [overloaded]: Self::with_overload
|
/// [overloaded]: Self::with_overload
|
||||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||||
self.name.as_ref()
|
self.internal.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the function is [overloaded].
|
/// Returns `true` if the function is [overloaded].
|
||||||
|
@ -349,7 +318,7 @@ impl<'env> DynamicFunction<'env> {
|
||||||
///
|
///
|
||||||
/// [overloaded]: Self::with_overload
|
/// [overloaded]: Self::with_overload
|
||||||
pub fn is_overloaded(&self) -> bool {
|
pub fn is_overloaded(&self) -> bool {
|
||||||
self.function_map.is_overloaded()
|
self.internal.is_overloaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of arguments the function expects.
|
/// Returns the number of arguments the function expects.
|
||||||
|
@ -372,17 +341,17 @@ impl<'env> DynamicFunction<'env> {
|
||||||
///
|
///
|
||||||
/// [overloaded]: Self::with_overload
|
/// [overloaded]: Self::with_overload
|
||||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
||||||
self.function_map.arg_count()
|
self.internal.arg_count()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function for DynamicFunction<'static> {
|
impl Function for DynamicFunction<'static> {
|
||||||
fn name(&self) -> Option<&Cow<'static, str>> {
|
fn name(&self) -> Option<&Cow<'static, str>> {
|
||||||
self.name.as_ref()
|
self.internal.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn info(&self) -> FunctionInfoType {
|
fn info(&self) -> FunctionInfoType {
|
||||||
self.function_map.info()
|
self.internal.info()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {
|
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
|
/// [overloaded]: DynamicFunction::with_overload
|
||||||
impl<'env> Debug for DynamicFunction<'env> {
|
impl<'env> Debug for DynamicFunction<'env> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
let name = self.name().unwrap_or(&Cow::Borrowed("_"));
|
write!(f, "DynamicFunction({:?})", &self.internal)
|
||||||
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(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,199 @@ use bevy_utils::hashbrown::HashMap;
|
||||||
use core::fmt::{Debug, Formatter};
|
use core::fmt::{Debug, Formatter};
|
||||||
use core::ops::RangeInclusive;
|
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
|
/// A helper type for storing a mapping of overloaded functions
|
||||||
/// along with the corresponding [function information].
|
/// along with the corresponding [function information].
|
||||||
///
|
///
|
||||||
|
@ -36,75 +229,6 @@ pub(super) enum FunctionMap<F> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F> 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.
|
/// Merge another [`FunctionMap`] into this one.
|
||||||
///
|
///
|
||||||
/// If the other map contains any functions with the same signature as 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)]
|
#[cfg(test)]
|
|
@ -5,8 +5,9 @@ use core::ops::RangeInclusive;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use alloc::{boxed::Box, format, vec};
|
use alloc::{boxed::Box, format, vec};
|
||||||
|
|
||||||
|
use crate::func::dynamic_function_internal::FunctionMap;
|
||||||
use crate::func::{
|
use crate::func::{
|
||||||
args::ArgList, function_map::FunctionMap, signature::ArgumentSignature, DynamicFunction,
|
args::ArgList, dynamic_function_internal::DynamicFunctionInternal, DynamicFunction,
|
||||||
FunctionError, FunctionInfoType, FunctionOverloadError, FunctionResult, IntoFunctionMut,
|
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
|
/// [`ReflectFnMut`]: crate::func::ReflectFnMut
|
||||||
/// [module-level documentation]: crate::func
|
/// [module-level documentation]: crate::func
|
||||||
pub struct DynamicFunctionMut<'env> {
|
pub struct DynamicFunctionMut<'env> {
|
||||||
name: Option<Cow<'static, str>>,
|
internal: DynamicFunctionInternal<BoxFnMut<'env>>,
|
||||||
function_map: FunctionMap<BoxFnMut<'env>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'env> DynamicFunctionMut<'env> {
|
impl<'env> DynamicFunctionMut<'env> {
|
||||||
|
@ -95,25 +95,8 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
func: F,
|
func: F,
|
||||||
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let info = info.try_into().unwrap();
|
|
||||||
|
|
||||||
let func: BoxFnMut = Box::new(func);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
name: match &info {
|
internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),
|
||||||
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)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,7 +109,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
///
|
///
|
||||||
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
||||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,15 +179,14 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
{
|
{
|
||||||
let function = function.into_function_mut();
|
let function = function.into_function_mut();
|
||||||
|
|
||||||
let name = self.name.clone();
|
let internal = self
|
||||||
let function_map = self
|
.internal
|
||||||
.function_map
|
.merge(function.internal)
|
||||||
.merge(function.function_map)
|
|
||||||
.unwrap_or_else(|(_, err)| {
|
.unwrap_or_else(|(_, err)| {
|
||||||
panic!("{}", err);
|
panic!("{}", err);
|
||||||
});
|
});
|
||||||
|
|
||||||
DynamicFunctionMut { name, function_map }
|
DynamicFunctionMut { internal }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to add an overload to this function.
|
/// Attempt to add an overload to this function.
|
||||||
|
@ -221,14 +203,11 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||||
let function = function.into_function_mut();
|
let function = function.into_function_mut();
|
||||||
|
|
||||||
let name = self.name.clone();
|
match self.internal.merge(function.internal) {
|
||||||
|
Ok(internal) => Ok(Self { internal }),
|
||||||
match self.function_map.merge(function.function_map) {
|
Err((internal, err)) => Err((
|
||||||
Ok(function_map) => Ok(Self { name, function_map }),
|
|
||||||
Err((function_map, err)) => Err((
|
|
||||||
Box::new(Self {
|
Box::new(Self {
|
||||||
name,
|
internal: *internal,
|
||||||
function_map: *function_map,
|
|
||||||
}),
|
}),
|
||||||
err,
|
err,
|
||||||
)),
|
)),
|
||||||
|
@ -267,18 +246,9 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
///
|
///
|
||||||
/// [`call_once`]: DynamicFunctionMut::call_once
|
/// [`call_once`]: DynamicFunctionMut::call_once
|
||||||
pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {
|
pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {
|
||||||
let expected_arg_count = self.function_map.info().arg_count();
|
self.internal.validate_args(&args)?;
|
||||||
let received_arg_count = args.len();
|
let func = self.internal.get_mut(&args)?;
|
||||||
|
func(args)
|
||||||
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)?;
|
|
||||||
func(args)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the function with the given arguments and consume it.
|
/// Call the function with the given arguments and consume it.
|
||||||
|
@ -315,7 +285,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
|
|
||||||
/// Returns the function info.
|
/// Returns the function info.
|
||||||
pub fn info(&self) -> FunctionInfoType {
|
pub fn info(&self) -> FunctionInfoType {
|
||||||
self.function_map.info()
|
self.internal.info()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The name of the function.
|
/// The name of the function.
|
||||||
|
@ -330,7 +300,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
||||||
/// [`with_name`]: Self::with_name
|
/// [`with_name`]: Self::with_name
|
||||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||||
self.name.as_ref()
|
self.internal.name()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the function is [overloaded].
|
/// Returns `true` if the function is [overloaded].
|
||||||
|
@ -350,7 +320,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
///
|
///
|
||||||
/// [overloaded]: Self::with_overload
|
/// [overloaded]: Self::with_overload
|
||||||
pub fn is_overloaded(&self) -> bool {
|
pub fn is_overloaded(&self) -> bool {
|
||||||
self.function_map.is_overloaded()
|
self.internal.is_overloaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of arguments the function expects.
|
/// Returns the number of arguments the function expects.
|
||||||
|
@ -373,7 +343,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
||||||
///
|
///
|
||||||
/// [overloaded]: Self::with_overload
|
/// [overloaded]: Self::with_overload
|
||||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
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
|
/// [overloaded]: DynamicFunctionMut::with_overload
|
||||||
impl<'env> Debug for DynamicFunctionMut<'env> {
|
impl<'env> Debug for DynamicFunctionMut<'env> {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||||
let name = self.name().unwrap_or(&Cow::Borrowed("_"));
|
write!(f, "DynamicFunctionMut({:?})", &self.internal)
|
||||||
write!(f, "DynamicFunctionMut(fn {name}")?;
|
|
||||||
self.function_map.debug(f)?;
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,15 +367,14 @@ impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(function: DynamicFunction<'env>) -> Self {
|
fn from(function: DynamicFunction<'env>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: function.name,
|
internal: function.internal.convert(|map| match map {
|
||||||
function_map: match function.function_map {
|
|
||||||
FunctionMap::Single(func, info) => FunctionMap::Single(arc_to_box(func), info),
|
FunctionMap::Single(func, info) => FunctionMap::Single(arc_to_box(func), info),
|
||||||
FunctionMap::Overloaded(funcs, infos, indices) => FunctionMap::Overloaded(
|
FunctionMap::Overloaded(funcs, infos, indices) => FunctionMap::Overloaded(
|
||||||
funcs.into_iter().map(arc_to_box).collect(),
|
funcs.into_iter().map(arc_to_box).collect(),
|
||||||
infos,
|
infos,
|
||||||
indices,
|
indices,
|
||||||
),
|
),
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,10 +173,10 @@ pub use return_type::*;
|
||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
mod dynamic_function;
|
mod dynamic_function;
|
||||||
|
mod dynamic_function_internal;
|
||||||
mod dynamic_function_mut;
|
mod dynamic_function_mut;
|
||||||
mod error;
|
mod error;
|
||||||
mod function;
|
mod function;
|
||||||
mod function_map;
|
|
||||||
mod info;
|
mod info;
|
||||||
mod into_function;
|
mod into_function;
|
||||||
mod into_function_mut;
|
mod into_function_mut;
|
||||||
|
|
Loading…
Reference in a new issue