use crate::func::args::ArgInfo;
use crate::func::{ArgList, SignatureInfo};
use crate::Type;
use alloc::boxed::Box;
use bevy_platform::collections::Equivalent;
use core::borrow::Borrow;
use core::fmt::{Debug, Formatter};
use core::hash::{Hash, Hasher};
use core::ops::{Deref, DerefMut};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Signature {
args: ArgumentSignature,
ret: Type,
}
impl Signature {
pub fn new(args: ArgumentSignature, ret: Type) -> Self {
Self { args, ret }
}
pub fn args(&self) -> &ArgumentSignature {
&self.args
}
pub fn return_type(&self) -> &Type {
&self.ret
}
}
impl Debug for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?} -> {:?}", self.args, self.ret)
}
}
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())
}
}
pub(super) struct ArgListSignature<'a, 'b>(&'a ArgList<'b>);
impl Equivalent<ArgumentSignature> for ArgListSignature<'_, '_> {
fn equivalent(&self, key: &ArgumentSignature) -> bool {
self.len() == key.len() && self.iter().eq(key.iter())
}
}
impl<'a, 'b> ArgListSignature<'a, 'b> {
pub fn iter(&self) -> impl ExactSizeIterator<Item = &Type> {
self.0.iter().map(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
})
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl Eq for ArgListSignature<'_, '_> {}
impl PartialEq for ArgListSignature<'_, '_> {
fn eq(&self, other: &Self) -> bool {
self.len() == other.len() && self.iter().eq(other.iter())
}
}
impl Hash for ArgListSignature<'_, '_> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.iter().for_each(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
.hash(state);
});
}
}
impl<'a, 'b> From<&'a ArgList<'b>> for ArgListSignature<'a, 'b> {
fn from(args: &'a ArgList<'b>) -> Self {
Self(args)
}
}
#[derive(Clone)]
pub struct ArgumentSignature(Box<[Type]>);
impl Debug for ArgumentSignature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut tuple = f.debug_tuple("");
for ty in self.0.iter() {
tuple.field(ty);
}
tuple.finish()
}
}
impl Deref for ArgumentSignature {
type Target = [Type];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for ArgumentSignature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Eq for ArgumentSignature {}
impl PartialEq for ArgumentSignature {
fn eq(&self, other: &Self) -> bool {
self.0.len() == other.0.len() && self.0.iter().eq(other.0.iter())
}
}
impl Hash for ArgumentSignature {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.iter().for_each(|ty| ty.hash(state));
}
}
impl FromIterator<Type> for ArgumentSignature {
fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {
Self(iter.into_iter().collect())
}
}
impl<T: Borrow<SignatureInfo>> From<T> for ArgumentSignature {
fn from(info: T) -> Self {
Self(
info.borrow()
.args()
.iter()
.map(ArgInfo::ty)
.copied()
.collect(),
)
}
}
impl From<&ArgList<'_>> for ArgumentSignature {
fn from(args: &ArgList) -> Self {
Self(
args.iter()
.map(|arg| {
arg.value()
.get_represented_type_info()
.unwrap_or_else(|| {
panic!("no `TypeInfo` found for argument: {:?}", arg);
})
.ty()
})
.copied()
.collect(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::func::TypedFunction;
use alloc::{format, string::String, vec};
#[test]
fn should_generate_signature_from_function_info() {
fn add(a: i32, b: f32) -> u32 {
(a as f32 + b).round() as u32
}
let info = add.get_function_info();
let signature = Signature::from(info.base());
assert_eq!(signature.args().0.len(), 2);
assert_eq!(signature.args().0[0], Type::of::<i32>());
assert_eq!(signature.args().0[1], Type::of::<f32>());
assert_eq!(*signature.return_type(), Type::of::<u32>());
}
#[test]
fn should_debug_signature() {
let signature = Signature::new(
ArgumentSignature::from_iter(vec![Type::of::<&mut String>(), Type::of::<i32>()]),
Type::of::<()>(),
);
assert_eq!(
format!("{signature:?}"),
"(&mut alloc::string::String, i32) -> ()"
);
}
}