extern crate self as alloc_once;
pub use alloc_once_macros::alloc_once;
#[doc(hidden)]
pub mod __private {
pub use bumpalo::Bump;
}
pub struct AllocOnce<T> {
ptr: *mut T,
#[allow(dead_code)]
arena: bumpalo::Bump,
}
impl<T> AllocOnce<T> {
#[doc(hidden)]
pub unsafe fn __from_parts(arena: bumpalo::Bump, ptr: *mut T) -> Self {
Self { ptr, arena }
}
}
impl<T> core::ops::Deref for AllocOnce<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.ptr }
}
}
impl<T> core::ops::DerefMut for AllocOnce<T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.ptr }
}
}
impl<T> Drop for AllocOnce<T> {
fn drop(&mut self) {
unsafe { core::ptr::drop_in_place(self.ptr) }
}
}
#[cfg(test)]
mod tests {
use crate::alloc_once;
use std::cell::Cell;
use std::rc::Rc;
#[test]
fn single_value() {
let mut g = alloc_once!(1u8);
let (only,) = &mut *g;
*only += 1;
assert_eq!(*only, 2);
}
#[test]
fn many_different_types() {
let mut g = alloc_once!(1i32, [10u8, 20, 30], "hello");
let (n, bytes, s) = &mut *g;
*n += 41;
bytes[0] = 99;
assert_eq!((*n, bytes[0], *s), (42, 99, "hello"));
}
#[test]
fn drops_value_when_guard_drops() {
struct Flag(Rc<Cell<bool>>);
impl Drop for Flag {
fn drop(&mut self) {
self.0.set(true);
}
}
let dropped = Rc::new(Cell::new(false));
let guard = alloc_once!(Flag(Rc::clone(&dropped)));
assert!(!dropped.get());
drop(guard);
assert!(dropped.get());
}
}