mirror of
https://github.com/bevyengine/bevy
synced 2024-12-21 02:23:08 +00:00
Improve function info representation
Replaced FunctionInfoType with FunctionInfo and added SignatureInfo
This commit is contained in:
parent
0a50c2a0cb
commit
a6121d62f9
8 changed files with 623 additions and 633 deletions
|
@ -2,9 +2,9 @@ use crate::{
|
|||
self as bevy_reflect,
|
||||
__macro_exports::RegisterForReflection,
|
||||
func::{
|
||||
args::ArgList, dynamic_function_internal::DynamicFunctionInternal, info::FunctionInfoType,
|
||||
signature::ArgumentSignature, DynamicFunctionMut, Function, FunctionOverloadError,
|
||||
FunctionResult, IntoFunction, IntoFunctionMut,
|
||||
args::ArgList, dynamic_function_internal::DynamicFunctionInternal, info::FunctionInfo,
|
||||
DynamicFunctionMut, Function, FunctionOverloadError, FunctionResult, IntoFunction,
|
||||
IntoFunctionMut,
|
||||
},
|
||||
serde::Serializable,
|
||||
ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,
|
||||
|
@ -83,14 +83,14 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if no [`FunctionInfo`] is provided or if the conversion to [`FunctionInfoType`] fails.
|
||||
/// Panics if no [`SignatureInfo`] is provided or if the conversion to [`FunctionInfo`] fails.
|
||||
///
|
||||
/// [calling]: crate::func::dynamic_function::DynamicFunction::call
|
||||
/// [`FunctionInfo`]: crate::func::FunctionInfo
|
||||
/// [`SignatureInfo`]: crate::func::SignatureInfo
|
||||
/// [function overloading]: Self::with_overload
|
||||
pub fn new<F: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>(
|
||||
func: F,
|
||||
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
||||
info: impl TryInto<FunctionInfo, Error: Debug>,
|
||||
) -> Self {
|
||||
Self {
|
||||
internal: DynamicFunctionInternal::new(Arc::new(func), info.try_into().unwrap()),
|
||||
|
@ -106,7 +106,7 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// [`DynamicFunctions`]: DynamicFunction
|
||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.internal.set_name(Some(name.into()));
|
||||
self.internal = self.internal.with_name(name);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ impl<'env> DynamicFunction<'env> {
|
|||
/// func = func.with_overload(sub);
|
||||
/// ```
|
||||
///
|
||||
/// [argument signature]: ArgumentSignature
|
||||
/// [argument signature]: crate::func::signature::ArgumentSignature
|
||||
/// [name]: Self::name
|
||||
/// [`try_with_overload`]: Self::try_with_overload
|
||||
pub fn with_overload<'a, F: IntoFunction<'a, Marker>, Marker>(
|
||||
|
@ -215,15 +215,9 @@ impl<'env> DynamicFunction<'env> {
|
|||
where
|
||||
'env: 'a,
|
||||
{
|
||||
let function = function.into_function();
|
||||
let internal = self
|
||||
.internal
|
||||
.merge(function.internal)
|
||||
.unwrap_or_else(|(_, err)| {
|
||||
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
|
||||
panic!("{}", err);
|
||||
});
|
||||
|
||||
DynamicFunction { internal }
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempt to add an overload to this function.
|
||||
|
@ -235,19 +229,14 @@ impl<'env> DynamicFunction<'env> {
|
|||
///
|
||||
/// [`with_overload`]: Self::with_overload
|
||||
pub fn try_with_overload<F: IntoFunction<'env, Marker>, Marker>(
|
||||
self,
|
||||
mut self,
|
||||
function: F,
|
||||
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||
let function = function.into_function();
|
||||
|
||||
match self.internal.merge(function.internal) {
|
||||
Ok(internal) => Ok(Self { internal }),
|
||||
Err((internal, err)) => Err((
|
||||
Box::new(Self {
|
||||
internal: *internal,
|
||||
}),
|
||||
err,
|
||||
)),
|
||||
Ok(_) => Ok(self),
|
||||
Err(err) => Err((Box::new(self), err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +270,7 @@ impl<'env> DynamicFunction<'env> {
|
|||
}
|
||||
|
||||
/// Returns the function info.
|
||||
pub fn info(&self) -> FunctionInfoType {
|
||||
pub fn info(&self) -> &FunctionInfo {
|
||||
self.internal.info()
|
||||
}
|
||||
|
||||
|
@ -350,7 +339,7 @@ impl Function for DynamicFunction<'static> {
|
|||
self.internal.name()
|
||||
}
|
||||
|
||||
fn info(&self) -> FunctionInfoType {
|
||||
fn info(&self) -> &FunctionInfo {
|
||||
self.internal.info()
|
||||
}
|
||||
|
||||
|
@ -484,10 +473,11 @@ impl<'env> IntoFunctionMut<'env, ()> for DynamicFunction<'env> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::func::{FunctionError, FunctionInfo, IntoReturn};
|
||||
use crate::func::signature::ArgumentSignature;
|
||||
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
|
||||
use crate::Type;
|
||||
use bevy_utils::HashSet;
|
||||
use std::ops::Add;
|
||||
use core::ops::Add;
|
||||
|
||||
#[test]
|
||||
fn should_overwrite_function_name() {
|
||||
|
@ -607,7 +597,7 @@ mod tests {
|
|||
},
|
||||
// The `FunctionInfo` doesn't really matter for this test
|
||||
// so we can just give it dummy information.
|
||||
FunctionInfo::anonymous()
|
||||
SignatureInfo::anonymous()
|
||||
.with_arg::<i32>("curr")
|
||||
.with_arg::<()>("this"),
|
||||
);
|
||||
|
@ -635,18 +625,18 @@ mod tests {
|
|||
}
|
||||
},
|
||||
vec![
|
||||
FunctionInfo::named("add::<i32>")
|
||||
SignatureInfo::named("add::<i32>")
|
||||
.with_arg::<i32>("a")
|
||||
.with_arg::<i32>("b")
|
||||
.with_return::<i32>(),
|
||||
FunctionInfo::named("add::<f32>")
|
||||
SignatureInfo::named("add::<f32>")
|
||||
.with_arg::<f32>("a")
|
||||
.with_arg::<f32>("b")
|
||||
.with_return::<f32>(),
|
||||
],
|
||||
);
|
||||
|
||||
assert!(func.name().is_none());
|
||||
assert_eq!(func.name().unwrap(), "add::<i32>");
|
||||
let func = func.with_name("add");
|
||||
assert_eq!(func.name().unwrap(), "add");
|
||||
|
||||
|
@ -660,9 +650,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(
|
||||
expected = "called `Result::unwrap()` on an `Err` value: MissingFunctionInfoError"
|
||||
)]
|
||||
#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: MissingSignature")]
|
||||
fn should_panic_on_missing_function_info() {
|
||||
let _ = DynamicFunction::new(|_| Ok(().into_return()), Vec::new());
|
||||
}
|
||||
|
@ -726,11 +714,11 @@ mod tests {
|
|||
}
|
||||
},
|
||||
vec![
|
||||
FunctionInfo::named("add::<i32>")
|
||||
SignatureInfo::named("add::<i32>")
|
||||
.with_arg::<i32>("a")
|
||||
.with_arg::<i32>("b")
|
||||
.with_return::<i32>(),
|
||||
FunctionInfo::named("add::<f32>")
|
||||
SignatureInfo::named("add::<f32>")
|
||||
.with_arg::<f32>("a")
|
||||
.with_arg::<f32>("b")
|
||||
.with_return::<f32>(),
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
use crate::func::signature::ArgumentSignature;
|
||||
use crate::func::{
|
||||
ArgList, FunctionError, FunctionInfo, FunctionInfoType, FunctionOverloadError,
|
||||
PrettyPrintFunctionInfo,
|
||||
};
|
||||
use crate::func::{ArgList, FunctionError, FunctionInfo, FunctionOverloadError};
|
||||
use alloc::borrow::Cow;
|
||||
use bevy_utils::hashbrown::HashMap;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
|
@ -18,45 +15,40 @@ use core::ops::RangeInclusive;
|
|||
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
|
||||
#[derive(Clone)]
|
||||
pub(super) struct DynamicFunctionInternal<F> {
|
||||
name: Option<Cow<'static, str>>,
|
||||
map: FunctionMap<F>,
|
||||
functions: Vec<F>,
|
||||
info: FunctionInfo,
|
||||
arg_map: HashMap<ArgumentSignature, usize>,
|
||||
}
|
||||
|
||||
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
|
||||
pub fn new(func: F, info: FunctionInfo) -> Self {
|
||||
let arg_map = info
|
||||
.signatures()
|
||||
.iter()
|
||||
.map(|info| (ArgumentSignature::from(info), 0))
|
||||
.map(|sig| (ArgumentSignature::from(sig), 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;
|
||||
Self {
|
||||
functions: vec![func],
|
||||
info,
|
||||
arg_map,
|
||||
}
|
||||
}
|
||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.info = self.info.with_name(Some(name.into()));
|
||||
self
|
||||
}
|
||||
|
||||
/// The name of the function.
|
||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||
self.name.as_ref()
|
||||
self.info.name()
|
||||
}
|
||||
|
||||
/// Returns `true` if the function is overloaded.
|
||||
pub fn is_overloaded(&self) -> bool {
|
||||
matches!(self.map, FunctionMap::Overloaded(..))
|
||||
self.info.is_overloaded()
|
||||
}
|
||||
|
||||
/// Get an immutable reference to the function.
|
||||
|
@ -66,52 +58,45 @@ impl<F> DynamicFunctionInternal<F> {
|
|||
///
|
||||
/// 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) => {
|
||||
if !self.info.is_overloaded() {
|
||||
return Ok(&self.functions[0]);
|
||||
}
|
||||
|
||||
let signature = ArgumentSignature::from(args);
|
||||
indices
|
||||
self.arg_map
|
||||
.get(&signature)
|
||||
.map(|index| &functions[*index])
|
||||
.map(|index| &self.functions[*index])
|
||||
.ok_or_else(|| FunctionError::NoOverload {
|
||||
expected: indices.keys().cloned().collect(),
|
||||
expected: self.arg_map.keys().cloned().collect(),
|
||||
received: signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an mutable reference to the function.
|
||||
/// Get a 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) => {
|
||||
if !self.info.is_overloaded() {
|
||||
return Ok(&mut self.functions[0]);
|
||||
}
|
||||
|
||||
let signature = ArgumentSignature::from(args);
|
||||
indices
|
||||
self.arg_map
|
||||
.get(&signature)
|
||||
.map(|index| &mut functions[*index])
|
||||
.map(|index| &mut self.functions[*index])
|
||||
.ok_or_else(|| FunctionError::NoOverload {
|
||||
expected: indices.keys().cloned().collect(),
|
||||
expected: self.arg_map.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))
|
||||
}
|
||||
}
|
||||
pub fn info(&self) -> &FunctionInfo {
|
||||
&self.info
|
||||
}
|
||||
|
||||
/// Returns the number of arguments the function expects.
|
||||
|
@ -121,7 +106,7 @@ impl<F> DynamicFunctionInternal<F> {
|
|||
///
|
||||
/// Otherwise, the range will have the same start and end.
|
||||
pub fn arg_count(&self) -> RangeInclusive<usize> {
|
||||
self.info().arg_count()
|
||||
self.info.arg_count()
|
||||
}
|
||||
|
||||
/// Helper method for validating that a given set of arguments are _potentially_ valid for this function.
|
||||
|
@ -155,215 +140,74 @@ impl<F> DynamicFunctionInternal<F> {
|
|||
/// `[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,
|
||||
)
|
||||
})?;
|
||||
pub fn merge(&mut self, mut other: Self) -> Result<(), FunctionOverloadError> {
|
||||
// Keep a separate map of the new indices to avoid mutating the existing one
|
||||
// until we can be sure the merge will be successful.
|
||||
let mut new_signatures = HashMap::new();
|
||||
|
||||
Ok(Self {
|
||||
name: self.name,
|
||||
map,
|
||||
})
|
||||
for (sig, index) in other.arg_map {
|
||||
if self.arg_map.contains_key(&sig) {
|
||||
return Err(FunctionOverloadError::DuplicateSignature(sig));
|
||||
}
|
||||
|
||||
/// Convert the inner [`FunctionMap`] from holding `F` to holding `G`.
|
||||
pub fn convert<G>(self, f: fn(FunctionMap<F>) -> FunctionMap<G>) -> DynamicFunctionInternal<G> {
|
||||
new_signatures.insert_unique_unchecked(sig, self.functions.len() + index);
|
||||
}
|
||||
|
||||
self.arg_map.reserve(new_signatures.len());
|
||||
for (sig, index) in new_signatures {
|
||||
self.arg_map.insert_unique_unchecked(sig, index);
|
||||
}
|
||||
|
||||
self.functions.append(&mut other.functions);
|
||||
self.info.extend_unchecked(other.info);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Maps the internally stored function(s) from type `F` to type `G`.
|
||||
pub fn map_functions<G>(self, f: fn(F) -> G) -> DynamicFunctionInternal<G> {
|
||||
DynamicFunctionInternal {
|
||||
name: self.name,
|
||||
map: f(self.map),
|
||||
functions: self.functions.into_iter().map(f).collect(),
|
||||
info: self.info,
|
||||
arg_map: self.arg_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].
|
||||
///
|
||||
/// By using an enum, we can optimize the common case of a single function,
|
||||
/// while still allowing for multiple function overloads to be stored.
|
||||
///
|
||||
/// [function information]: FunctionInfo
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) enum FunctionMap<F> {
|
||||
/// Represents a single, non-overloaded function.
|
||||
Single(F, FunctionInfo),
|
||||
/// Represents an overloaded function.
|
||||
Overloaded(
|
||||
/// The list of function overloads.
|
||||
Vec<F>,
|
||||
/// The information for each function.
|
||||
///
|
||||
/// Note that some functions may have multiple `FunctionInfo` values (i.e. manually created overloads),
|
||||
/// so this list may not always line up one-to-one with the functions list.
|
||||
Vec<FunctionInfo>,
|
||||
/// A mapping of argument signatures to the index of the corresponding function.
|
||||
///
|
||||
/// Multiple signatures may point to the same function index (i.e. for manually created overloads).
|
||||
HashMap<ArgumentSignature, usize>,
|
||||
),
|
||||
}
|
||||
|
||||
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 along with the original, unchanged map.
|
||||
///
|
||||
/// Therefore, this method should always return `Ok(Self::Overloaded(..))` 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)> {
|
||||
match (self, other) {
|
||||
(Self::Single(self_func, self_info), Self::Single(other_func, other_info)) => {
|
||||
let self_sig = ArgumentSignature::from(&self_info);
|
||||
let other_sig = ArgumentSignature::from(&other_info);
|
||||
if self_sig == other_sig {
|
||||
return Err((
|
||||
Box::new(Self::Single(self_func, self_info)),
|
||||
FunctionOverloadError {
|
||||
signature: self_sig,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert_unique_unchecked(self_sig, 0);
|
||||
map.insert_unique_unchecked(other_sig, 1);
|
||||
|
||||
Ok(Self::Overloaded(
|
||||
vec![self_func, other_func],
|
||||
vec![self_info, other_info],
|
||||
map,
|
||||
))
|
||||
}
|
||||
(
|
||||
Self::Single(self_func, self_info),
|
||||
Self::Overloaded(mut other_funcs, mut other_infos, mut other_indices),
|
||||
) => {
|
||||
let self_sig = ArgumentSignature::from(&self_info);
|
||||
if other_indices.contains_key(&self_sig) {
|
||||
return Err((
|
||||
Box::new(Self::Single(self_func, self_info)),
|
||||
FunctionOverloadError {
|
||||
signature: self_sig,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
for index in other_indices.values_mut() {
|
||||
*index += 1;
|
||||
}
|
||||
|
||||
other_funcs.insert(0, self_func);
|
||||
other_infos.insert(0, self_info);
|
||||
other_indices.insert_unique_unchecked(self_sig, 0);
|
||||
|
||||
Ok(Self::Overloaded(other_funcs, other_infos, other_indices))
|
||||
}
|
||||
(
|
||||
Self::Overloaded(mut self_funcs, mut self_infos, mut self_indices),
|
||||
Self::Single(other_func, other_info),
|
||||
) => {
|
||||
let other_sig = ArgumentSignature::from(&other_info);
|
||||
if self_indices.contains_key(&other_sig) {
|
||||
return Err((
|
||||
Box::new(Self::Overloaded(self_funcs, self_infos, self_indices)),
|
||||
FunctionOverloadError {
|
||||
signature: other_sig,
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
let index = self_funcs.len();
|
||||
self_funcs.push(other_func);
|
||||
self_infos.push(other_info);
|
||||
self_indices.insert_unique_unchecked(other_sig, index);
|
||||
|
||||
Ok(Self::Overloaded(self_funcs, self_infos, self_indices))
|
||||
}
|
||||
(
|
||||
Self::Overloaded(mut self_funcs, mut self_infos, mut self_indices),
|
||||
Self::Overloaded(mut other_funcs, mut other_infos, other_indices),
|
||||
) => {
|
||||
// Keep a separate map of the new indices to avoid mutating the existing one
|
||||
// until we can be sure the merge will be successful.
|
||||
let mut new_indices = HashMap::new();
|
||||
|
||||
for (sig, index) in other_indices {
|
||||
if self_indices.contains_key(&sig) {
|
||||
return Err((
|
||||
Box::new(Self::Overloaded(self_funcs, self_infos, self_indices)),
|
||||
FunctionOverloadError { signature: sig },
|
||||
));
|
||||
}
|
||||
|
||||
new_indices.insert_unique_unchecked(sig, self_funcs.len() + index);
|
||||
}
|
||||
|
||||
self_indices.reserve(new_indices.len());
|
||||
for (sig, index) in new_indices {
|
||||
self_indices.insert_unique_unchecked(sig, index);
|
||||
}
|
||||
|
||||
self_funcs.append(&mut other_funcs);
|
||||
// The index map and `FunctionInfo` list should always be in sync,
|
||||
// so we can simply append the new infos to the existing ones.
|
||||
self_infos.append(&mut other_infos);
|
||||
|
||||
Ok(Self::Overloaded(self_funcs, self_infos, self_indices))
|
||||
}
|
||||
}
|
||||
self.info
|
||||
.pretty_printer()
|
||||
.include_fn_token()
|
||||
.include_name()
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::func::FunctionInfo;
|
||||
use crate::func::{FunctionInfo, SignatureInfo};
|
||||
use crate::Type;
|
||||
|
||||
#[test]
|
||||
fn should_merge_single_into_single() {
|
||||
let map_a = FunctionMap::Single('a', FunctionInfo::anonymous().with_arg::<i8>("arg0"));
|
||||
let map_b = FunctionMap::Single('b', FunctionInfo::anonymous().with_arg::<u8>("arg0"));
|
||||
let mut func_a = DynamicFunctionInternal::new(
|
||||
'a',
|
||||
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
|
||||
);
|
||||
|
||||
let FunctionMap::Overloaded(functions, infos, indices) = map_a.merge(map_b).unwrap() else {
|
||||
panic!("expected overloaded function");
|
||||
};
|
||||
assert_eq!(functions, vec!['a', 'b']);
|
||||
assert_eq!(infos.len(), 2);
|
||||
let func_b = DynamicFunctionInternal::new(
|
||||
'b',
|
||||
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
|
||||
);
|
||||
|
||||
func_a.merge(func_b).unwrap();
|
||||
|
||||
assert_eq!(func_a.functions, vec!['a', 'b']);
|
||||
assert_eq!(func_a.info.signatures().len(), 2);
|
||||
assert_eq!(
|
||||
indices,
|
||||
func_a.arg_map,
|
||||
HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
|
||||
|
@ -373,26 +217,28 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn should_merge_single_into_overloaded() {
|
||||
let map_a = FunctionMap::Single('a', FunctionInfo::anonymous().with_arg::<i8>("arg0"));
|
||||
let map_b = FunctionMap::Overloaded(
|
||||
vec!['b', 'c'],
|
||||
vec![
|
||||
FunctionInfo::anonymous().with_arg::<u8>("arg0"),
|
||||
FunctionInfo::anonymous().with_arg::<u16>("arg0"),
|
||||
],
|
||||
HashMap::from_iter([
|
||||
let mut func_a = DynamicFunctionInternal::new(
|
||||
'a',
|
||||
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),
|
||||
);
|
||||
|
||||
let func_b = DynamicFunctionInternal {
|
||||
functions: vec!['b', 'c'],
|
||||
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
|
||||
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
|
||||
.unwrap(),
|
||||
arg_map: HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
|
||||
]),
|
||||
);
|
||||
|
||||
let FunctionMap::Overloaded(functions, infos, indices) = map_a.merge(map_b).unwrap() else {
|
||||
panic!("expected overloaded function");
|
||||
};
|
||||
assert_eq!(functions, vec!['a', 'b', 'c']);
|
||||
assert_eq!(infos.len(), 3);
|
||||
|
||||
func_a.merge(func_b).unwrap();
|
||||
|
||||
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
|
||||
assert_eq!(func_a.info.signatures().len(), 3);
|
||||
assert_eq!(
|
||||
indices,
|
||||
func_a.arg_map,
|
||||
HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),
|
||||
|
@ -403,26 +249,28 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn should_merge_overloaed_into_single() {
|
||||
let map_a = FunctionMap::Overloaded(
|
||||
vec!['a', 'b'],
|
||||
vec![
|
||||
FunctionInfo::anonymous().with_arg::<i8>("arg0"),
|
||||
FunctionInfo::anonymous().with_arg::<i16>("arg0"),
|
||||
],
|
||||
HashMap::from_iter([
|
||||
let mut func_a = DynamicFunctionInternal {
|
||||
functions: vec!['a', 'b'],
|
||||
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
|
||||
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
|
||||
.unwrap(),
|
||||
arg_map: HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
|
||||
]),
|
||||
);
|
||||
let map_b = FunctionMap::Single('c', FunctionInfo::anonymous().with_arg::<u8>("arg0"));
|
||||
|
||||
let FunctionMap::Overloaded(functions, infos, indices) = map_a.merge(map_b).unwrap() else {
|
||||
panic!("expected overloaded function");
|
||||
};
|
||||
assert_eq!(functions, vec!['a', 'b', 'c']);
|
||||
assert_eq!(infos.len(), 3);
|
||||
|
||||
let func_b = DynamicFunctionInternal::new(
|
||||
'c',
|
||||
FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),
|
||||
);
|
||||
|
||||
func_a.merge(func_b).unwrap();
|
||||
|
||||
assert_eq!(func_a.functions, vec!['a', 'b', 'c']);
|
||||
assert_eq!(func_a.info.signatures().len(), 3);
|
||||
assert_eq!(
|
||||
indices,
|
||||
func_a.arg_map,
|
||||
HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
|
||||
|
@ -433,36 +281,34 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn should_merge_overloaded_into_overloaded() {
|
||||
let map_a = FunctionMap::Overloaded(
|
||||
vec!['a', 'b'],
|
||||
vec![
|
||||
FunctionInfo::anonymous().with_arg::<i8>("arg0"),
|
||||
FunctionInfo::anonymous().with_arg::<i16>("arg0"),
|
||||
],
|
||||
HashMap::from_iter([
|
||||
let mut func_a = DynamicFunctionInternal {
|
||||
functions: vec!['a', 'b'],
|
||||
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))
|
||||
.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))
|
||||
.unwrap(),
|
||||
arg_map: HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
|
||||
]),
|
||||
);
|
||||
let map_b = FunctionMap::Overloaded(
|
||||
vec!['c', 'd'],
|
||||
vec![
|
||||
FunctionInfo::anonymous().with_arg::<u8>("arg0"),
|
||||
FunctionInfo::anonymous().with_arg::<u16>("arg0"),
|
||||
],
|
||||
HashMap::from_iter([
|
||||
};
|
||||
|
||||
let func_b = DynamicFunctionInternal {
|
||||
functions: vec!['c', 'd'],
|
||||
info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))
|
||||
.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))
|
||||
.unwrap(),
|
||||
arg_map: HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),
|
||||
]),
|
||||
);
|
||||
|
||||
let FunctionMap::Overloaded(functions, infos, indices) = map_a.merge(map_b).unwrap() else {
|
||||
panic!("expected overloaded function");
|
||||
};
|
||||
assert_eq!(functions, vec!['a', 'b', 'c', 'd']);
|
||||
assert_eq!(infos.len(), 4);
|
||||
|
||||
func_a.merge(func_b).unwrap();
|
||||
|
||||
assert_eq!(func_a.functions, vec!['a', 'b', 'c', 'd']);
|
||||
assert_eq!(func_a.info.signatures().len(), 4);
|
||||
assert_eq!(
|
||||
indices,
|
||||
func_a.arg_map,
|
||||
HashMap::from_iter([
|
||||
(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),
|
||||
(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),
|
||||
|
@ -474,19 +320,29 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn should_return_error_on_duplicate_signature() {
|
||||
let map_a = FunctionMap::Single(
|
||||
let mut func_a = DynamicFunctionInternal::new(
|
||||
'a',
|
||||
FunctionInfo::anonymous()
|
||||
FunctionInfo::new(
|
||||
SignatureInfo::anonymous()
|
||||
.with_arg::<i8>("arg0")
|
||||
.with_arg::<i16>("arg1"),
|
||||
),
|
||||
);
|
||||
let map_b = FunctionMap::Overloaded(
|
||||
vec!['b', 'c'],
|
||||
vec![
|
||||
FunctionInfo::anonymous().with_arg::<u8>("arg0"),
|
||||
FunctionInfo::anonymous().with_arg::<u16>("arg1"),
|
||||
],
|
||||
HashMap::from_iter([
|
||||
|
||||
let func_b = DynamicFunctionInternal {
|
||||
functions: vec!['b', 'c'],
|
||||
info: FunctionInfo::new(
|
||||
SignatureInfo::anonymous()
|
||||
.with_arg::<u8>("arg0")
|
||||
.with_arg::<u16>("arg1"),
|
||||
)
|
||||
.with_overload(
|
||||
SignatureInfo::anonymous()
|
||||
.with_arg::<i8>("arg0")
|
||||
.with_arg::<i16>("arg1"),
|
||||
)
|
||||
.unwrap(),
|
||||
arg_map: HashMap::from_iter([
|
||||
(
|
||||
ArgumentSignature::from_iter([Type::of::<u8>(), Type::of::<u16>()]),
|
||||
0,
|
||||
|
@ -496,23 +352,29 @@ mod tests {
|
|||
1,
|
||||
),
|
||||
]),
|
||||
);
|
||||
|
||||
let (map, error) = map_a.merge(map_b).unwrap_err();
|
||||
assert_eq!(
|
||||
error.signature,
|
||||
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()])
|
||||
);
|
||||
|
||||
// Assert the original map remains unchanged:
|
||||
let FunctionMap::Single(function, info) = *map else {
|
||||
panic!("expected single function");
|
||||
};
|
||||
|
||||
assert_eq!(function, 'a');
|
||||
let FunctionOverloadError::DuplicateSignature(duplicate) =
|
||||
func_a.merge(func_b).unwrap_err()
|
||||
else {
|
||||
panic!("Expected `FunctionOverloadError::DuplicateSignature`");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
ArgumentSignature::from(info),
|
||||
duplicate,
|
||||
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()])
|
||||
);
|
||||
|
||||
// Assert the original remains unchanged:
|
||||
assert!(!func_a.is_overloaded());
|
||||
assert_eq!(func_a.functions, vec!['a']);
|
||||
assert_eq!(func_a.info.signatures().len(), 1);
|
||||
assert_eq!(
|
||||
func_a.arg_map,
|
||||
HashMap::from_iter([(
|
||||
ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),
|
||||
0
|
||||
),])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +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, dynamic_function_internal::DynamicFunctionInternal, DynamicFunction,
|
||||
FunctionError, FunctionInfoType, FunctionOverloadError, FunctionResult, IntoFunctionMut,
|
||||
FunctionInfo, FunctionOverloadError, FunctionResult, IntoFunctionMut,
|
||||
};
|
||||
|
||||
/// A [`Box`] containing a callback to a reflected function.
|
||||
|
@ -86,14 +85,14 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if no [`FunctionInfo`] is provided or if the conversion to [`FunctionInfoType`] fails.
|
||||
/// Panics if no [`SignatureInfo`] is provided or if the conversion to [`FunctionInfo`] fails.
|
||||
///
|
||||
/// [calling]: crate::func::dynamic_function_mut::DynamicFunctionMut::call
|
||||
/// [`FunctionInfo`]: crate::func::FunctionInfo
|
||||
/// [`SignatureInfo`]: crate::func::SignatureInfo
|
||||
/// [function overloading]: Self::with_overload
|
||||
pub fn new<F: for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>(
|
||||
func: F,
|
||||
info: impl TryInto<FunctionInfoType<'static>, Error: Debug>,
|
||||
info: impl TryInto<FunctionInfo, Error: Debug>,
|
||||
) -> Self {
|
||||
Self {
|
||||
internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),
|
||||
|
@ -109,7 +108,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// [`DynamicFunctionMuts`]: DynamicFunctionMut
|
||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.internal.set_name(Some(name.into()));
|
||||
self.internal = self.internal.with_name(name);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -167,7 +166,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
/// assert_eq!(total_f32, 1.23);
|
||||
/// ```
|
||||
///
|
||||
/// [argument signature]: ArgumentSignature
|
||||
/// [argument signature]: crate::func::signature::ArgumentSignature
|
||||
/// [name]: Self::name
|
||||
/// [`try_with_overload`]: Self::try_with_overload
|
||||
pub fn with_overload<'a, F: IntoFunctionMut<'a, Marker>, Marker>(
|
||||
|
@ -177,16 +176,9 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
where
|
||||
'env: 'a,
|
||||
{
|
||||
let function = function.into_function_mut();
|
||||
|
||||
let internal = self
|
||||
.internal
|
||||
.merge(function.internal)
|
||||
.unwrap_or_else(|(_, err)| {
|
||||
self.try_with_overload(function).unwrap_or_else(|(_, err)| {
|
||||
panic!("{}", err);
|
||||
});
|
||||
|
||||
DynamicFunctionMut { internal }
|
||||
})
|
||||
}
|
||||
|
||||
/// Attempt to add an overload to this function.
|
||||
|
@ -198,19 +190,14 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
///
|
||||
/// [`with_overload`]: Self::with_overload
|
||||
pub fn try_with_overload<F: IntoFunctionMut<'env, Marker>, Marker>(
|
||||
self,
|
||||
mut self,
|
||||
function: F,
|
||||
) -> Result<Self, (Box<Self>, FunctionOverloadError)> {
|
||||
let function = function.into_function_mut();
|
||||
|
||||
match self.internal.merge(function.internal) {
|
||||
Ok(internal) => Ok(Self { internal }),
|
||||
Err((internal, err)) => Err((
|
||||
Box::new(Self {
|
||||
internal: *internal,
|
||||
}),
|
||||
err,
|
||||
)),
|
||||
Ok(_) => Ok(self),
|
||||
Err(err) => Err((Box::new(self), err)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +271,7 @@ impl<'env> DynamicFunctionMut<'env> {
|
|||
}
|
||||
|
||||
/// Returns the function info.
|
||||
pub fn info(&self) -> FunctionInfoType {
|
||||
pub fn info(&self) -> &FunctionInfo {
|
||||
self.internal.info()
|
||||
}
|
||||
|
||||
|
@ -367,14 +354,7 @@ impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {
|
|||
#[inline]
|
||||
fn from(function: DynamicFunction<'env>) -> Self {
|
||||
Self {
|
||||
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,
|
||||
),
|
||||
}),
|
||||
internal: function.internal.map_functions(arc_to_box),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -398,8 +378,8 @@ impl<'env> IntoFunctionMut<'env, ()> for DynamicFunctionMut<'env> {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::func::{FunctionInfo, IntoReturn};
|
||||
use std::ops::Add;
|
||||
use crate::func::{FunctionError, IntoReturn, SignatureInfo};
|
||||
use core::ops::Add;
|
||||
|
||||
#[test]
|
||||
fn should_overwrite_function_name() {
|
||||
|
@ -466,12 +446,12 @@ mod tests {
|
|||
Ok(().into_return())
|
||||
},
|
||||
vec![
|
||||
FunctionInfo::named("add::<i32>").with_arg::<i32>("value"),
|
||||
FunctionInfo::named("add::<i16>").with_arg::<i16>("value"),
|
||||
SignatureInfo::named("add::<i32>").with_arg::<i32>("value"),
|
||||
SignatureInfo::named("add::<i16>").with_arg::<i16>("value"),
|
||||
],
|
||||
);
|
||||
|
||||
assert!(func.name().is_none());
|
||||
assert_eq!(func.name().unwrap(), "add::<i32>");
|
||||
let mut func = func.with_name("add");
|
||||
assert_eq!(func.name().unwrap(), "add");
|
||||
|
||||
|
|
|
@ -40,18 +40,17 @@ pub enum FunctionError {
|
|||
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
|
||||
pub type FunctionResult<'a> = Result<Return<'a>, FunctionError>;
|
||||
|
||||
/// A [`FunctionInfo`] was expected but none was found.
|
||||
///
|
||||
/// [`FunctionInfo`]: crate::func::FunctionInfo
|
||||
/// An error that occurs when attempting to add a function overload.
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
#[error("expected a `FunctionInfo` but found none")]
|
||||
pub struct MissingFunctionInfoError;
|
||||
|
||||
/// An error that occurs when attempting to add a function overload with a duplicate signature.
|
||||
#[derive(Debug, Error, PartialEq)]
|
||||
#[error("could not add function overload: duplicate found for signature `{signature:?}`")]
|
||||
pub struct FunctionOverloadError {
|
||||
pub signature: ArgumentSignature,
|
||||
pub enum FunctionOverloadError {
|
||||
/// A [`SignatureInfo`] was expected, but none was found.
|
||||
///
|
||||
/// [`SignatureInfo`]: crate::func::info::SignatureInfo
|
||||
#[error("expected at least one `SignatureInfo` but found none")]
|
||||
MissingSignature,
|
||||
/// An error that occurs when attempting to add a function overload with a duplicate signature.
|
||||
#[error("could not add function overload: duplicate found for signature `{0:?}`")]
|
||||
DuplicateSignature(ArgumentSignature),
|
||||
}
|
||||
|
||||
/// An error that occurs when registering a function into a [`FunctionRegistry`].
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
func::{ArgList, DynamicFunction, FunctionInfoType, FunctionResult},
|
||||
func::{ArgList, DynamicFunction, FunctionInfo, FunctionResult},
|
||||
PartialReflect,
|
||||
};
|
||||
use alloc::borrow::Cow;
|
||||
|
@ -50,18 +50,16 @@ pub trait Function: PartialReflect + Debug {
|
|||
|
||||
/// Returns the number of arguments the function expects.
|
||||
///
|
||||
/// For [overloaded] functions that can have a variable number of arguments,
|
||||
/// 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]: FunctionInfoType::Overloaded
|
||||
fn arg_count(&self) -> RangeInclusive<usize> {
|
||||
self.info().arg_count()
|
||||
}
|
||||
|
||||
/// The [`FunctionInfoType`] for this function.
|
||||
fn info(&self) -> FunctionInfoType;
|
||||
/// The [`FunctionInfo`] for this function.
|
||||
fn info(&self) -> &FunctionInfo;
|
||||
|
||||
/// Call this function with the given arguments.
|
||||
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
|
||||
|
|
|
@ -3,134 +3,232 @@ use alloc::{borrow::Cow, vec};
|
|||
#[cfg(not(feature = "std"))]
|
||||
use alloc::{boxed::Box, format, vec};
|
||||
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use core::ops::RangeInclusive;
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
use crate::{
|
||||
func::{
|
||||
args::{ArgInfo, GetOwnership, Ownership},
|
||||
MissingFunctionInfoError,
|
||||
},
|
||||
func::args::{ArgInfo, GetOwnership, Ownership},
|
||||
func::signature::ArgumentSignature,
|
||||
func::FunctionOverloadError,
|
||||
type_info::impl_type_methods,
|
||||
Type, TypePath,
|
||||
};
|
||||
|
||||
/// A wrapper around [`FunctionInfo`] used to represent either a standard function
|
||||
/// or an overloaded function.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum FunctionInfoType<'a> {
|
||||
/// A standard function with a single set of arguments.
|
||||
///
|
||||
/// This includes generic functions with a single set of monomorphized arguments.
|
||||
Standard(Cow<'a, FunctionInfo>),
|
||||
/// An overloaded function with multiple sets of arguments.
|
||||
///
|
||||
/// This includes generic functions with multiple sets of monomorphized arguments,
|
||||
/// as well as functions with a variable number of arguments (i.e. "variadic functions").
|
||||
Overloaded(Cow<'a, [FunctionInfo]>),
|
||||
}
|
||||
|
||||
impl From<FunctionInfo> for FunctionInfoType<'_> {
|
||||
fn from(info: FunctionInfo) -> Self {
|
||||
FunctionInfoType::Standard(Cow::Owned(info))
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<FunctionInfo>> for FunctionInfoType<'_> {
|
||||
type Error = MissingFunctionInfoError;
|
||||
|
||||
fn try_from(mut infos: Vec<FunctionInfo>) -> Result<Self, Self::Error> {
|
||||
match infos.len() {
|
||||
0 => Err(MissingFunctionInfoError),
|
||||
1 => Ok(Self::Standard(Cow::Owned(infos.pop().unwrap()))),
|
||||
_ => Ok(Self::Overloaded(Cow::Owned(infos))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for FunctionInfoType<'_> {
|
||||
type Item = FunctionInfo;
|
||||
type IntoIter = vec::IntoIter<FunctionInfo>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
// Allow `.into_owned()` so that we can create a `std::vec::IntoIter`
|
||||
#[allow(clippy::unnecessary_to_owned)]
|
||||
match self {
|
||||
FunctionInfoType::Standard(info) => vec![info.into_owned()].into_iter(),
|
||||
FunctionInfoType::Overloaded(infos) => infos.into_owned().into_iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FunctionInfoType<'_> {
|
||||
/// 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> {
|
||||
match self {
|
||||
Self::Standard(info) => RangeInclusive::new(info.arg_count(), info.arg_count()),
|
||||
Self::Overloaded(infos) => infos.iter().map(FunctionInfo::arg_count).fold(
|
||||
RangeInclusive::new(usize::MAX, usize::MIN),
|
||||
|acc, count| {
|
||||
RangeInclusive::new((*acc.start()).min(count), (*acc.end()).max(count))
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use core::ops::RangeInclusive;
|
||||
use variadics_please::all_tuples;
|
||||
|
||||
/// Type information for a [`DynamicFunction`] or [`DynamicFunctionMut`].
|
||||
///
|
||||
/// This information can be retrieved directly from certain functions and closures
|
||||
/// using the [`TypedFunction`] trait, and manually constructed otherwise.
|
||||
///
|
||||
/// It is compromised of one or more [`SignatureInfo`] structs,
|
||||
/// allowing it to represent functions with multiple sets of arguments (i.e. "overloaded functions").
|
||||
///
|
||||
/// [`DynamicFunction`]: crate::func::DynamicFunction
|
||||
/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FunctionInfo {
|
||||
name: Option<Cow<'static, str>>,
|
||||
args: Vec<ArgInfo>,
|
||||
return_info: ReturnInfo,
|
||||
signatures: Box<[SignatureInfo]>,
|
||||
}
|
||||
|
||||
impl FunctionInfo {
|
||||
/// Create a new [`FunctionInfo`] for a function with the given name.
|
||||
/// Create a new [`FunctionInfo`] for a function with the given signature.
|
||||
pub fn new(signature: SignatureInfo) -> Self {
|
||||
Self {
|
||||
name: signature.name.clone(),
|
||||
signatures: vec![signature].into(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`FunctionInfo`] from a set of signatures.
|
||||
///
|
||||
/// Returns an error if the given iterator is empty or contains duplicate signatures.
|
||||
pub fn try_from_iter(
|
||||
signatures: impl IntoIterator<Item = SignatureInfo>,
|
||||
) -> Result<Self, FunctionOverloadError> {
|
||||
let mut iter = signatures.into_iter();
|
||||
|
||||
let mut info = Self::new(iter.next().ok_or(FunctionOverloadError::MissingSignature)?);
|
||||
|
||||
for signature in iter {
|
||||
info = info.with_overload(signature).map_err(|sig| {
|
||||
FunctionOverloadError::DuplicateSignature(ArgumentSignature::from(&sig))
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
/// The base signature for this function.
|
||||
///
|
||||
/// All functions—including overloaded functions—are guaranteed to have at least one signature.
|
||||
/// The first signature used to define the [`FunctionInfo`] is considered the base signature.
|
||||
pub fn base(&self) -> &SignatureInfo {
|
||||
&self.signatures[0]
|
||||
}
|
||||
|
||||
/// Whether this function is overloaded.
|
||||
///
|
||||
/// This is determined by the existence of multiple signatures.
|
||||
pub fn is_overloaded(&self) -> bool {
|
||||
self.signatures.len() > 1
|
||||
}
|
||||
|
||||
/// Set the name of the function.
|
||||
pub fn with_name(mut self, name: Option<impl Into<Cow<'static, str>>>) -> Self {
|
||||
self.name = name.map(Into::into);
|
||||
self
|
||||
}
|
||||
|
||||
/// The name of the function.
|
||||
///
|
||||
/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],
|
||||
/// the default name will always be the full path to the function as returned by [`std::any::type_name`],
|
||||
/// unless the function is a closure, anonymous function, or function pointer,
|
||||
/// in which case the name will be `None`.
|
||||
///
|
||||
/// For overloaded functions, this will be the name of the base signature,
|
||||
/// unless manually overwritten using [`Self::with_name`].
|
||||
///
|
||||
/// [`DynamicFunctions`]: crate::func::DynamicFunction
|
||||
/// [`IntoFunction`]: crate::func::IntoFunction
|
||||
/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut
|
||||
/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut
|
||||
pub fn name(&self) -> Option<&Cow<'static, str>> {
|
||||
self.name.as_ref()
|
||||
}
|
||||
|
||||
/// Add a signature to this function.
|
||||
///
|
||||
/// If a signature with the same [`ArgumentSignature`] already exists,
|
||||
/// an error is returned with the given signature.
|
||||
pub fn with_overload(mut self, signature: SignatureInfo) -> Result<Self, SignatureInfo> {
|
||||
let is_duplicate = self.signatures.iter().any(|s| {
|
||||
s.arg_count() == signature.arg_count()
|
||||
&& ArgumentSignature::from(s) == ArgumentSignature::from(&signature)
|
||||
});
|
||||
|
||||
if is_duplicate {
|
||||
return Err(signature);
|
||||
}
|
||||
|
||||
self.signatures = IntoIterator::into_iter(self.signatures)
|
||||
.chain(Some(signature))
|
||||
.collect();
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// 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.signatures
|
||||
.iter()
|
||||
.map(SignatureInfo::arg_count)
|
||||
.fold(RangeInclusive::new(usize::MAX, usize::MIN), |acc, count| {
|
||||
RangeInclusive::new((*acc.start()).min(count), (*acc.end()).max(count))
|
||||
})
|
||||
}
|
||||
|
||||
/// The signatures of the function.
|
||||
///
|
||||
/// This is guaranteed to always contain at least one signature.
|
||||
/// Overloaded functions will contain two or more.
|
||||
pub fn signatures(&self) -> &[SignatureInfo] {
|
||||
&self.signatures
|
||||
}
|
||||
|
||||
/// Returns a wrapper around this info that implements [`Debug`] for pretty-printing the function.
|
||||
///
|
||||
/// This can be useful for more readable debugging and logging.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_reflect::func::{FunctionInfo, TypedFunction};
|
||||
/// #
|
||||
/// fn add(a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
/// }
|
||||
///
|
||||
/// let info = add.get_function_info();
|
||||
///
|
||||
/// let pretty = info.pretty_printer();
|
||||
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
|
||||
/// ```
|
||||
pub fn pretty_printer(&self) -> PrettyPrintFunctionInfo {
|
||||
PrettyPrintFunctionInfo::new(self)
|
||||
}
|
||||
|
||||
/// Extend this [`FunctionInfo`] with another without checking for duplicates.
|
||||
pub(super) fn extend_unchecked(&mut self, other: FunctionInfo) {
|
||||
if self.name.is_none() {
|
||||
self.name = other.name;
|
||||
}
|
||||
|
||||
let signatures = core::mem::take(&mut self.signatures);
|
||||
self.signatures = IntoIterator::into_iter(signatures)
|
||||
.chain(IntoIterator::into_iter(other.signatures))
|
||||
.collect();
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignatureInfo> for FunctionInfo {
|
||||
fn from(info: SignatureInfo) -> Self {
|
||||
Self::new(info)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<SignatureInfo>> for FunctionInfo {
|
||||
type Error = FunctionOverloadError;
|
||||
|
||||
fn try_from(signatures: Vec<SignatureInfo>) -> Result<Self, Self::Error> {
|
||||
Self::try_from_iter(signatures)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> TryFrom<[SignatureInfo; N]> for FunctionInfo {
|
||||
type Error = FunctionOverloadError;
|
||||
|
||||
fn try_from(signatures: [SignatureInfo; N]) -> Result<Self, Self::Error> {
|
||||
Self::try_from_iter(signatures)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SignatureInfo {
|
||||
name: Option<Cow<'static, str>>,
|
||||
args: Box<[ArgInfo]>,
|
||||
return_info: ReturnInfo,
|
||||
}
|
||||
|
||||
impl SignatureInfo {
|
||||
/// Create a new [`SignatureInfo`] for a function with the given name.
|
||||
pub fn named(name: impl Into<Cow<'static, str>>) -> Self {
|
||||
Self {
|
||||
name: Some(name.into()),
|
||||
args: Vec::new(),
|
||||
args: Box::new([]),
|
||||
return_info: ReturnInfo::new::<()>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`FunctionInfo`] with no name.
|
||||
/// Create a new [`SignatureInfo`] with no name.
|
||||
///
|
||||
/// For the purposes of debugging and [registration],
|
||||
/// it's recommended to use [`FunctionInfo::named`] instead.
|
||||
/// it's recommended to use [`Self::named`] instead.
|
||||
///
|
||||
/// [registration]: crate::func::FunctionRegistry
|
||||
pub fn anonymous() -> Self {
|
||||
Self {
|
||||
name: None,
|
||||
args: Vec::new(),
|
||||
args: Box::new([]),
|
||||
return_info: ReturnInfo::new::<()>(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new [`FunctionInfo`] from the given function.
|
||||
pub fn from<F, Marker>(function: &F) -> Self
|
||||
where
|
||||
F: TypedFunction<Marker>,
|
||||
{
|
||||
function.get_function_info()
|
||||
}
|
||||
|
||||
/// Set the name of the function.
|
||||
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
|
||||
self.name = Some(name.into());
|
||||
|
@ -146,7 +244,9 @@ impl FunctionInfo {
|
|||
name: impl Into<Cow<'static, str>>,
|
||||
) -> Self {
|
||||
let index = self.args.len();
|
||||
self.args.push(ArgInfo::new::<T>(index).with_name(name));
|
||||
self.args = IntoIterator::into_iter(self.args)
|
||||
.chain(Some(ArgInfo::new::<T>(index).with_name(name)))
|
||||
.collect();
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -157,7 +257,7 @@ impl FunctionInfo {
|
|||
/// It's preferable to use [`Self::with_arg`] to add arguments to the function
|
||||
/// as it will automatically set the index of the argument.
|
||||
pub fn with_args(mut self, args: Vec<ArgInfo>) -> Self {
|
||||
self.args = args;
|
||||
self.args = IntoIterator::into_iter(self.args).chain(args).collect();
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -212,28 +312,6 @@ impl FunctionInfo {
|
|||
pub fn return_info(&self) -> &ReturnInfo {
|
||||
&self.return_info
|
||||
}
|
||||
|
||||
/// Returns a wrapper around this info that implements [`Debug`] for pretty-printing the function.
|
||||
///
|
||||
/// This can be useful for more readable debugging and logging.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_reflect::func::{FunctionInfo, TypedFunction};
|
||||
/// #
|
||||
/// fn add(a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
/// }
|
||||
///
|
||||
/// let info = add.get_function_info();
|
||||
///
|
||||
/// let pretty = info.pretty_printer();
|
||||
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
|
||||
/// ```
|
||||
pub fn pretty_printer(&self) -> PrettyPrintFunctionInfo {
|
||||
PrettyPrintFunctionInfo::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about the return type of a [`DynamicFunction`] or [`DynamicFunctionMut`].
|
||||
|
@ -309,6 +387,81 @@ impl<'a> PrettyPrintFunctionInfo<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Debug for PrettyPrintFunctionInfo<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
if self.include_fn_token {
|
||||
write!(f, "fn")?;
|
||||
|
||||
if self.include_name {
|
||||
write!(f, " ")?;
|
||||
}
|
||||
}
|
||||
|
||||
match (self.include_name, self.info.name()) {
|
||||
(true, Some(name)) => write!(f, "{}", name)?,
|
||||
(true, None) => write!(f, "_")?,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if self.info.is_overloaded() {
|
||||
// `{(arg0: i32, arg1: i32) -> (), (arg0: f32, arg1: f32) -> ()}`
|
||||
let mut set = f.debug_set();
|
||||
for signature in self.info.signatures() {
|
||||
set.entry(&PrettyPrintSignatureInfo::new(signature));
|
||||
}
|
||||
set.finish()
|
||||
} else {
|
||||
// `(arg0: i32, arg1: i32) -> ()`
|
||||
PrettyPrintSignatureInfo::new(self.info.base()).fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper around [`SignatureInfo`] that implements [`Debug`] for pretty-printing function signature information.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintSignatureInfo, TypedFunction};
|
||||
/// #
|
||||
/// fn add(a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
/// }
|
||||
///
|
||||
/// let info = add.get_function_info();
|
||||
///
|
||||
/// let pretty = PrettyPrintSignatureInfo::new(info.base());
|
||||
/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
|
||||
/// ```
|
||||
pub struct PrettyPrintSignatureInfo<'a> {
|
||||
info: &'a SignatureInfo,
|
||||
include_fn_token: bool,
|
||||
include_name: bool,
|
||||
}
|
||||
|
||||
impl<'a> PrettyPrintSignatureInfo<'a> {
|
||||
/// Create a new pretty-printer for the given [`SignatureInfo`].
|
||||
pub fn new(info: &'a SignatureInfo) -> Self {
|
||||
Self {
|
||||
info,
|
||||
include_fn_token: false,
|
||||
include_name: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Include the function name in the pretty-printed output.
|
||||
pub fn include_name(mut self) -> Self {
|
||||
self.include_name = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Include the `fn` token in the pretty-printed output.
|
||||
pub fn include_fn_token(mut self) -> Self {
|
||||
self.include_fn_token = true;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for PrettyPrintSignatureInfo<'a> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
|
||||
if self.include_fn_token {
|
||||
write!(f, "fn")?;
|
||||
|
@ -370,7 +523,7 @@ impl<'a> Debug for PrettyPrintFunctionInfo<'a> {
|
|||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFnMut, TypedFunction};
|
||||
/// # use bevy_reflect::func::{ArgList, ReflectFnMut, TypedFunction};
|
||||
/// #
|
||||
/// fn print(value: String) {
|
||||
/// println!("{}", value);
|
||||
|
@ -378,9 +531,9 @@ impl<'a> Debug for PrettyPrintFunctionInfo<'a> {
|
|||
///
|
||||
/// let info = print.get_function_info();
|
||||
/// assert!(info.name().unwrap().ends_with("print"));
|
||||
/// assert_eq!(info.arg_count(), 1);
|
||||
/// assert_eq!(info.args()[0].type_path(), "alloc::string::String");
|
||||
/// assert_eq!(info.return_info().type_path(), "()");
|
||||
/// assert!(info.arg_count().contains(&1));
|
||||
/// assert_eq!(info.base().args()[0].type_path(), "alloc::string::String");
|
||||
/// assert_eq!(info.base().return_info().type_path(), "()");
|
||||
/// ```
|
||||
///
|
||||
/// # Trait Parameters
|
||||
|
@ -419,6 +572,7 @@ macro_rules! impl_typed_function {
|
|||
Function: FnMut($($Arg),*) -> ReturnType,
|
||||
{
|
||||
fn function_info() -> FunctionInfo {
|
||||
FunctionInfo::new(
|
||||
create_info::<Function>()
|
||||
.with_args({
|
||||
#[allow(unused_mut)]
|
||||
|
@ -431,6 +585,7 @@ macro_rules! impl_typed_function {
|
|||
]
|
||||
})
|
||||
.with_return_info(ReturnInfo::new::<ReturnType>())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,7 +597,8 @@ macro_rules! impl_typed_function {
|
|||
for<'a> &'a ReturnType: TypePath + GetOwnership,
|
||||
Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType,
|
||||
{
|
||||
fn function_info() -> $crate::func::FunctionInfo {
|
||||
fn function_info() -> FunctionInfo {
|
||||
FunctionInfo::new(
|
||||
create_info::<Function>()
|
||||
.with_args({
|
||||
#[allow(unused_mut)]
|
||||
|
@ -456,6 +612,7 @@ macro_rules! impl_typed_function {
|
|||
]
|
||||
})
|
||||
.with_return_info(ReturnInfo::new::<&ReturnType>())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,6 +625,7 @@ macro_rules! impl_typed_function {
|
|||
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType,
|
||||
{
|
||||
fn function_info() -> FunctionInfo {
|
||||
FunctionInfo::new(
|
||||
create_info::<Function>()
|
||||
.with_args({
|
||||
#[allow(unused_mut)]
|
||||
|
@ -481,6 +639,7 @@ macro_rules! impl_typed_function {
|
|||
]
|
||||
})
|
||||
.with_return_info(ReturnInfo::new::<&mut ReturnType>())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -493,6 +652,7 @@ macro_rules! impl_typed_function {
|
|||
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType,
|
||||
{
|
||||
fn function_info() -> FunctionInfo {
|
||||
FunctionInfo::new(
|
||||
create_info::<Function>()
|
||||
.with_args({
|
||||
#[allow(unused_mut)]
|
||||
|
@ -506,6 +666,7 @@ macro_rules! impl_typed_function {
|
|||
]
|
||||
})
|
||||
.with_return_info(ReturnInfo::new::<&ReturnType>())
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -531,13 +692,13 @@ all_tuples!(impl_typed_function, 0, 15, Arg, arg);
|
|||
/// | Function pointer | `fn() -> String` | `None` |
|
||||
///
|
||||
/// [`type_name`]: core::any::type_name
|
||||
fn create_info<F>() -> FunctionInfo {
|
||||
fn create_info<F>() -> SignatureInfo {
|
||||
let name = core::any::type_name::<F>();
|
||||
|
||||
if name.ends_with("{{closure}}") || name.starts_with("fn(") {
|
||||
FunctionInfo::anonymous()
|
||||
SignatureInfo::anonymous()
|
||||
} else {
|
||||
FunctionInfo::named(name)
|
||||
SignatureInfo::named(name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,10 +723,10 @@ mod tests {
|
|||
info.name().unwrap(),
|
||||
"bevy_reflect::func::info::tests::should_create_function_info::add"
|
||||
);
|
||||
assert_eq!(info.arg_count(), 2);
|
||||
assert_eq!(info.args()[0].type_path(), "i32");
|
||||
assert_eq!(info.args()[1].type_path(), "i32");
|
||||
assert_eq!(info.return_info().type_path(), "i32");
|
||||
assert_eq!(info.base().arg_count(), 2);
|
||||
assert_eq!(info.base().args()[0].type_path(), "i32");
|
||||
assert_eq!(info.base().args()[1].type_path(), "i32");
|
||||
assert_eq!(info.base().return_info().type_path(), "i32");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -581,10 +742,10 @@ mod tests {
|
|||
|
||||
let info = add.get_function_info();
|
||||
assert!(info.name().is_none());
|
||||
assert_eq!(info.arg_count(), 2);
|
||||
assert_eq!(info.args()[0].type_path(), "i32");
|
||||
assert_eq!(info.args()[1].type_path(), "i32");
|
||||
assert_eq!(info.return_info().type_path(), "i32");
|
||||
assert_eq!(info.base().arg_count(), 2);
|
||||
assert_eq!(info.base().args()[0].type_path(), "i32");
|
||||
assert_eq!(info.base().args()[1].type_path(), "i32");
|
||||
assert_eq!(info.base().return_info().type_path(), "i32");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -599,10 +760,10 @@ mod tests {
|
|||
|
||||
let info = add.get_function_info();
|
||||
assert!(info.name().is_none());
|
||||
assert_eq!(info.arg_count(), 2);
|
||||
assert_eq!(info.args()[0].type_path(), "i32");
|
||||
assert_eq!(info.args()[1].type_path(), "i32");
|
||||
assert_eq!(info.return_info().type_path(), "i32");
|
||||
assert_eq!(info.base().arg_count(), 2);
|
||||
assert_eq!(info.base().args()[0].type_path(), "i32");
|
||||
assert_eq!(info.base().args()[1].type_path(), "i32");
|
||||
assert_eq!(info.base().return_info().type_path(), "i32");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -618,30 +779,30 @@ mod tests {
|
|||
|
||||
let info = add.get_function_info();
|
||||
assert!(info.name().is_none());
|
||||
assert_eq!(info.arg_count(), 2);
|
||||
assert_eq!(info.args()[0].type_path(), "i32");
|
||||
assert_eq!(info.args()[1].type_path(), "i32");
|
||||
assert_eq!(info.return_info().type_path(), "()");
|
||||
assert_eq!(info.base().arg_count(), 2);
|
||||
assert_eq!(info.base().args()[0].type_path(), "i32");
|
||||
assert_eq!(info.base().args()[1].type_path(), "i32");
|
||||
assert_eq!(info.base().return_info().type_path(), "()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_pretty_print_info() {
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
a + b
|
||||
}
|
||||
|
||||
let info = add.get_function_info().with_name("add");
|
||||
|
||||
let pretty = info.pretty_printer();
|
||||
assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
|
||||
|
||||
let pretty = info.pretty_printer().include_fn_token();
|
||||
assert_eq!(format!("{:?}", pretty), "fn(_: i32, _: i32) -> i32");
|
||||
|
||||
let pretty = info.pretty_printer().include_name();
|
||||
assert_eq!(format!("{:?}", pretty), "add(_: i32, _: i32) -> i32");
|
||||
|
||||
let pretty = info.pretty_printer().include_fn_token().include_name();
|
||||
assert_eq!(format!("{:?}", pretty), "fn add(_: i32, _: i32) -> i32");
|
||||
// fn add(a: i32, b: i32) -> i32 {
|
||||
// a + b
|
||||
// }
|
||||
//
|
||||
// let info = add.get_function_info().with_name("add");
|
||||
//
|
||||
// let pretty = info.pretty_printer();
|
||||
// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");
|
||||
//
|
||||
// let pretty = info.pretty_printer().include_fn_token();
|
||||
// assert_eq!(format!("{:?}", pretty), "fn(_: i32, _: i32) -> i32");
|
||||
//
|
||||
// let pretty = info.pretty_printer().include_name();
|
||||
// assert_eq!(format!("{:?}", pretty), "add(_: i32, _: i32) -> i32");
|
||||
//
|
||||
// let pretty = info.pretty_printer().include_fn_token().include_name();
|
||||
// assert_eq!(format!("{:?}", pretty), "fn add(_: i32, _: i32) -> i32");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
//! Function signature types.
|
||||
//!
|
||||
//! Function signatures differ from [`FunctionInfo`] in that they are only concerned
|
||||
//! about the types and order of the arguments and return type of a function.
|
||||
//! Function signatures differ from [`FunctionInfo`] and [`SignatureInfo`] in that they
|
||||
//! are only concerned about the types and order of the arguments and return type of a function.
|
||||
//!
|
||||
//! The names of arguments do not matter,
|
||||
//! nor does any other information about the function such as its name or other attributes.
|
||||
//!
|
||||
//! This makes signatures useful for comparing or hashing functions strictly based on their
|
||||
//! arguments and return type.
|
||||
//!
|
||||
//! [`FunctionInfo`]: crate::func::info::FunctionInfo
|
||||
|
||||
use crate::func::args::ArgInfo;
|
||||
use crate::func::{ArgList, FunctionInfo};
|
||||
use crate::func::{ArgList, SignatureInfo};
|
||||
use crate::Type;
|
||||
use core::borrow::Borrow;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
|
@ -48,7 +50,7 @@ impl Debug for Signature {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Borrow<FunctionInfo>> From<T> for Signature {
|
||||
impl<T: Borrow<SignatureInfo>> From<T> for Signature {
|
||||
fn from(info: T) -> Self {
|
||||
let info = info.borrow();
|
||||
Self::new(ArgumentSignature::from(info), *info.return_info().ty())
|
||||
|
@ -94,7 +96,7 @@ impl FromIterator<Type> for ArgumentSignature {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Borrow<FunctionInfo>> From<T> for ArgumentSignature {
|
||||
impl<T: Borrow<SignatureInfo>> From<T> for ArgumentSignature {
|
||||
fn from(info: T) -> Self {
|
||||
Self(
|
||||
info.borrow()
|
||||
|
@ -137,7 +139,7 @@ mod tests {
|
|||
}
|
||||
|
||||
let info = add.get_function_info();
|
||||
let signature = Signature::from(&info);
|
||||
let signature = Signature::from(info.base());
|
||||
|
||||
assert_eq!(signature.args().0.len(), 2);
|
||||
assert_eq!(signature.args().0[0], Type::of::<i32>());
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
use bevy::reflect::{
|
||||
func::{
|
||||
ArgList, DynamicFunction, DynamicFunctionMut, FunctionInfo, FunctionResult, IntoFunction,
|
||||
IntoFunctionMut, Return,
|
||||
ArgList, DynamicFunction, DynamicFunctionMut, FunctionResult, IntoFunction,
|
||||
IntoFunctionMut, Return, SignatureInfo,
|
||||
},
|
||||
PartialReflect, Reflect,
|
||||
};
|
||||
|
@ -193,7 +193,7 @@ fn main() {
|
|||
// This makes it easier to debug and is also required for function registration.
|
||||
// We can either give it a custom name or use the function's type name as
|
||||
// derived from `std::any::type_name_of_val`.
|
||||
FunctionInfo::named(std::any::type_name_of_val(&get_or_insert))
|
||||
SignatureInfo::named(std::any::type_name_of_val(&get_or_insert))
|
||||
// We can always change the name if needed.
|
||||
// It's a good idea to also ensure that the name is unique,
|
||||
// such as by using its type name or by prefixing it with your crate name.
|
||||
|
|
Loading…
Reference in a new issue