tiny_fn/lib.rs
1//!
2//! Have you ever being placing closure into [`Box<dyn Fn(...)>`] and wondered:
3//! "Is there a crate to avoid heap allocations for small closures?"
4//!
5//! Wonder no more, this is the crate.
6//!
7//! # How to use
8//!
9//! This crate provides declarative macro [`tiny_fn!`] to generate closure wrappers
10//! able store closure erasing its type.
11//!
12//! Generated closure wrappers avoid heap allocations when wrapped closure fits inline storage.
13//!
14//! The macro is designed to be easy to write with simple syntax that mostly reuse constructs already existing in Rust.\
15//! Behavior of generated wrappers should be obvious from the first glance.
16//!
17//! # Example
18//!
19//! ```
20//! # use tiny_fn::tiny_fn;
21//! tiny_fn! {
22//! struct Foo = Fn(a: i32, b: i32) -> i32;
23//! }
24//!
25//! let foo: Foo = Foo::new(|a, b| a + b);
26//! assert_eq!(3, foo.call(1, 2));
27//! ```
28//!
29//! Macro expands to `struct Foo` definition with two public methods.
30//!
31//! * `Foo::new` accepts any value that implements [`Fn(i32, i32) -> i32`] and returns new instance of `Foo`.
32//! * `Foo::call` follows signature specified to the macro. e.g. `Foo::call` accepts `a: i32` and `b: i32` and returns [`i32`].\
33//! Plainly `Foo::call` calls closure from which this instance of `Foo` was crated using `a` and `b` arguments at the same positions.
34//!
35//! [`tiny_fn!`] macro supports defining multiple items at once.
36//!
37//! ```
38//! # use tiny_fn::tiny_fn;
39//! tiny_fn! {
40//! struct Foo = Fn(a: i32, b: i32) -> i32;
41//! struct Bar = Fn() -> String;
42//! }
43//!
44//! let foo: Foo = Foo::new(|a, b| a + b);
45//! let bar: Bar = Bar::new(|| "Hello, World!".to_string());
46//!
47//! assert_eq!(foo.call(1, 2), 3);
48//! assert_eq!(bar.call(), "Hello, World!");
49//! ```
50//!
51//! # Visibility
52//!
53//! [`tiny_fn!`] macro supports visibility qualifiers.
54//!
55//!
56//! ```
57//! # use tiny_fn::tiny_fn;
58//! tiny_fn! {
59//! pub struct Foo = Fn(a: i32, b: i32) -> i32;
60//! struct Bar = Fn() -> String;
61//! pub(crate) struct Baz = Fn();
62//! }
63//! ```
64//!
65//! # Attributes
66//!
67//! [`tiny_fn!`] macro supports item attributes, including documentation.
68//!
69//! ```
70//! # use tiny_fn::tiny_fn;
71//! tiny_fn! {
72//! /// This is `Foo` wrapper for that takes two `i32`s and return `i32`.
73//! pub struct Foo = Fn(a: i32, b: i32) -> i32;
74//! }
75//! ```
76//!
77//! # [`Fn*`] traits family
78//!
79//! [`tiny_fn!`] macro can generate closure wrappers for any of the [`Fn*`] traits family.
80//!
81//! ```
82//! # use tiny_fn::tiny_fn;
83//! tiny_fn! {
84//! struct A = Fn();
85//! struct B = FnMut();
86//! struct C = FnOnce();
87//! }
88//!
89//! let a = 42;
90//! let a: A = A::new(|| println!("{}", a));
91//! a.call();
92//! a.call();
93//!
94//! let mut b = 42;
95//! let mut b: B = B::new(|| b += 1);
96//! b.call();
97//! b.call();
98//!
99//! let c = String::from("Hello, World!");
100//! let c: C = C::new(move || println!("{}", c));
101//! c.call();
102//! // c.call(); // This will not compile, because `C` can be called only once.
103//! ```
104//!
105//! * `A` can wrap only closures that are callable when immutably borrowed. And so `A::call` takes `&self`.
106//! * `B` can wrap only closures that are callable when borrowed. And so `B::call` takes `&mut self`.
107//! * `C` can wrap any closures, even ones that are callable once. And so `C::call` takes `self`.
108//!
109//! # Generics
110//!
111//! Closure wrappers can be declared generic over number of types and those types should be used in function signature.
112//!
113//! ```
114//! # use tiny_fn::tiny_fn;
115//! tiny_fn! {
116//! struct BinOp<T> = Fn(a: T, b: T) -> T;
117//! }
118//!
119//! let add: BinOp<i32> = BinOp::new(|a, b| a + b);
120//! let mul: BinOp<i32> = BinOp::new(|a, b| a * b);
121//!
122//! assert_eq!(mul.call(add.call(1, 2), 3), 9);
123//! ```
124//!
125//! Here `BinOp` is generic over `T`.\
126//! `BiOp::<T>::new` accepts closures bounds by [`Fn(T, T) -> T`].
127//!
128//! Notably `T` is not constrained by traits in `BinOp`.\
129//! Closure wrappers only move arguments and return values, so they don't need to know anything else about the type.
130//!
131//! # Markers
132//!
133//! Closure wrappers can be declared with marker traits.
134//! Simply add `|` and list of `+` prefixed marker traits after function signature.
135//! In Fn traits family `|` symbol is not used, but here it is required due to declarative macro limitations.
136//!
137//! They will be added to bounds on contained types.
138//! And if autotraits, they will be implemented for the wrapper type as well.
139//!
140//! ```rust
141//! # use tiny_fn::tiny_fn;
142//! tiny_fn! {
143//! struct Foo = Fn(a: i32, b: i32) -> i32 | + Send;
144//! }
145//!
146//! let foo: Foo = Foo::new(|a, b| a + b);
147//!
148//! std::thread::spawn(move || {
149//! foo.call(1, 2);
150//! });
151//! ```
152//! # Special generic parameters
153//!
154//! Closure wrapper generated by [`tiny_fn!`] macro always have two generic parameters besides generic types specified by macro caller:
155//! * Lifetime `'closure`.\
156//! Wrapper contains closures bound by `'closure` lifetime.
157//! * Constant `INLINE_SIZE: usize`.\
158//! Closures with size up to `INLINE_SIZE` and alignment requirement not exceeding [`tiny_fn::ALIGN`] will be inlined into wrapper structure directly.\
159//! Otherwise heap allocation will occur.\
160//! `INLINE_SIZE` parameter is defaulted to [`tiny_fn::DEFAULT_INLINE_SIZE`].
161//!
162//! [`Box<dyn Fn(...)>`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
163//! [`Fn(i32, i32) -> i32`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
164//! [`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
165//! [`Fn(T, T) -> T`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
166//! [`tiny_fn::ALIGN`]: `ALIGN`
167//! [`tiny_fn::DEFAULT_INLINE_SIZE`]: `DEFAULT_INLINE_SIZE`
168
169#![no_std]
170
171extern crate alloc;
172
173/// Inline storage alignment.
174/// Closures with stricter alignment requirements will be heap allocated by wrapper
175/// even if size fits.
176pub const ALIGN: usize = core::mem::align_of::<crate::private::InlineStorage<1>>();
177
178/// Default value for `INLINE_SIZE` parameter of closure wrappers generated by [`tiny_fn!`] macro.
179pub const DEFAULT_INLINE_SIZE: usize = core::mem::size_of::<[usize; 3]>();
180
181/// Content of this module is not public API.
182/// It is used by macro output.
183#[doc(hidden)]
184pub mod private {
185 pub use alloc::boxed::Box;
186 pub use core::{
187 mem::{align_of, size_of, transmute, ManuallyDrop, MaybeUninit},
188 ptr::{copy_nonoverlapping, drop_in_place, read, NonNull},
189 };
190
191 pub trait Closure {
192 type Inner;
193 }
194
195 #[repr(C)]
196 pub struct VTable<D = unsafe fn(), C = unsafe fn()> {
197 pub drop: D,
198 pub call: C,
199 }
200
201 #[repr(C, align(16))]
202 #[derive(Clone, Copy)]
203 pub struct InlineStorage<const INLINE_SIZE: usize> {
204 pub storage: MaybeUninit<[u8; INLINE_SIZE]>,
205 }
206
207 pub type StoragePtr<const INLINE_SIZE: usize> = NonNull<InlineStorage<INLINE_SIZE>>;
208
209 pub type DropFn<const INLINE_SIZE: usize> = unsafe fn(StoragePtr<INLINE_SIZE>);
210}
211
212#[doc(hidden)]
213#[macro_export]
214macro_rules! private_tiny_fn {
215 (@call $(<$($hrl:lifetime),+>)? Fn $(< $($lt:lifetime,)* $($t:ident,)* >)? ($($arg_name:ident: $arg_type:ty),* $(,)?) $( -> $ret:ty)?) => {
216 fn call $(< $($hrl),+ >)? (&self, $($arg_name: $arg_type),*) $(-> $ret)? {
217 unsafe {
218 match self.vtable {
219 None => (*self.payload.boxed.closure)($($arg_name),*),
220 Some(vtable) => {
221 let call_fn: CallFn< $($($lt,)* $($t,)*)? INLINE_SIZE> = $crate::private::transmute(vtable.call);
222 call_fn(
223 $crate::private::NonNull::from(&self.payload.inline),
224 $($arg_name),*
225 )
226 }
227 }
228 }
229 }
230 };
231
232 (@call $(<$($hrl:lifetime),+>)? FnMut $(< $($lt:lifetime,)* $($t:ident,)* >)? ($($arg_name:ident: $arg_type:ty),* $(,)?) $( -> $ret:ty)?) => {
233 fn call $(< $($hrl),+ >)? (&mut self, $($arg_name: $arg_type),*) $(-> $ret)? {
234 unsafe {
235 match self.vtable {
236 None => (*(*self.payload.boxed).closure)($($arg_name),*),
237 Some(vtable) => {
238 let call_fn: CallFn< $($($lt,)* $($t,)*)? INLINE_SIZE> = $crate::private::transmute(vtable.call);
239 call_fn(
240 $crate::private::NonNull::from(&mut self.payload.inline),
241 $($arg_name),*
242 )
243 }
244 }
245 }
246 }
247 };
248
249 (@call $(<$($hrl:lifetime),+>)? FnOnce $(< $($lt:lifetime,)* $($t:ident,)* >)? ($($arg_name:ident: $arg_type:ty),* $(,)?) $( -> $ret:ty)?) => {
250 fn call $(< $($hrl),+ >)? (self, $($arg_name: $arg_type),*) $(-> $ret)? {
251 let mut me = $crate::private::ManuallyDrop::new(self);
252 unsafe {
253 match me.vtable {
254 None => ($crate::private::ManuallyDrop::take(&mut me.payload.boxed).closure)($($arg_name),*),
255 Some(vtable) => {
256 let call_fn: CallFn< $($($lt,)* $($t,)*)? INLINE_SIZE> = $crate::private::transmute(vtable.call);
257 call_fn(
258 $crate::private::NonNull::from(&mut (*me).payload.inline),
259 $($arg_name),*
260 )
261 }
262 }
263 }
264 }
265 };
266
267
268 (@call_outer $(<$($hrl:lifetime),+>)? Fn $(< $($lt:lifetime,)* $($t:ident,)* >)? ($($arg_name:ident: $arg_type:ty),* $(,)?) $( -> $ret:ty)?) => {
269 /// Calls wrapped closure
270 /// and returns it result.
271 #[allow(dead_code)]
272 pub fn call $(<$($hrl),+>)? (&self, $($arg_name: $arg_type),*) $(-> $ret)? {
273 self.inner.call($($arg_name,)*)
274 }
275 };
276
277 (@call_outer $(<$($hrl:lifetime),+>)? FnMut $(< $($lt:lifetime,)* $($t:ident,)* >)? ($($arg_name:ident: $arg_type:ty),* $(,)?) $( -> $ret:ty)?) => {
278 /// Calls wrapped closure
279 /// and returns it result.
280 #[allow(dead_code)]
281 pub fn call $(<$($hrl),+>)? (&mut self, $($arg_name: $arg_type),*) $(-> $ret)? {
282 self.inner.call($($arg_name,)*)
283 }
284 };
285
286 (@call_outer $(<$($hrl:lifetime),+>)? FnOnce $(< $($lt:lifetime,)* $($t:ident,)* >)? ($($arg_name:ident: $arg_type:ty),* $(,)?) $( -> $ret:ty)?) => {
287 /// Calls wrapped closure
288 /// and returns it result.
289 #[allow(dead_code)]
290 pub fn call $(<$($hrl),+>)? (self, $($arg_name: $arg_type),*) $(-> $ret)? {
291 self.inner.call($($arg_name,)*)
292 }
293 };
294
295 (@inline_call_cast Fn $ptr:ident) => {
296 (*(*$ptr.as_ptr()).storage.as_ptr().cast::<F>())
297 };
298
299 (@inline_call_cast FnMut $ptr:ident) => {
300 (*(*$ptr.as_ptr()).storage.as_mut_ptr().cast::<F>())
301 };
302
303 (@inline_call_cast FnOnce $ptr:ident) => {
304 $crate::private::read((*$ptr.as_ptr()).storage.as_mut_ptr().cast::<F>())
305 };
306
307 // (@get_self_bounds [$($lifetimes:lifetime)*] [$($traits:path)*] [$(,)?]) => {
308 // $($traits +)* $($lifetimes +)* 'closure
309 // };
310
311 // (@get_self_bounds [$($lifetimes:lifetime)*] [$($traits:path)*] [Self: $(+ $self_lifetimes:lifetime)* $(+ $self_traits:path)* $(, $tail:tt: $(+ $tail_lifetimes:lifetime)* $(+ $tail_traits:path)*,),* $(,)?]) => {
312 // $crate::private_tiny_fn!(@get_self_bounds [$($lifetimes)* $($self_lifetimes)*] [$($traits)* $($self_traits)*] [$( $($tail: $(+ $tail_lifetimes)* $(+ $tail_traits)*),* )*])
313 // };
314
315 // (@get_self_bounds [$($lifetimes:lifetime)*] [$($traits:path)*] [$not_self:tt: $(+ $not_self_lifetimes:lifetime)* $(+ $not_self_traits:path)* $(, $tail:tt: $(+ $tail_lifetimes:lifetime)* $(+ $tail_traits:path)*,),* $(,)?]) => {
316 // $crate::private_tiny_fn!(@get_self_bounds [$($lifetimes)*] [$($traits)*] [$( $($tail: $(+ $tail_lifetimes)* $(+ $tail_traits)*),* )*])
317 // };
318
319 // (@get_generic_bounds [$($lt:ident: $lifetimes:lifetime,)*] [$($tt:ident: $traits:path,)*] []) => {
320 // $($lt : $lifetimes,)*
321 // $($tt : $traits,)*
322 // Self: 'closure,
323 // };
324
325 // (@get_generic_bounds [$($lt:ident: $lifetimes:lifetime,)*] [$($tt:ident: $traits:path,)*] [Self: $(+ $self_lifetimes:lifetime)* $(+ $self_traits:path)* $(, $tail:tt: $(+ $tail_lifetimes:lifetime)* $(+ $tail_traits:path)*,),* $(,)?]) => {
326 // $crate::private_tiny_fn!(@get_generic_bounds [$($lt: $lifetimes,)*] [$($tt: $traits,)*] [$( $($tail: $(+ $tail_lifetimes)* $(+ $tail_traits)*),* )*])
327 // };
328
329 // (@get_generic_bounds [$($lt:ident: $lifetimes:lifetime,)*] [$($tt:ident: $traits:path,)*] [$not_self:tt: $(+ $not_self_lifetimes:lifetime)* $(+ $not_self_traits:path)* $(, $tail:tt: $(+ $tail_lifetimes:lifetime)* $(+ $tail_traits:path)*,),* $(,)?]) => {
330 // $crate::private_tiny_fn!(@get_generic_bounds [$($lt: $lifetimes,)* $($not_self: $not_self_lifetimes,)*] [$($tt: $traits,)* $($not_self: $not_self_traits.)*] [$( $($tail: $(+ $tail_lifetimes)* $(+ $tail_traits)*),* )*])
331 // };
332}
333
334/// Defines new structure type.
335/// This type will be constructible from any closure
336/// that implement specified [`Fn*`] trait.
337/// Closures that fits into inline storage will be placed there.
338/// Otherwise closure will be boxed.
339/// And it will have `call` method with the same signature as the closure.
340///
341/// Defined type can have generic parameters that can be used in function signature.
342/// It will always have additional `const INLINE_SIZE: usize` generic parameter,
343/// that controls size of the inline storage. Alignment of the inline storage is hardcoded to 16
344/// which is enough for any primitive type and thus fits most of the types.
345///
346/// [`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html
347#[macro_export]
348macro_rules! tiny_fn {
349 ($(
350 $(#[$meta:meta])*
351 $vis:vis struct $name:ident $(< $($lt:lifetime),* $(,)? $($t:ident),* >)? =
352 $(<$($hrl:lifetime),+>)?
353 $fun:ident ($(
354 $arg_name:ident: $arg_type:ty
355 ),* $(,)?)
356 $( -> $ret:ty)?
357 $(| $(+ $markers:path)+)?
358 $(where $( $wt:tt: $(+ $wtl:lifetime)* $(+ $wtb:path)* ),*)?
359 ;
360 )*) => {
361 $(
362 const _: () = {
363 type CallFn< $($($lt,)* $($t,)*)? const INLINE_SIZE: usize> = $(for<$($hrl),+>)? unsafe fn($crate::private::StoragePtr<INLINE_SIZE>, $($arg_type),*) $( -> $ret)?;
364
365 struct BoxedFn <'closure $( $(, $lt)* $(, $t)*)?>
366 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
367 {
368 closure: $crate::private::Box<dyn $(for<$($hrl),+>)? $fun($($arg_type),*) $(-> $ret)? $($(+ $markers)+)? + 'closure>,
369 }
370
371 #[doc(hidden)]
372 union TinyClosurePayload<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize>
373 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
374 {
375 inline: $crate::private::InlineStorage<INLINE_SIZE>,
376 boxed: $crate::private::ManuallyDrop<BoxedFn<'closure $($(, $lt)* $(, $t)*)?>>,
377 }
378
379 pub struct TinyClosure<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize>
380 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
381 {
382 vtable: Option<&'static $crate::private::VTable>,
383 payload: TinyClosurePayload<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE>,
384 }
385
386 impl<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize> Drop for TinyClosure<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE>
387 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
388 {
389 fn drop(&mut self) {
390 unsafe {
391 match self.vtable {
392 None => $crate::private::ManuallyDrop::drop(&mut self.payload.boxed),
393 Some(vtable) => {
394 let drop_fn: $crate::private::DropFn<INLINE_SIZE> = $crate::private::transmute(vtable.drop);
395 drop_fn($crate::private::NonNull::from(&mut self.payload.inline));
396 }
397 }
398 }
399 }
400 }
401
402 impl<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize> TinyClosure<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE>
403 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
404 {
405 fn new<F>(f: F) -> Self
406 where
407 F: $(for<$($hrl),+>)? $fun ($($arg_type),*) $( -> $ret)? $($(+ $markers)+)? + 'closure,
408 {
409 let size_fits = $crate::private::size_of::<F>() <= INLINE_SIZE;
410 let align_fits = $crate::private::align_of::<F>() <= $crate::ALIGN;
411
412 if size_fits && align_fits {
413 let mut inline = $crate::private::InlineStorage {
414 storage: $crate::private::MaybeUninit::uninit(),
415 };
416
417 unsafe {
418 let storage_f = inline.storage.as_mut_ptr() as *mut $crate::private::MaybeUninit<F>;
419 (*storage_f).write(f);
420 }
421
422 let vtable = unsafe {
423 $crate::private::transmute(&$crate::private::VTable::< $crate::private::DropFn<INLINE_SIZE>, CallFn< $($($lt,)* $($t,)*)? INLINE_SIZE>> {
424 drop: |ptr: $crate::private::StoragePtr<INLINE_SIZE>| {
425 $crate::private::drop_in_place(ptr.cast::<F>().as_ptr());
426 },
427 call: |ptr: $crate::private::StoragePtr<INLINE_SIZE> $(, $arg_name)*| {
428 $crate::private_tiny_fn!(@inline_call_cast $fun ptr)($($arg_name),*)
429 }
430 })
431 };
432 TinyClosure {
433 vtable: Some(vtable),
434 payload: TinyClosurePayload {
435 inline,
436 }
437 }
438 } else {
439 let boxed_fn = BoxedFn {
440 closure: $crate::private::Box::new(f),
441 };
442
443 TinyClosure {
444 vtable: None,
445 payload: TinyClosurePayload {
446 boxed: $crate::private::ManuallyDrop::new(boxed_fn),
447 }
448 }
449 }
450 }
451
452 $crate::private_tiny_fn!(@call $(<$($hrl),+>)? $fun $(< $($lt,)* $($t,)* >)? ($($arg_name: $arg_type),*) $( -> $ret)?);
453 }
454
455 impl<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize> $crate::private::Closure for $name<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE>
456 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
457 {
458 type Inner = TinyClosure<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE>;
459 }
460 };
461
462 #[repr(transparent)]
463 $(#[$meta])*
464 $vis struct $name<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize = { $crate::DEFAULT_INLINE_SIZE }>
465 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
466 {
467 #[allow(dead_code)]
468 inner: < $name<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE> as $crate::private::Closure>::Inner,
469 }
470
471 impl<'closure, $($($lt,)* $($t,)*)? const INLINE_SIZE: usize> $name<'closure, $($($lt,)* $($t,)*)? INLINE_SIZE>
472 $(where $( $($wt: $wtl,)* $($wt: $wtb,)* ),*)?
473 {
474 /// Constructs new instance of wrapper from specified closure.
475 /// Closure will be boxed if it doesn't fit inline storage.
476 #[inline]
477 pub fn new<F>(f: F) -> Self
478 where
479 F: $(for<$($hrl),+>)? $fun ($($arg_type),*) $( -> $ret)? $($(+ $markers)+)? + 'closure,
480 {
481 $name {
482 inner: < < $name < $($($t,)*)? INLINE_SIZE > as $crate::private::Closure>::Inner>::new(f),
483 }
484 }
485
486 $crate::private_tiny_fn!(@call_outer $(<$($hrl),+>)? $fun $(< $($lt,)* $($t,)* >)? ($($arg_name: $arg_type),*) $( -> $ret)?);
487 }
488 )*
489 };
490}
491
492#[cfg(feature = "example")]
493pub mod example {
494 //! This module contains a few example declarations with [`tiny_fn!`] macro.\
495 //! And their usage in the section below.
496 //!
497 //! # Usage
498 //!
499 //! ```
500 //! # extern crate alloc;
501 //! # use tiny_fn::example::*;
502 //! # use alloc::{borrow::ToOwned, format};
503 //! #
504 //! let binop: BinOp::<i32, 24> = BinOp::new(|a, b| a + b);
505 //! assert_eq!(3, binop.call(1, 2));
506 //!
507 //! let a = "Hello".to_owned();
508 //! let b = "world".to_owned();
509 //! let make_string = MakeString::<32>::new(move || format!("{a} {b}!"));
510 //!
511 //! assert_eq!(make_string.call(), "Hello world!");
512 //! ```
513
514 tiny_fn! {
515 /// Contains any binary operation for a specific type.
516 /// That takes two values of that type
517 /// and returns value of that type.
518 pub struct BinOp<T> = Fn(a: T, b: T) -> T;
519
520 pub struct MakeString = Fn() -> alloc::string::String;
521 }
522}
523
524#[cfg(test)]
525mod tests {
526 use alloc::string::String;
527
528 #[test]
529 fn test() {
530 use alloc::rc::Rc;
531
532 tiny_fn! {
533 pub(crate) struct Foo<T> = FnMut(a: &T, b: T) -> T | + Send;
534 pub struct Bar = FnOnce(b: u8) -> alloc::string::String;
535 pub struct Baz<'a> = Fn(a: &'a str) -> &'a str | + Send;
536 pub struct Hrl = <'a> Fn(a: &'a str) -> &'a str | + Send;
537 struct Complex<'a, A, B> = <'b> Fn(a: &'a A, b: &'b B) -> &'a str | + Send where A: + 'a;
538 }
539
540 let mut x = 3;
541 let mut foo = Foo::<u8>::new(|a, b| {
542 x += a + b;
543 x
544 });
545 let bar: Bar<0> = Bar::new(|b| alloc::format!("{}", b));
546
547 assert_eq!(6, foo.call(&1, 2));
548 assert_eq!(13, foo.call(&3, 4));
549
550 assert_eq!("3", bar.call(3));
551
552 fn assert_send<T: Send>() {}
553 assert_send::<Foo<Rc<u8>>>();
554 let s = String::new();
555
556 let baz: Baz = Baz::new(|a: &str| a);
557
558 let _: &'static str = baz.call("Hello, World!");
559
560 // let _: &str = baz.call(&s); // This will not compile, because `s` is not `'static` and `baz` is bound to `'static` lifetime.
561
562 let mut hlp: Hrl = Hrl::new(|a: &str| a);
563
564 let _: &'static str = hlp.call("Hello, World!");
565
566 hlp = Hrl::new(|_| "foo");
567 let _: &str = hlp.call(&s); // This compiles because argument's lifetime is not bound by the type.
568
569 let complex: Complex<u8, u8> = Complex::new(|a: &u8, b: &u8| {
570 if *a > *b {
571 "a is greater"
572 } else {
573 "b is greater"
574 }
575 });
576 }
577}
578