Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_reflect/src/func/registry.rs
6599 views
1
use alloc::borrow::Cow;
2
use bevy_platform::{
3
collections::HashMap,
4
sync::{Arc, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard},
5
};
6
use core::fmt::Debug;
7
8
use crate::func::{
9
ArgList, DynamicFunction, FunctionRegistrationError, FunctionResult, IntoFunction,
10
};
11
12
/// A registry of [reflected functions].
13
///
14
/// This is the function-equivalent to the [`TypeRegistry`].
15
///
16
/// All functions must be `'static` as they are stored as [`DynamicFunction<'static>`].
17
///
18
/// [reflected functions]: crate::func
19
/// [`TypeRegistry`]: crate::TypeRegistry
20
#[derive(Default)]
21
pub struct FunctionRegistry {
22
/// Maps function [names] to their respective [`DynamicFunctions`].
23
///
24
/// [names]: DynamicFunction::name
25
/// [`DynamicFunctions`]: DynamicFunction
26
functions: HashMap<Cow<'static, str>, DynamicFunction<'static>>,
27
}
28
29
impl FunctionRegistry {
30
/// Attempts to register the given function.
31
///
32
/// This function accepts both functions that satisfy [`IntoFunction`]
33
/// and direct [`DynamicFunction`] instances.
34
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
35
/// and mapped according to its [name].
36
///
37
/// Because the function must have a name,
38
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
39
/// be registered using [`register_with_name`] or manually converted to a [`DynamicFunction`]
40
/// and named using [`DynamicFunction::with_name`].
41
/// Failure to do so will result in an error being returned.
42
///
43
/// If a registered function with the same name already exists,
44
/// it will not be registered again and an error will be returned.
45
/// To register the function anyway, overwriting any existing registration,
46
/// use [`overwrite_registration`] instead.
47
///
48
/// # Examples
49
///
50
/// ```
51
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry};
52
/// fn add(a: i32, b: i32) -> i32 {
53
/// a + b
54
/// }
55
///
56
/// # fn main() -> Result<(), FunctionRegistrationError> {
57
/// let mut registry = FunctionRegistry::default();
58
/// registry.register(add)?;
59
/// # Ok(())
60
/// # }
61
/// ```
62
///
63
/// Functions cannot be registered more than once.
64
///
65
/// ```
66
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry, IntoFunction};
67
/// fn add(a: i32, b: i32) -> i32 {
68
/// a + b
69
/// }
70
///
71
/// let mut registry = FunctionRegistry::default();
72
/// registry.register(add).unwrap();
73
///
74
/// let result = registry.register(add);
75
/// assert!(matches!(result, Err(FunctionRegistrationError::DuplicateName(_))));
76
///
77
/// // Note that this simply relies on the name of the function to determine uniqueness.
78
/// // You can rename the function to register a separate instance of it.
79
/// let result = registry.register(add.into_function().with_name("add2"));
80
/// assert!(result.is_ok());
81
/// ```
82
///
83
/// Anonymous functions and closures should be registered using [`register_with_name`] or given a name using [`DynamicFunction::with_name`].
84
///
85
/// ```
86
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry, IntoFunction};
87
///
88
/// let anonymous = || -> i32 { 123 };
89
///
90
/// let mut registry = FunctionRegistry::default();
91
///
92
/// let result = registry.register(|a: i32, b: i32| a + b);
93
/// assert!(matches!(result, Err(FunctionRegistrationError::MissingName)));
94
///
95
/// let result = registry.register_with_name("my_crate::add", |a: i32, b: i32| a + b);
96
/// assert!(result.is_ok());
97
///
98
/// let result = registry.register((|a: i32, b: i32| a * b).into_function().with_name("my_crate::mul"));
99
/// assert!(result.is_ok());
100
/// ```
101
///
102
/// [name]: DynamicFunction::name
103
/// [`register_with_name`]: Self::register_with_name
104
/// [`overwrite_registration`]: Self::overwrite_registration
105
pub fn register<F, Marker>(
106
&mut self,
107
function: F,
108
) -> Result<&mut Self, FunctionRegistrationError>
109
where
110
F: IntoFunction<'static, Marker> + 'static,
111
{
112
let function = function.into_function();
113
let name = function
114
.name()
115
.ok_or(FunctionRegistrationError::MissingName)?
116
.clone();
117
self.functions
118
.try_insert(name, function.into_function())
119
.map_err(|err| FunctionRegistrationError::DuplicateName(err.entry.key().clone()))?;
120
121
Ok(self)
122
}
123
124
/// Attempts to register the given function with the given name.
125
///
126
/// This function accepts both functions that satisfy [`IntoFunction`]
127
/// and direct [`DynamicFunction`] instances.
128
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
129
/// with its [name] set to the given name.
130
///
131
/// For named functions (e.g. `fn add(a: i32, b: i32) -> i32 { a + b }`) where a custom name is not needed,
132
/// it's recommended to use [`register`] instead as the generated name is guaranteed to be unique.
133
///
134
/// If a registered function with the same name already exists,
135
/// it will not be registered again and an error will be returned.
136
/// To register the function anyway, overwriting any existing registration,
137
/// use [`overwrite_registration_with_name`] instead.
138
///
139
/// To avoid conflicts, it's recommended to use a unique name for the function.
140
/// This can be achieved by "namespacing" the function with a unique identifier,
141
/// such as the name of your crate.
142
///
143
/// For example, to register a function, `add`, from a crate, `my_crate`,
144
/// you could use the name, `"my_crate::add"`.
145
///
146
/// Another approach could be to use the [type name] of the function,
147
/// however, it should be noted that anonymous functions and closures
148
/// are not guaranteed to have unique type names.
149
///
150
/// This method is a convenience around calling [`IntoFunction::into_function`] and [`DynamicFunction::with_name`]
151
/// on the function and inserting it into the registry using the [`register`] method.
152
///
153
/// # Examples
154
///
155
/// ```
156
/// # use bevy_reflect::func::{FunctionRegistrationError, FunctionRegistry};
157
/// # fn main() -> Result<(), FunctionRegistrationError> {
158
/// fn mul(a: i32, b: i32) -> i32 {
159
/// a * b
160
/// }
161
///
162
/// let div = |a: i32, b: i32| a / b;
163
///
164
/// let mut registry = FunctionRegistry::default();
165
/// registry
166
/// // Registering an anonymous function with a unique name
167
/// .register_with_name("my_crate::add", |a: i32, b: i32| {
168
/// a + b
169
/// })?
170
/// // Registering an existing function with its type name
171
/// .register_with_name(core::any::type_name_of_val(&mul), mul)?
172
/// // Registering an existing function with a custom name
173
/// .register_with_name("my_crate::mul", mul)?;
174
///
175
/// // Be careful not to register anonymous functions with their type name.
176
/// // This code works but registers the function with a non-unique name like `foo::bar::{{closure}}`
177
/// registry.register_with_name(core::any::type_name_of_val(&div), div)?;
178
/// # Ok(())
179
/// # }
180
/// ```
181
///
182
/// Names must be unique.
183
///
184
/// ```should_panic
185
/// # use bevy_reflect::func::FunctionRegistry;
186
/// fn one() {}
187
/// fn two() {}
188
///
189
/// let mut registry = FunctionRegistry::default();
190
/// registry.register_with_name("my_function", one).unwrap();
191
///
192
/// // Panic! A function has already been registered with the name "my_function"
193
/// registry.register_with_name("my_function", two).unwrap();
194
/// ```
195
///
196
/// [name]: DynamicFunction::name
197
/// [`register`]: Self::register
198
/// [`overwrite_registration_with_name`]: Self::overwrite_registration_with_name
199
/// [type name]: core::any::type_name
200
pub fn register_with_name<F, Marker>(
201
&mut self,
202
name: impl Into<Cow<'static, str>>,
203
function: F,
204
) -> Result<&mut Self, FunctionRegistrationError>
205
where
206
F: IntoFunction<'static, Marker> + 'static,
207
{
208
let function = function.into_function().with_name(name);
209
self.register(function)
210
}
211
212
/// Registers the given function, overwriting any existing registration.
213
///
214
/// This function accepts both functions that satisfy [`IntoFunction`]
215
/// and direct [`DynamicFunction`] instances.
216
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
217
/// and mapped according to its [name].
218
///
219
/// Because the function must have a name,
220
/// anonymous functions (e.g. `|a: i32, b: i32| { a + b }`) and closures must instead
221
/// be registered using [`overwrite_registration_with_name`] or manually converted to a [`DynamicFunction`]
222
/// and named using [`DynamicFunction::with_name`].
223
/// Failure to do so will result in an error being returned.
224
///
225
/// To avoid overwriting existing registrations,
226
/// it's recommended to use the [`register`] method instead.
227
///
228
/// Returns the previous function with the same name, if any.
229
///
230
/// [name]: DynamicFunction::name
231
/// [`overwrite_registration_with_name`]: Self::overwrite_registration_with_name
232
/// [`register`]: Self::register
233
pub fn overwrite_registration<F, Marker>(
234
&mut self,
235
function: F,
236
) -> Result<Option<DynamicFunction<'static>>, FunctionRegistrationError>
237
where
238
F: IntoFunction<'static, Marker> + 'static,
239
{
240
let function = function.into_function();
241
let name = function
242
.name()
243
.ok_or(FunctionRegistrationError::MissingName)?
244
.clone();
245
246
Ok(self.functions.insert(name, function))
247
}
248
249
/// Registers the given function, overwriting any existing registration.
250
///
251
/// This function accepts both functions that satisfy [`IntoFunction`]
252
/// and direct [`DynamicFunction`] instances.
253
/// The given function will internally be stored as a [`DynamicFunction<'static>`]
254
/// with its [name] set to the given name.
255
///
256
/// Functions are mapped according to their name.
257
/// To avoid overwriting existing registrations,
258
/// it's recommended to use the [`register_with_name`] method instead.
259
///
260
/// This method is a convenience around calling [`IntoFunction::into_function`] and [`DynamicFunction::with_name`]
261
/// on the function and inserting it into the registry using the [`overwrite_registration`] method.
262
///
263
/// Returns the previous function with the same name, if any.
264
///
265
/// [name]: DynamicFunction::name
266
/// [`register_with_name`]: Self::register_with_name
267
/// [`overwrite_registration`]: Self::overwrite_registration
268
pub fn overwrite_registration_with_name<F, Marker>(
269
&mut self,
270
name: impl Into<Cow<'static, str>>,
271
function: F,
272
) -> Option<DynamicFunction<'static>>
273
where
274
F: IntoFunction<'static, Marker> + 'static,
275
{
276
let function = function.into_function().with_name(name);
277
match self.overwrite_registration(function) {
278
Ok(existing) => existing,
279
Err(FunctionRegistrationError::MissingName) => {
280
unreachable!("the function should have a name")
281
}
282
Err(FunctionRegistrationError::DuplicateName(_)) => {
283
unreachable!("should overwrite functions with the same name")
284
}
285
}
286
}
287
288
/// Calls the function with the given [name] and [args].
289
///
290
/// Returns `None` if no function with the given name is registered.
291
/// Otherwise, returns the result of the function call.
292
///
293
/// [name]: DynamicFunction::name
294
/// [args]: ArgList
295
pub fn call<'a>(&self, name: &str, args: ArgList<'a>) -> Option<FunctionResult<'a>> {
296
let func = self.get(name)?;
297
Some(func.call(args))
298
}
299
300
/// Get a reference to a registered function by [name].
301
///
302
/// [name]: DynamicFunction::name
303
pub fn get(&self, name: &str) -> Option<&DynamicFunction<'static>> {
304
self.functions.get(name)
305
}
306
307
/// Returns `true` if a function with the given [name] is registered.
308
///
309
/// [name]: DynamicFunction::name
310
pub fn contains(&self, name: &str) -> bool {
311
self.functions.contains_key(name)
312
}
313
314
/// Returns an iterator over all registered functions.
315
pub fn iter(&self) -> impl ExactSizeIterator<Item = &DynamicFunction<'static>> {
316
self.functions.values()
317
}
318
319
/// Returns the number of registered functions.
320
pub fn len(&self) -> usize {
321
self.functions.len()
322
}
323
324
/// Returns `true` if no functions are registered.
325
pub fn is_empty(&self) -> bool {
326
self.functions.is_empty()
327
}
328
}
329
330
impl Debug for FunctionRegistry {
331
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
332
f.debug_set().entries(self.functions.values()).finish()
333
}
334
}
335
336
/// A synchronized wrapper around a [`FunctionRegistry`].
337
#[derive(Clone, Default, Debug)]
338
pub struct FunctionRegistryArc {
339
/// The wrapped [`FunctionRegistry`].
340
pub internal: Arc<RwLock<FunctionRegistry>>,
341
}
342
343
impl FunctionRegistryArc {
344
/// Takes a read lock on the underlying [`FunctionRegistry`].
345
pub fn read(&self) -> RwLockReadGuard<'_, FunctionRegistry> {
346
self.internal.read().unwrap_or_else(PoisonError::into_inner)
347
}
348
349
/// Takes a write lock on the underlying [`FunctionRegistry`].
350
pub fn write(&self) -> RwLockWriteGuard<'_, FunctionRegistry> {
351
self.internal
352
.write()
353
.unwrap_or_else(PoisonError::into_inner)
354
}
355
}
356
357
#[cfg(test)]
358
mod tests {
359
use super::*;
360
use crate::func::{ArgList, IntoFunction};
361
use alloc::format;
362
363
#[test]
364
fn should_register_function() {
365
fn foo() -> i32 {
366
123
367
}
368
369
let mut registry = FunctionRegistry::default();
370
registry.register(foo).unwrap();
371
372
let function = registry.get(core::any::type_name_of_val(&foo)).unwrap();
373
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
374
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
375
}
376
377
#[test]
378
fn should_register_anonymous_function() {
379
let mut registry = FunctionRegistry::default();
380
registry.register_with_name("foo", || 123_i32).unwrap();
381
382
let function = registry.get("foo").unwrap();
383
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
384
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
385
}
386
387
#[test]
388
fn should_register_closure() {
389
let value = 123;
390
let foo = move || -> i32 { value };
391
392
let mut registry = FunctionRegistry::default();
393
registry.register_with_name("foo", foo).unwrap();
394
395
let function = registry.get("foo").unwrap();
396
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
397
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
398
}
399
400
#[test]
401
fn should_register_dynamic_function() {
402
fn foo() -> i32 {
403
123
404
}
405
406
let function = foo.into_function().with_name("custom_name");
407
408
let mut registry = FunctionRegistry::default();
409
registry.register(function).unwrap();
410
411
let function = registry.get("custom_name").unwrap();
412
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
413
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
414
}
415
416
#[test]
417
fn should_register_dynamic_closure() {
418
let value = 123;
419
let foo = move || -> i32 { value };
420
421
let function = foo.into_function().with_name("custom_name");
422
423
let mut registry = FunctionRegistry::default();
424
registry.register(function).unwrap();
425
426
let function = registry.get("custom_name").unwrap();
427
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
428
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
429
}
430
431
#[test]
432
fn should_only_register_function_once() {
433
fn foo() -> i32 {
434
123
435
}
436
437
fn bar() -> i32 {
438
321
439
}
440
441
let name = core::any::type_name_of_val(&foo);
442
443
let mut registry = FunctionRegistry::default();
444
registry.register(foo).unwrap();
445
let result = registry.register(bar.into_function().with_name(name));
446
447
assert!(matches!(
448
result,
449
Err(FunctionRegistrationError::DuplicateName(_))
450
));
451
assert_eq!(registry.len(), 1);
452
453
let function = registry.get(name).unwrap();
454
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
455
assert_eq!(value.try_downcast_ref::<i32>(), Some(&123));
456
}
457
458
#[test]
459
fn should_allow_overwriting_registration() {
460
fn foo() -> i32 {
461
123
462
}
463
464
fn bar() -> i32 {
465
321
466
}
467
468
let name = core::any::type_name_of_val(&foo);
469
470
let mut registry = FunctionRegistry::default();
471
registry.register(foo).unwrap();
472
registry
473
.overwrite_registration(bar.into_function().with_name(name))
474
.unwrap();
475
476
assert_eq!(registry.len(), 1);
477
478
let function = registry.get(name).unwrap();
479
let value = function.call(ArgList::new()).unwrap().unwrap_owned();
480
assert_eq!(value.try_downcast_ref::<i32>(), Some(&321));
481
}
482
483
#[test]
484
fn should_call_function_via_registry() {
485
fn add(a: i32, b: i32) -> i32 {
486
a + b
487
}
488
489
let mut registry = FunctionRegistry::default();
490
registry.register(add).unwrap();
491
492
let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);
493
let result = registry
494
.call(core::any::type_name_of_val(&add), args)
495
.unwrap();
496
let value = result.unwrap().unwrap_owned();
497
assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));
498
}
499
500
#[test]
501
fn should_error_on_missing_name() {
502
let foo = || -> i32 { 123 };
503
504
let function = foo.into_function();
505
506
let mut registry = FunctionRegistry::default();
507
let result = registry.register(function);
508
509
assert!(matches!(
510
result,
511
Err(FunctionRegistrationError::MissingName)
512
));
513
}
514
515
#[test]
516
fn should_debug_function_registry() {
517
fn foo() -> i32 {
518
123
519
}
520
521
let mut registry = FunctionRegistry::default();
522
registry.register_with_name("foo", foo).unwrap();
523
524
let debug = format!("{registry:?}");
525
assert_eq!(debug, "{DynamicFunction(fn foo() -> i32)}");
526
}
527
}
528
529