use std::cell::{
Cell,
RefCell,
Ref,
RefMut
};
use std::ops::{
Deref,
DerefMut
};
use std::borrow::{
Borrow,
BorrowMut
};
const EXPECT_VALUE_CELL_INITIALIZED: &str = "option in value_cell must be initialized at this point";
const EXPECT_EVALUATOR_STILL_PRESENT: &str = "evaluator must still be present at this point";
const EXPECT_VALUE_CELL_PTR_NOT_NULL: &str = "value_cell as ptr must not be null";
pub struct Lazy<T, Eval>
where Eval: FnOnce() -> T
{
evaluator_cell: Cell<Option<Eval>>,
value_cell: RefCell<Option<T>>
}
impl<T, Eval> Deref for Lazy<T, Eval>
where Eval: FnOnce() -> T
{
type Target = T;
fn deref(&self) -> &T {
self.as_ref_impl()
}
}
impl<T, Eval> DerefMut for Lazy<T, Eval>
where Eval: FnOnce() -> T
{
fn deref_mut(&mut self) -> &mut T {
self.as_mut_impl()
}
}
impl<T, Eval> AsRef<T> for Lazy<T, Eval>
where Eval: FnOnce() -> T
{
fn as_ref(&self) -> &T {
self.as_ref_impl()
}
}
impl<T, Eval> AsMut<T> for Lazy<T, Eval>
where Eval: FnOnce() -> T
{
fn as_mut(&mut self) -> &mut T {
self.as_mut_impl()
}
}
impl<T, Eval> Borrow<T> for Lazy<T, Eval>
where Eval: FnOnce() -> T
{
fn borrow(&self) -> &T {
self.as_ref_impl()
}
}
impl<T, Eval> BorrowMut<T> for Lazy<T, Eval>
where Eval: FnOnce() -> T
{
fn borrow_mut(&mut self) -> &mut T {
self.as_mut_impl()
}
}
impl<T, Eval> Lazy<T, Eval>
where Eval: FnOnce() -> T
{
pub fn new(evaluator: Eval) -> Self {
Self{
evaluator_cell: Cell::new(Some(evaluator)),
value_cell: RefCell::new(None)
}
}
#[must_use]
#[deprecated(since = "0.2.0", note = "will be removed in sloth 0.3.0; please use as_ref() or * deref operator instead")]
pub fn value_ref(&self) -> Ref<'_, T> {
self.init_once();
Ref::map(
self.value_cell.borrow(),
|value_option| {
value_option.as_ref().expect(EXPECT_VALUE_CELL_INITIALIZED)
}
)
}
#[must_use]
#[deprecated(since = "0.2.0", note = "will be removed in sloth 0.3.0; please use as_mut() or * deref operator instead")]
pub fn value_mut(&mut self) -> RefMut<'_, T> {
self.init_once();
RefMut::map(
self.value_cell.borrow_mut(),
|value_option| {
value_option.as_mut().expect(EXPECT_VALUE_CELL_INITIALIZED)
}
)
}
#[must_use]
pub fn unwrap(self) -> T {
self.init_once();
self.value_cell.replace(None).expect(EXPECT_VALUE_CELL_INITIALIZED)
}
fn as_ref_impl(&self) -> &T {
self.init_once();
unsafe {
self.value_cell
.as_ptr()
.as_ref()
.expect(EXPECT_VALUE_CELL_PTR_NOT_NULL)
.as_ref()
.expect(EXPECT_VALUE_CELL_INITIALIZED)
}
}
fn as_mut_impl(&mut self) -> &mut T {
self.init_once();
unsafe {
self.value_cell
.as_ptr()
.as_mut()
.expect(EXPECT_VALUE_CELL_PTR_NOT_NULL)
.as_mut()
.expect(EXPECT_VALUE_CELL_INITIALIZED)
}
}
fn init_once(&self) {
if self.value_cell.borrow().is_none() {
*self.value_cell.borrow_mut() = Some(self.evaluate());
}
}
fn evaluate(&self) -> T {
let evaluator = self.evaluator_cell
.take()
.expect(EXPECT_EVALUATOR_STILL_PRESENT);
evaluator()
}
}
impl<T, Eval> Lazy<T, Eval>
where T: Copy,
Eval: FnOnce() -> T
{
#[must_use]
pub fn value(&self) -> T {
self.init_once();
self.value_cell.borrow().expect(EXPECT_VALUE_CELL_INITIALIZED)
}
}