Skip to main content

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}