use core::{
cell::{BorrowError, BorrowMutError, Ref, RefCell, RefMut, UnsafeCell},
fmt::Debug,
};
pub struct TempRef<'a, T, F: FnMut(&mut T)> {
re: RefMut<'a, T>,
reset: &'a mut F,
}
impl<'a, T, F: FnMut(&mut T)> TempRef<'a, T, F> {
fn new(temp: &'a Temp<T, F>) -> Self {
TempRef {
re: temp.value.borrow_mut(),
reset: unsafe { &mut *temp.reset.get() },
}
}
fn try_new(temp: &'a Temp<T, F>) -> Result<Self, BorrowMutError> {
Ok(TempRef {
re: temp.value.try_borrow_mut()?,
reset: unsafe { &mut *temp.reset.get() },
})
}
pub fn reset(&mut self) {
(self.reset)(&mut self.re);
}
}
impl<'a, T, F: FnMut(&mut T)> core::ops::Deref for TempRef<'a, T, F> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.re
}
}
impl<'a, T, F: FnMut(&mut T)> core::ops::DerefMut for TempRef<'a, T, F> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.re
}
}
impl<'a, T, F: FnMut(&mut T)> Drop for TempRef<'a, T, F> {
fn drop(&mut self) {
(self.reset)(&mut self.re);
}
}
pub struct Temp<T, F: FnMut(&mut T)> {
value: RefCell<T>,
reset: UnsafeCell<F>,
}
impl<T, F: FnMut(&mut T)> Temp<T, F> {
pub const fn new(value: T, reset: F) -> Self {
Temp {
value: RefCell::new(value),
reset: UnsafeCell::new(reset),
}
}
pub fn new_with(mut value: T, mut reset: F) -> Self {
reset(&mut value);
Temp {
value: RefCell::new(value),
reset: UnsafeCell::new(reset),
}
}
pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
self.value.borrow()
}
pub fn borrow_mut<'a>(&'a self) -> TempRef<'a, T, F> {
TempRef::new(self)
}
pub fn try_borrow<'a>(&'a self) -> Result<Ref<'a, T>, BorrowError> {
self.value.try_borrow()
}
pub fn try_borrow_mut<'a>(&'a self) -> Result<TempRef<'a, T, F>, BorrowMutError> {
TempRef::try_new(self)
}
pub fn into_inner(self) -> T {
self.value.into_inner()
}
pub fn replace(&self, value: T) -> T {
self.value.replace(value)
}
pub fn replace_with<C: FnOnce(&mut T) -> T>(&self, f: C) -> T {
self.value.replace_with(f)
}
pub fn swap(&self, other: &RefCell<T>) {
self.value.swap(other);
}
pub fn reset(&self) {
unsafe { (*self.reset.get())(&mut self.value.borrow_mut()) }
}
pub fn try_reset(&self) -> Result<(), BorrowMutError> {
unsafe { (*self.reset.get())(&mut *self.value.try_borrow_mut()?) }
Ok(())
}
}
impl<T: Default, F: FnMut(&mut T)> Temp<T, F> {
pub fn new_default(reset: F) -> Self {
Temp {
value: RefCell::new(T::default()),
reset: UnsafeCell::new(reset),
}
}
pub fn new_default_with(mut reset: F) -> Self {
let mut default = T::default();
reset(&mut default);
Temp {
value: RefCell::new(default),
reset: UnsafeCell::new(reset),
}
}
}
impl<T: Debug, F: FnMut(&mut T)> Debug for Temp<T, F> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Temp").field("value", &self.value).finish()
}
}