use crate::Cell;
trait Sealed {}
impl<T> Sealed for Cell<Option<T>> {}
#[doc = crate::_tags!(mem)]
#[cfg_attr(nightly_doc, doc(notable_trait))]
#[expect(private_bounds, reason = "Sealed")]
pub trait CellOptionExt<T>: Sealed {
fn modify<F: FnOnce(T) -> T>(&self, func: F);
fn modify_ret<F: FnOnce(T) -> T>(&self, func: F) -> Option<T>
where
T: Clone;
fn modify_mut<R, F: FnOnce(&mut T) -> R>(&self, func: F) -> Option<R>;
}
impl<T> CellOptionExt<T> for Cell<Option<T>> {
fn modify<F: FnOnce(T) -> T>(&self, func: F) {
let mut value = self.take();
if let Some(v) = value.take() {
self.set(Some(func(v)));
}
}
fn modify_ret<F: FnOnce(T) -> T>(&self, func: F) -> Option<T>
where
T: Clone,
{
self.replace(None).inspect(|v| {
let new_value = func(v.clone());
self.set(Some(new_value));
})
}
fn modify_mut<R, F: FnOnce(&mut T) -> R>(&self, func: F) -> Option<R> {
if let Some(mut v) = self.take() {
let result = func(&mut v);
self.set(Some(v));
Some(result)
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_modify() {
let cell = Cell::new(Some(10));
cell.modify(|x| x + 5);
assert_eq!(cell.get(), Some(15));
}
#[test]
fn test_modify_with_none() {
let cell: Cell<Option<i32>> = Cell::new(None);
cell.modify(|x| x + 5);
assert_eq!(cell.get(), None);
}
#[test]
fn test_modify_ret() {
let cell = Cell::new(Some(10));
let previous_value = cell.modify_ret(|x| x * 2);
assert_eq!(previous_value, Some(10));
assert_eq!(cell.get(), Some(20));
}
#[test]
fn test_modify_ret_with_none() {
let cell: Cell<Option<i32>> = Cell::new(None);
let previous_value = cell.modify_ret(|x| x * 2);
assert_eq!(previous_value, None);
assert_eq!(cell.get(), None);
}
#[test]
fn test_modify_mut_previous() {
let cell = Cell::new(Some(10));
let result = cell.modify_mut(|x| {
let prev = *x;
*x *= 2;
prev
});
assert_eq!(result, Some(10)); assert_eq!(cell.get(), Some(20));
}
#[test]
fn test_modify_mut() {
let cell = Cell::new(Some(10));
let result = cell.modify_mut(|x| {
*x *= 2;
*x + 5
});
assert_eq!(result, Some(25));
assert_eq!(cell.get(), Some(20));
}
#[test]
fn test_modify_mut_with_none() {
let cell: Cell<Option<i32>> = Cell::new(None);
let result = cell.modify_mut(|x| {
*x *= 2;
*x + 5
});
assert_eq!(result, None);
assert_eq!(cell.get(), None);
}
#[test]
fn test_modify_mut_side_effect() {
let cell = Cell::new(Some(10));
let result = cell.modify_mut(|x| {
*x += 3;
"Done"
});
assert_eq!(result, Some("Done"));
assert_eq!(cell.get(), Some(13));
}
}