Path: blob/main/crates/bevy_reflect/src/func/signature.rs
6599 views
//! Function signature types.1//!2//! Function signatures differ from [`FunctionInfo`] and [`SignatureInfo`] in that they3//! are only concerned about the types and order of the arguments and return type of a function.4//!5//! The names of arguments do not matter,6//! nor does any other information about the function such as its name or other attributes.7//!8//! This makes signatures useful for comparing or hashing functions strictly based on their9//! arguments and return type.10//!11//! [`FunctionInfo`]: crate::func::info::FunctionInfo1213use crate::func::args::ArgInfo;14use crate::func::{ArgList, SignatureInfo};15use crate::Type;16use alloc::boxed::Box;17use bevy_platform::collections::Equivalent;18use core::borrow::Borrow;19use core::fmt::{Debug, Formatter};20use core::hash::{Hash, Hasher};21use core::ops::{Deref, DerefMut};2223/// The signature of a function.24///25/// This can be used as a way to compare or hash functions based on their arguments and return type.26#[derive(Clone, PartialEq, Eq, Hash)]27pub struct Signature {28args: ArgumentSignature,29ret: Type,30}3132impl Signature {33/// Create a new function signature with the given argument signature and return type.34pub fn new(args: ArgumentSignature, ret: Type) -> Self {35Self { args, ret }36}3738/// Get the argument signature of the function.39pub fn args(&self) -> &ArgumentSignature {40&self.args41}4243/// Get the return type of the function.44pub fn return_type(&self) -> &Type {45&self.ret46}47}4849impl Debug for Signature {50fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {51write!(f, "{:?} -> {:?}", self.args, self.ret)52}53}5455impl<T: Borrow<SignatureInfo>> From<T> for Signature {56fn from(info: T) -> Self {57let info = info.borrow();58Self::new(ArgumentSignature::from(info), *info.return_info().ty())59}60}6162/// A wrapper around a borrowed [`ArgList`] that can be used as an63/// [equivalent] of an [`ArgumentSignature`].64///65/// [equivalent]: Equivalent66pub(super) struct ArgListSignature<'a, 'b>(&'a ArgList<'b>);6768impl Equivalent<ArgumentSignature> for ArgListSignature<'_, '_> {69fn equivalent(&self, key: &ArgumentSignature) -> bool {70self.len() == key.len() && self.iter().eq(key.iter())71}72}7374impl<'a, 'b> ArgListSignature<'a, 'b> {75pub fn iter(&self) -> impl ExactSizeIterator<Item = &Type> {76self.0.iter().map(|arg| {77arg.value()78.get_represented_type_info()79.unwrap_or_else(|| {80panic!("no `TypeInfo` found for argument: {:?}", arg);81})82.ty()83})84}8586pub fn len(&self) -> usize {87self.0.len()88}89}9091impl Eq for ArgListSignature<'_, '_> {}9293impl PartialEq for ArgListSignature<'_, '_> {94fn eq(&self, other: &Self) -> bool {95self.len() == other.len() && self.iter().eq(other.iter())96}97}9899impl Hash for ArgListSignature<'_, '_> {100fn hash<H: Hasher>(&self, state: &mut H) {101self.0.iter().for_each(|arg| {102arg.value()103.get_represented_type_info()104.unwrap_or_else(|| {105panic!("no `TypeInfo` found for argument: {:?}", arg);106})107.ty()108.hash(state);109});110}111}112113impl<'a, 'b> From<&'a ArgList<'b>> for ArgListSignature<'a, 'b> {114fn from(args: &'a ArgList<'b>) -> Self {115Self(args)116}117}118119/// The argument-portion of a function signature.120///121/// For example, given a function signature `(a: i32, b: f32) -> u32`,122/// the argument signature would be `(i32, f32)`.123///124/// This can be used as a way to compare or hash functions based on their arguments.125#[derive(Clone)]126pub struct ArgumentSignature(Box<[Type]>);127128impl Debug for ArgumentSignature {129fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {130let mut tuple = f.debug_tuple("");131for ty in self.0.iter() {132tuple.field(ty);133}134tuple.finish()135}136}137138impl Deref for ArgumentSignature {139type Target = [Type];140141fn deref(&self) -> &Self::Target {142&self.0143}144}145146impl DerefMut for ArgumentSignature {147fn deref_mut(&mut self) -> &mut Self::Target {148&mut self.0149}150}151152impl Eq for ArgumentSignature {}153154impl PartialEq for ArgumentSignature {155fn eq(&self, other: &Self) -> bool {156self.0.len() == other.0.len() && self.0.iter().eq(other.0.iter())157}158}159160impl Hash for ArgumentSignature {161fn hash<H: Hasher>(&self, state: &mut H) {162self.0.iter().for_each(|ty| ty.hash(state));163}164}165166impl FromIterator<Type> for ArgumentSignature {167fn from_iter<T: IntoIterator<Item = Type>>(iter: T) -> Self {168Self(iter.into_iter().collect())169}170}171172impl<T: Borrow<SignatureInfo>> From<T> for ArgumentSignature {173fn from(info: T) -> Self {174Self(175info.borrow()176.args()177.iter()178.map(ArgInfo::ty)179.copied()180.collect(),181)182}183}184185impl From<&ArgList<'_>> for ArgumentSignature {186fn from(args: &ArgList) -> Self {187Self(188args.iter()189.map(|arg| {190arg.value()191.get_represented_type_info()192.unwrap_or_else(|| {193panic!("no `TypeInfo` found for argument: {:?}", arg);194})195.ty()196})197.copied()198.collect(),199)200}201}202203#[cfg(test)]204mod tests {205use super::*;206use crate::func::TypedFunction;207use alloc::{format, string::String, vec};208209#[test]210fn should_generate_signature_from_function_info() {211fn add(a: i32, b: f32) -> u32 {212(a as f32 + b).round() as u32213}214215let info = add.get_function_info();216let signature = Signature::from(info.base());217218assert_eq!(signature.args().0.len(), 2);219assert_eq!(signature.args().0[0], Type::of::<i32>());220assert_eq!(signature.args().0[1], Type::of::<f32>());221assert_eq!(*signature.return_type(), Type::of::<u32>());222}223224#[test]225fn should_debug_signature() {226let signature = Signature::new(227ArgumentSignature::from_iter(vec![Type::of::<&mut String>(), Type::of::<i32>()]),228Type::of::<()>(),229);230231assert_eq!(232format!("{signature:?}"),233"(&mut alloc::string::String, i32) -> ()"234);235}236}237238239