#![doc = include_str!("../README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "atomic")]
pub mod atomic;
#[cfg(feature = "cell")]
pub mod cell;
pub mod lich;
pub mod shroud;
pub mod soul;
pub unsafe trait Binding {
const NEW: Self;
fn sever<const FORCE: bool>(&self) -> bool;
fn redeem(&self);
fn count(&self) -> u32;
fn increment(&self) -> u32;
fn decrement(&self) -> u32;
}
static PANIC: core::sync::atomic::AtomicBool = core::sync::atomic::AtomicBool::new(false);
fn is_panicking() -> bool {
#[cfg(feature = "std")]
if std::thread::panicking() {
return true;
}
PANIC.load(core::sync::atomic::Ordering::Relaxed)
}
#[cfg(feature = "cell")]
fn panic(value: u32) -> bool {
#[cfg(feature = "std")]
if std::thread::panicking() {
return false;
}
if PANIC.swap(true, core::sync::atomic::Ordering::Relaxed) {
return false;
}
if value <= 1 {
panic!("'{value}' `Lich<T>` has not been redeemed")
} else {
panic!("'{value}' `Lich<T>`es have not been redeemed")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn is_panicking_is_false() {
assert!(!is_panicking());
}
#[test]
#[cfg(all(feature = "cell", feature = "std"))]
fn is_panicking_is_true() {
std::panic::catch_unwind(|| panic(0)).unwrap_err();
assert!(is_panicking());
}
}
#[allow(dead_code)]
mod fails {
macro_rules! fail {
($function: ident, $block: block) => {
#[doc = concat!("```compile_fail\n", stringify!($block), "\n```")]
const fn $function() {}
};
}
fail!(can_not_drop_while_soul_lives, {
use core::{cell::RefCell, pin::pin};
use phylactery::cell::Soul;
let cell = RefCell::new(String::new());
let function = move |letter| cell.borrow_mut().push(letter);
let soul = Soul::new(&function);
drop(function);
});
fail!(can_not_clone_soul, {
use core::{cell::RefCell, pin::pin};
use phylactery::cell::Soul;
let cell = RefCell::new(String::new());
let soul = Soul::new(move |letter| cell.borrow_mut().push(letter));
<Soul<_> as Clone>::clone(&soul);
});
fail!(can_not_send_cell_to_thread, {
use core::pin::pin;
use phylactery::cell::Soul;
use std::thread::spawn;
let soul = pin!(Soul::new(|| {}));
let lich = soul.as_ref().bind::<dyn Fn() + Send + Sync>();
spawn(move || lich());
});
fail!(can_not_send_unsync_to_thread, {
use core::pin::pin;
use phylactery::atomic::Soul;
use std::thread::spawn;
let soul = pin!(Soul::new(|| {}));
let lich = soul.as_ref().bind::<dyn Fn() + Send>();
spawn(move || lich());
});
}