Added non-panicking method for adding overloads

This commit is contained in:
Gino Valente 2024-09-03 19:02:56 -07:00
parent 38b3cbf5c5
commit 77ae7cf822
3 changed files with 93 additions and 27 deletions

View file

@ -3,8 +3,8 @@ use crate::{
__macro_exports::RegisterForReflection,
func::{
args::ArgList, function_map::FunctionMap, info::FunctionInfoType,
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionError, FunctionResult,
IntoFunction, IntoFunctionMut,
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionError,
FunctionOverloadError, FunctionResult, IntoFunction, IntoFunctionMut,
},
serde::Serializable,
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
@ -150,6 +150,8 @@ impl<'env> DynamicFunction<'env> {
///
/// Panics if the function, `F`, contains a signature already found in this function.
///
/// For a non-panicking version, see [`try_with_overload`].
///
/// # Examples
///
/// ```
@ -227,6 +229,7 @@ impl<'env> DynamicFunction<'env> {
///
/// [argument signature]: ArgumentSignature
/// [name]: Self::name
/// [`try_with_overload`]: Self::try_with_overload
pub fn with_overload<'a, F: IntoFunction<'a, Marker>, Marker>(
self,
function: F,
@ -237,16 +240,44 @@ impl<'env> DynamicFunction<'env> {
let function = function.into_function();
let name = self.name.clone();
let mut function_map = self.function_map;
function_map
let function_map = self
.function_map
.merge(function.function_map)
.unwrap_or_else(|err| {
.unwrap_or_else(|(_, err)| {
panic!("{}", err);
});
DynamicFunction { name, function_map }
}
/// Attempt to add an overload to this function.
///
/// If the function, `F`, contains a signature already found in this function,
/// an error will be returned along with the original function.
///
/// For a panicking version, see [`with_overload`].
///
/// [`with_overload`]: Self::with_overload
pub fn try_with_overload<F: IntoFunction<'env, Marker>, Marker>(
self,
function: F,
) -> 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((
Box::new(Self {
name,
function_map: *function_map,
}),
err,
)),
}
}
/// Call the function with the given arguments.
///
/// # Example

View file

@ -6,7 +6,7 @@ use alloc::{boxed::Box, format, vec};
use crate::func::{
args::ArgList, function_map::FunctionMap, signature::ArgumentSignature, DynamicFunction,
FunctionError, FunctionInfoType, FunctionResult, IntoFunctionMut,
FunctionError, FunctionInfoType, FunctionOverloadError, FunctionResult, IntoFunctionMut,
};
use bevy_utils::HashMap;
@ -158,6 +158,8 @@ impl<'env> DynamicFunctionMut<'env> {
///
/// Panics if the function, `F`, contains a signature already found in this function.
///
/// For a non-panicking version, see [`try_with_overload`].
///
/// # Example
///
/// ```
@ -189,6 +191,7 @@ impl<'env> DynamicFunctionMut<'env> {
///
/// [argument signature]: ArgumentSignature
/// [name]: Self::name
/// [`try_with_overload`]: Self::try_with_overload
pub fn with_overload<'a, F: IntoFunctionMut<'a, Marker>, Marker>(
self,
function: F,
@ -199,14 +202,44 @@ impl<'env> DynamicFunctionMut<'env> {
let function = function.into_function_mut();
let name = self.name.clone();
let mut function_map = self.function_map;
function_map
let function_map = self
.function_map
.merge(function.function_map)
.unwrap_or_else(|_| todo!());
.unwrap_or_else(|(_, err)| {
panic!("{}", err);
});
DynamicFunctionMut { name, function_map }
}
/// Attempt to add an overload to this function.
///
/// If the function, `F`, contains a signature already found in this function,
/// an error will be returned along with the original function.
///
/// For a panicking version, see [`with_overload`].
///
/// [`with_overload`]: Self::with_overload
pub fn try_with_overload<F: IntoFunctionMut<'env, Marker>, Marker>(
self,
function: F,
) -> 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((
Box::new(Self {
name,
function_map: *function_map,
}),
err,
)),
}
}
/// Call the function with the given arguments.
///
/// Variables that are captured mutably by this function

View file

@ -59,14 +59,14 @@ impl<F> FunctionMap<F> {
/// Merge another [`FunctionMap`] into this one.
///
/// If the other map contains any functions with the same signature as this one,
/// an error will be returned and the original map will remain unchanged.
pub fn merge(&mut self, other: Self) -> Result<(), FunctionOverloadError> {
/// an error will be returned along with the original, unchanged map.
pub fn merge(mut self, other: Self) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
// === Function Map === //
let mut other_indices = HashMap::new();
for (sig, index) in other.indices {
if self.indices.contains_key(&sig) {
return Err(FunctionOverloadError { signature: sig });
return Err((Box::new(self), FunctionOverloadError { signature: sig }));
}
other_indices.insert(sig, self.functions.len() + index);
@ -78,7 +78,7 @@ impl<F> FunctionMap<F> {
for info in other.info.into_iter() {
let sig = ArgumentSignature::from(&info);
if self.indices.contains_key(&sig) {
return Err(FunctionOverloadError { signature: sig });
return Err((Box::new(self), FunctionOverloadError { signature: sig }));
}
other_infos.push(info);
}
@ -86,16 +86,16 @@ impl<F> FunctionMap<F> {
// === Update === //
self.indices.extend(other_indices);
self.functions.extend(other.functions);
self.info = match &self.info {
FunctionInfoType::Standard(info) => FunctionInfoType::Overloaded(
std::iter::once(info.clone()).chain(other_infos).collect(),
),
FunctionInfoType::Overloaded(infos) => {
FunctionInfoType::Overloaded(infos.iter().cloned().chain(other_infos).collect())
self.info = match self.info {
FunctionInfoType::Standard(info) => {
FunctionInfoType::Overloaded(std::iter::once(info).chain(other_infos).collect())
}
FunctionInfoType::Overloaded(infos) => FunctionInfoType::Overloaded(
IntoIterator::into_iter(infos).chain(other_infos).collect(),
),
};
Ok(())
Ok(self)
}
}
@ -107,7 +107,7 @@ mod tests {
#[test]
fn should_merge_function_maps() {
let mut map_a = FunctionMap {
let map_a = FunctionMap {
info: FunctionInfoType::Overloaded(Box::new([
FunctionInfo::anonymous().with_arg::<i8>("arg0"),
FunctionInfo::anonymous().with_arg::<i16>("arg0"),
@ -135,11 +135,11 @@ mod tests {
]),
};
map_a.merge(map_b).unwrap();
let map = map_a.merge(map_b).unwrap();
assert_eq!(map_a.functions, vec!['a', 'b', 'c', 'd', 'e', 'f']);
assert_eq!(map.functions, vec!['a', 'b', 'c', 'd', 'e', 'f']);
assert_eq!(
map_a.indices,
map.indices,
HashMap::from([
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
@ -153,7 +153,7 @@ mod tests {
#[test]
fn should_return_error_on_duplicate_signature() {
let mut map_a = FunctionMap {
let map_a = FunctionMap {
info: FunctionInfoType::Overloaded(Box::new([
FunctionInfo::anonymous().with_arg::<i8>("arg0"),
FunctionInfo::anonymous().with_arg::<i16>("arg0"),
@ -181,9 +181,11 @@ mod tests {
]),
};
let result = map_a.merge(map_b);
let Err((map_a, error)) = map_a.merge(map_b) else {
panic!("expected an error");
};
assert_eq!(
result.unwrap_err(),
error,
FunctionOverloadError {
signature: ArgumentSignature::from_iter([Type::of::<i16>()])
}