Path: blob/main/crates/bevy_reflect/src/func/dynamic_function_internal.rs
6599 views
use crate::func::args::ArgCount;1use crate::func::signature::{ArgListSignature, ArgumentSignature};2use crate::func::{ArgList, FunctionError, FunctionInfo, FunctionOverloadError};3use alloc::{borrow::Cow, vec, vec::Vec};4use bevy_platform::collections::HashMap;5use core::fmt::{Debug, Formatter};67/// An internal structure for storing a function and its corresponding [function information].8///9/// This is used to facilitate the sharing of functionality between [`DynamicFunction`]10/// and [`DynamicFunctionMut`].11///12/// [function information]: FunctionInfo13/// [`DynamicFunction`]: crate::func::DynamicFunction14/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut15#[derive(Clone)]16pub(super) struct DynamicFunctionInternal<F> {17functions: Vec<F>,18info: FunctionInfo,19arg_map: HashMap<ArgumentSignature, usize>,20}2122impl<F> DynamicFunctionInternal<F> {23/// Create a new instance of [`DynamicFunctionInternal`] with the given function24/// and its corresponding information.25pub fn new(func: F, info: FunctionInfo) -> Self {26let arg_map = info27.signatures()28.iter()29.map(|sig| (ArgumentSignature::from(sig), 0))30.collect();3132Self {33functions: vec![func],34info,35arg_map,36}37}38pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {39self.info = self.info.with_name(Some(name.into()));40self41}4243/// The name of the function.44pub fn name(&self) -> Option<&Cow<'static, str>> {45self.info.name()46}4748/// Returns `true` if the function is overloaded.49pub fn is_overloaded(&self) -> bool {50self.info.is_overloaded()51}5253/// Get an immutable reference to the function.54///55/// If the function is not overloaded, it will always be returned regardless of the arguments.56/// Otherwise, the function will be selected based on the arguments provided.57///58/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].59pub fn get(&self, args: &ArgList) -> Result<&F, FunctionError> {60if !self.info.is_overloaded() {61return Ok(&self.functions[0]);62}6364let signature = ArgListSignature::from(args);65self.arg_map66.get(&signature)67.map(|index| &self.functions[*index])68.ok_or_else(|| FunctionError::NoOverload {69expected: self.arg_map.keys().cloned().collect(),70received: ArgumentSignature::from(args),71})72}7374/// Get a mutable reference to the function.75///76/// If the function is not overloaded, it will always be returned regardless of the arguments.77/// Otherwise, the function will be selected based on the arguments provided.78///79/// If no overload matches the provided arguments, returns [`FunctionError::NoOverload`].80pub fn get_mut(&mut self, args: &ArgList) -> Result<&mut F, FunctionError> {81if !self.info.is_overloaded() {82return Ok(&mut self.functions[0]);83}8485let signature = ArgListSignature::from(args);86self.arg_map87.get(&signature)88.map(|index| &mut self.functions[*index])89.ok_or_else(|| FunctionError::NoOverload {90expected: self.arg_map.keys().cloned().collect(),91received: ArgumentSignature::from(args),92})93}9495/// Returns the function information contained in the map.96#[inline]97pub fn info(&self) -> &FunctionInfo {98&self.info99}100101/// Returns the number of arguments the function expects.102///103/// For overloaded functions that can have a variable number of arguments,104/// this will contain the full set of counts for all signatures.105pub fn arg_count(&self) -> ArgCount {106self.info.arg_count()107}108109/// Helper method for validating that a given set of arguments are _potentially_ valid for this function.110///111/// Currently, this validates:112/// - The number of arguments is within the expected range113pub fn validate_args(&self, args: &ArgList) -> Result<(), FunctionError> {114let expected_arg_count = self.arg_count();115let received_arg_count = args.len();116117if !expected_arg_count.contains(received_arg_count) {118Err(FunctionError::ArgCountMismatch {119expected: expected_arg_count,120received: received_arg_count,121})122} else {123Ok(())124}125}126127/// Merge another [`DynamicFunctionInternal`] into this one.128///129/// If `other` contains any functions with the same signature as this one,130/// an error will be returned along with the original, unchanged instance.131///132/// Therefore, this method should always return an overloaded function if the merge is successful.133///134/// Additionally, if the merge succeeds, it should be guaranteed that the order135/// of the functions in the map will be preserved.136/// For example, merging `[func_a, func_b]` (self) with `[func_c, func_d]` (other) should result in137/// `[func_a, func_b, func_c, func_d]`.138/// And merging `[func_c, func_d]` (self) with `[func_a, func_b]` (other) should result in139/// `[func_c, func_d, func_a, func_b]`.140pub fn merge(&mut self, mut other: Self) -> Result<(), FunctionOverloadError> {141// Keep a separate map of the new indices to avoid mutating the existing one142// until we can be sure the merge will be successful.143let mut new_signatures = <HashMap<_, _>>::default();144145for (sig, index) in other.arg_map {146if self.arg_map.contains_key(&sig) {147return Err(FunctionOverloadError::DuplicateSignature(sig));148}149150new_signatures.insert(sig, self.functions.len() + index);151}152153self.arg_map.reserve(new_signatures.len());154for (sig, index) in new_signatures {155self.arg_map.insert(sig, index);156}157158self.functions.append(&mut other.functions);159self.info.extend_unchecked(other.info);160161Ok(())162}163164/// Maps the internally stored function(s) from type `F` to type `G`.165pub fn map_functions<G>(self, f: fn(F) -> G) -> DynamicFunctionInternal<G> {166DynamicFunctionInternal {167functions: self.functions.into_iter().map(f).collect(),168info: self.info,169arg_map: self.arg_map,170}171}172}173174impl<F> Debug for DynamicFunctionInternal<F> {175fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {176self.info177.pretty_printer()178.include_fn_token()179.include_name()180.fmt(f)181}182}183184#[cfg(test)]185mod tests {186use super::*;187use crate::func::{FunctionInfo, SignatureInfo};188use crate::Type;189190#[test]191fn should_merge_single_into_single() {192let mut func_a = DynamicFunctionInternal::new(193'a',194FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),195);196197let func_b = DynamicFunctionInternal::new(198'b',199FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),200);201202func_a.merge(func_b).unwrap();203204assert_eq!(func_a.functions, vec!['a', 'b']);205assert_eq!(func_a.info.signatures().len(), 2);206assert_eq!(207func_a.arg_map,208HashMap::from_iter([209(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),210(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),211])212);213}214215#[test]216fn should_merge_single_into_overloaded() {217let mut func_a = DynamicFunctionInternal::new(218'a',219FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0")),220);221222let func_b = DynamicFunctionInternal {223functions: vec!['b', 'c'],224info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))225.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))226.unwrap(),227arg_map: HashMap::from_iter([228(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),229(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),230]),231};232233func_a.merge(func_b).unwrap();234235assert_eq!(func_a.functions, vec!['a', 'b', 'c']);236assert_eq!(func_a.info.signatures().len(), 3);237assert_eq!(238func_a.arg_map,239HashMap::from_iter([240(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),241(ArgumentSignature::from_iter([Type::of::<u8>()]), 1),242(ArgumentSignature::from_iter([Type::of::<u16>()]), 2),243])244);245}246247#[test]248fn should_merge_overload_into_single() {249let mut func_a = DynamicFunctionInternal {250functions: vec!['a', 'b'],251info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))252.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))253.unwrap(),254arg_map: HashMap::from_iter([255(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),256(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),257]),258};259260let func_b = DynamicFunctionInternal::new(261'c',262FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0")),263);264265func_a.merge(func_b).unwrap();266267assert_eq!(func_a.functions, vec!['a', 'b', 'c']);268assert_eq!(func_a.info.signatures().len(), 3);269assert_eq!(270func_a.arg_map,271HashMap::from_iter([272(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),273(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),274(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),275])276);277}278279#[test]280fn should_merge_overloaded_into_overloaded() {281let mut func_a = DynamicFunctionInternal {282functions: vec!['a', 'b'],283info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<i8>("arg0"))284.with_overload(SignatureInfo::anonymous().with_arg::<i16>("arg0"))285.unwrap(),286arg_map: HashMap::from_iter([287(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),288(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),289]),290};291292let func_b = DynamicFunctionInternal {293functions: vec!['c', 'd'],294info: FunctionInfo::new(SignatureInfo::anonymous().with_arg::<u8>("arg0"))295.with_overload(SignatureInfo::anonymous().with_arg::<u16>("arg0"))296.unwrap(),297arg_map: HashMap::from_iter([298(ArgumentSignature::from_iter([Type::of::<u8>()]), 0),299(ArgumentSignature::from_iter([Type::of::<u16>()]), 1),300]),301};302303func_a.merge(func_b).unwrap();304305assert_eq!(func_a.functions, vec!['a', 'b', 'c', 'd']);306assert_eq!(func_a.info.signatures().len(), 4);307assert_eq!(308func_a.arg_map,309HashMap::from_iter([310(ArgumentSignature::from_iter([Type::of::<i8>()]), 0),311(ArgumentSignature::from_iter([Type::of::<i16>()]), 1),312(ArgumentSignature::from_iter([Type::of::<u8>()]), 2),313(ArgumentSignature::from_iter([Type::of::<u16>()]), 3),314])315);316}317318#[test]319fn should_return_error_on_duplicate_signature() {320let mut func_a = DynamicFunctionInternal::new(321'a',322FunctionInfo::new(323SignatureInfo::anonymous()324.with_arg::<i8>("arg0")325.with_arg::<i16>("arg1"),326),327);328329let func_b = DynamicFunctionInternal {330functions: vec!['b', 'c'],331info: FunctionInfo::new(332SignatureInfo::anonymous()333.with_arg::<u8>("arg0")334.with_arg::<u16>("arg1"),335)336.with_overload(337SignatureInfo::anonymous()338.with_arg::<i8>("arg0")339.with_arg::<i16>("arg1"),340)341.unwrap(),342arg_map: HashMap::from_iter([343(344ArgumentSignature::from_iter([Type::of::<u8>(), Type::of::<u16>()]),3450,346),347(348ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),3491,350),351]),352};353354let FunctionOverloadError::DuplicateSignature(duplicate) =355func_a.merge(func_b).unwrap_err()356else {357panic!("Expected `FunctionOverloadError::DuplicateSignature`");358};359360assert_eq!(361duplicate,362ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()])363);364365// Assert the original remains unchanged:366assert!(!func_a.is_overloaded());367assert_eq!(func_a.functions, vec!['a']);368assert_eq!(func_a.info.signatures().len(), 1);369assert_eq!(370func_a.arg_map,371HashMap::from_iter([(372ArgumentSignature::from_iter([Type::of::<i8>(), Type::of::<i16>()]),3730374),])375);376}377}378379380