use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec};
use core::fmt::{Debug, Formatter};
use crate::{
func::args::{ArgCount, ArgCountOutOfBoundsError, ArgInfo, GetOwnership, Ownership},
func::signature::ArgumentSignature,
func::FunctionOverloadError,
type_info::impl_type_methods,
Type, TypePath,
};
use variadics_please::all_tuples;
#[derive(Debug, Clone)]
pub struct FunctionInfo {
name: Option<Cow<'static, str>>,
arg_count: ArgCount,
signatures: Box<[SignatureInfo]>,
}
impl FunctionInfo {
pub fn new(signature: SignatureInfo) -> Self {
Self {
name: signature.name.clone(),
arg_count: ArgCount::new(signature.arg_count()).unwrap(),
signatures: vec![signature].into(),
}
}
pub fn try_from_iter(
signatures: impl IntoIterator<Item = SignatureInfo>,
) -> Result<Self, FunctionOverloadError> {
let mut iter = signatures.into_iter();
let base = iter.next().ok_or(FunctionOverloadError::MissingSignature)?;
if base.arg_count() > ArgCount::MAX_COUNT {
return Err(FunctionOverloadError::TooManyArguments(
ArgumentSignature::from(&base),
));
}
let mut info = Self::new(base);
for signature in iter {
if signature.arg_count() > ArgCount::MAX_COUNT {
return Err(FunctionOverloadError::TooManyArguments(
ArgumentSignature::from(&signature),
));
}
info = info.with_overload(signature).map_err(|sig| {
FunctionOverloadError::DuplicateSignature(ArgumentSignature::from(&sig))
})?;
}
Ok(info)
}
pub fn base(&self) -> &SignatureInfo {
&self.signatures[0]
}
pub fn is_overloaded(&self) -> bool {
self.signatures.len() > 1
}
pub fn with_name(mut self, name: Option<impl Into<Cow<'static, str>>>) -> Self {
self.name = name.map(Into::into);
self
}
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.name.as_ref()
}
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.arg_count.add(signature.arg_count());
self.signatures = IntoIterator::into_iter(self.signatures)
.chain(Some(signature))
.collect();
Ok(self)
}
pub fn arg_count(&self) -> ArgCount {
self.arg_count
}
pub fn signatures(&self) -> &[SignatureInfo] {
&self.signatures
}
pub fn pretty_printer(&self) -> PrettyPrintFunctionInfo<'_> {
PrettyPrintFunctionInfo::new(self)
}
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();
self.arg_count = self
.signatures
.iter()
.fold(ArgCount::default(), |mut count, sig| {
count.add(sig.arg_count());
count
});
}
}
impl TryFrom<SignatureInfo> for FunctionInfo {
type Error = ArgCountOutOfBoundsError;
fn try_from(signature: SignatureInfo) -> Result<Self, Self::Error> {
let count = signature.arg_count();
if count > ArgCount::MAX_COUNT {
return Err(ArgCountOutOfBoundsError(count));
}
Ok(Self::new(signature))
}
}
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 {
pub fn named(name: impl Into<Cow<'static, str>>) -> Self {
Self {
name: Some(name.into()),
args: Box::new([]),
return_info: ReturnInfo::new::<()>(),
}
}
pub fn anonymous() -> Self {
Self {
name: None,
args: Box::new([]),
return_info: ReturnInfo::new::<()>(),
}
}
pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {
self.name = Some(name.into());
self
}
pub fn with_arg<T: TypePath + GetOwnership>(
mut self,
name: impl Into<Cow<'static, str>>,
) -> Self {
let index = self.args.len();
self.args = IntoIterator::into_iter(self.args)
.chain(Some(ArgInfo::new::<T>(index).with_name(name)))
.collect();
self
}
pub fn with_args(mut self, args: Vec<ArgInfo>) -> Self {
self.args = IntoIterator::into_iter(self.args).chain(args).collect();
self
}
pub fn with_return<T: TypePath + GetOwnership>(mut self) -> Self {
self.return_info = ReturnInfo::new::<T>();
self
}
pub fn with_return_info(mut self, return_info: ReturnInfo) -> Self {
self.return_info = return_info;
self
}
pub fn name(&self) -> Option<&Cow<'static, str>> {
self.name.as_ref()
}
pub fn args(&self) -> &[ArgInfo] {
&self.args
}
pub fn arg_count(&self) -> usize {
self.args.len()
}
pub fn return_info(&self) -> &ReturnInfo {
&self.return_info
}
}
#[derive(Debug, Clone)]
pub struct ReturnInfo {
ty: Type,
ownership: Ownership,
}
impl ReturnInfo {
pub fn new<T: TypePath + GetOwnership>() -> Self {
Self {
ty: Type::of::<T>(),
ownership: T::ownership(),
}
}
impl_type_methods!(ty);
pub fn ownership(&self) -> Ownership {
self.ownership
}
}
pub struct PrettyPrintFunctionInfo<'a> {
info: &'a FunctionInfo,
include_fn_token: bool,
include_name: bool,
}
impl<'a> PrettyPrintFunctionInfo<'a> {
pub fn new(info: &'a FunctionInfo) -> Self {
Self {
info,
include_fn_token: false,
include_name: false,
}
}
pub fn include_name(mut self) -> Self {
self.include_name = true;
self
}
pub fn include_fn_token(mut self) -> Self {
self.include_fn_token = true;
self
}
}
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() {
let mut set = f.debug_set();
for signature in self.info.signatures() {
set.entry(&PrettyPrintSignatureInfo::new(signature));
}
set.finish()
} else {
PrettyPrintSignatureInfo::new(self.info.base()).fmt(f)
}
}
}
pub struct PrettyPrintSignatureInfo<'a> {
info: &'a SignatureInfo,
include_fn_token: bool,
include_name: bool,
}
impl<'a> PrettyPrintSignatureInfo<'a> {
pub fn new(info: &'a SignatureInfo) -> Self {
Self {
info,
include_fn_token: false,
include_name: false,
}
}
pub fn include_name(mut self) -> Self {
self.include_name = true;
self
}
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")?;
if self.include_name {
write!(f, " ")?;
}
}
match (self.include_name, self.info.name()) {
(true, Some(name)) => write!(f, "{name}")?,
(true, None) => write!(f, "_")?,
_ => {}
}
write!(f, "(")?;
for (index, arg) in self.info.args().iter().enumerate() {
if index > 0 {
write!(f, ", ")?;
}
let name = arg.name().unwrap_or("_");
let ty = arg.type_path();
write!(f, "{name}: {ty}")?;
}
let ret = self.info.return_info().type_path();
write!(f, ") -> {ret}")
}
}
pub trait TypedFunction<Marker> {
fn function_info() -> FunctionInfo;
fn get_function_info(&self) -> FunctionInfo {
Self::function_info()
}
}
macro_rules! impl_typed_function {
($($Arg:ident),*) => {
impl<$($Arg,)* ReturnType, Function> TypedFunction<fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: TypePath + GetOwnership,)*
ReturnType: TypePath + GetOwnership,
Function: FnMut($($Arg),*) -> ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 0;
vec![
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<ReturnType>())
)
}
}
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
for<'a> &'a Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&Receiver>(0),
$($crate::func::args::ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&ReturnType>())
)
}
}
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
for<'a> &'a mut Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a mut ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&mut Receiver>(0),
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&mut ReturnType>())
)
}
}
impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
for<'a> &'a mut Receiver: TypePath + GetOwnership,
$($Arg: TypePath + GetOwnership,)*
for<'a> &'a ReturnType: TypePath + GetOwnership,
Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType,
{
fn function_info() -> FunctionInfo {
FunctionInfo::new(
create_info::<Function>()
.with_args({
let mut _index = 1;
vec![
ArgInfo::new::<&mut Receiver>(0),
$(ArgInfo::new::<$Arg>({
_index += 1;
_index - 1
}),)*
]
})
.with_return_info(ReturnInfo::new::<&ReturnType>())
)
}
}
};
}
all_tuples!(impl_typed_function, 0, 15, Arg);
fn create_info<F>() -> SignatureInfo {
let name = core::any::type_name::<F>();
if name.ends_with("{{closure}}") || name.starts_with("fn(") {
SignatureInfo::anonymous()
} else {
SignatureInfo::named(name)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_create_function_info() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_function_info::add"
);
let info = add.get_function_info();
assert_eq!(
info.name().unwrap(),
"bevy_reflect::func::info::tests::should_create_function_info::add"
);
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]
fn should_create_function_pointer_info() {
fn add(a: i32, b: i32) -> i32 {
a + b
}
let add = add as fn(i32, i32) -> i32;
assert_eq!(core::any::type_name_of_val(&add), "fn(i32, i32) -> i32");
let info = add.get_function_info();
assert!(info.name().is_none());
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]
fn should_create_anonymous_function_info() {
let add = |a: i32, b: i32| a + b;
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_anonymous_function_info::{{closure}}"
);
let info = add.get_function_info();
assert!(info.name().is_none());
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]
fn should_create_closure_info() {
let mut total = 0;
let add = |a: i32, b: i32| total = a + b;
assert_eq!(
core::any::type_name_of_val(&add),
"bevy_reflect::func::info::tests::should_create_closure_info::{{closure}}"
);
let info = add.get_function_info();
assert!(info.name().is_none());
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() {
}
}