phylactery/lib.rs
1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4mod lich;
5mod shroud;
6mod soul;
7mod sync;
8
9pub use lich::Lich;
10/// A convenience macro to implement the [`Shroud<T>`] trait for a given trait.
11/// The macro is applied to a trait directly because it will derive blanket
12/// implementations of [`Shroud<T>`] for all `T: Trait`. It can also handle
13/// implementing [`Shroud<T>`] for all combinations of marker traits [`Send`],
14/// [`Sync`], and [`Unpin`] (e.g., `dyn Trait + Send`, `dyn Trait + Sync`, `dyn
15/// Trait + Send + Unpin`, etc.).
16///
17/// # Usage
18///
19/// ```
20/// use core::{
21/// fmt::{Debug, Display},
22/// str::FromStr,
23/// };
24/// use phylactery::shroud;
25///
26/// // Generates `impl<T: Simple> Shroud<T> for dyn Simple`.
27/// #[shroud]
28/// pub trait Simple {}
29///
30/// // The `..` will generate implementations for all combinations of the specified
31/// // traits. In this case `dyn Combine`, `dyn Combine + Send`, `dyn Combine + Sync + Unpin`,
32/// // `dyn Combine + Send + Sync + Unpin`, etc. Be wary that the number of
33/// // implementations can be very large if used with many traits.
34/// #[shroud(Send, Sync, Unpin, ..)]
35/// pub trait Combine {}
36///
37/// // Instead of `..`, the combinations can be specified manually by adding
38/// // multiple `#[shroud]`.
39/// #[shroud]
40/// #[shroud(Send)]
41/// #[shroud(Sync)]
42/// #[shroud(Send, Sync)]
43/// // `Self` means that the implementation will be for `Shroud<dyn Trait> for
44/// // dyn Trait` rather than a blanket implementation. In that case, associated
45/// // types must be specified explicitly (here with `A = usize`).
46/// #[shroud(Self, A = usize)]
47/// pub trait Complex<'a, T: Debug, U: FromStr + 'a, const N: usize>: Simple
48/// where
49/// for<'b> &'b T: Display,
50/// {
51/// type A;
52/// }
53/// ```
54#[cfg(feature = "shroud")]
55pub use phylactery_macro::shroud;
56pub use shroud::Shroud;
57pub use soul::Soul;
58
59#[allow(dead_code)]
60mod fails {
61 macro_rules! fail {
62 ($function: ident, $block: block) => {
63 #[doc = concat!("```compile_fail\n", stringify!($block), "\n```")]
64 const fn $function() {}
65 };
66 }
67
68 fail!(can_not_drop_while_soul_lives, {
69 use core::{cell::RefCell, pin::pin};
70 use phylactery::Soul;
71
72 let cell = RefCell::new(String::new());
73 let function = move |letter| cell.borrow_mut().push(letter);
74 let soul = Soul::new(&function);
75 drop(function);
76 });
77
78 fail!(can_not_clone_soul, {
79 use core::{cell::RefCell, pin::pin};
80 use phylactery::Soul;
81
82 let cell = RefCell::new(String::new());
83 let soul = Soul::new(move |letter| cell.borrow_mut().push(letter));
84 <Soul<_> as Clone>::clone(&soul);
85 });
86
87 fail!(can_not_send_unsync_to_thread, {
88 use core::pin::pin;
89 use phylactery::Soul;
90 use std::thread::spawn;
91
92 let soul = pin!(Soul::new(|| {}));
93 let lich = soul.as_ref().bind::<dyn Fn() + Send>();
94 spawn(move || lich());
95 });
96
97 // Issue 14: Lich<dyn FnOnce()> cannot be called through Deref (&T).
98 // Binding compiles; calling fails because FnOnce requires owning self.
99 fail!(can_not_call_lich_dyn_fnonce, {
100 use core::pin::pin;
101 use phylactery::Soul;
102
103 let soul = pin!(Soul::new(|| 42u32));
104 let lich = soul.as_ref().bind::<dyn FnOnce() -> u32>();
105 // compile error: cannot call `dyn FnOnce() -> u32` by value through `*`
106 let _result = (*lich)();
107 });
108}