use get_size::GetSize;
use get_size_derive::GetSize;
use std::ops::{Deref, DerefMut};
#[derive(Debug, GetSize)]
pub(crate) struct Detach<T> {
val: Option<Box<T>>,
}
impl<T> Default for Detach<T> {
fn default() -> Self {
Self { val: None }
}
}
impl<T> Clone for Detach<T>
where
T: Clone,
{
fn clone(&self) -> Self {
if let Some(t) = &self.val {
Detach {
val: Some(t.clone()),
}
} else {
Detach { val: None }
}
}
}
impl<T> Deref for Detach<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.val.as_ref().expect("already detached")
}
}
impl<T> DerefMut for Detach<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.val.as_mut().expect("already detached")
}
}
impl<T> Detach<T> {
#[allow(dead_code)]
pub(crate) fn new(val: T) -> Self {
Self {
val: Some(Box::new(val)),
}
}
#[allow(dead_code)]
pub(crate) fn is_detached(&self) -> bool {
self.val.is_none()
}
pub(crate) fn detach<K: Copy>(&mut self, key: K) -> Detached<K, T> {
let val = self.val.take().expect("already detached");
Detached::new(key, val)
}
pub(crate) fn attach<K: Copy>(&mut self, detached: Detached<K, T>) {
let Detached { key: _, val } = detached;
self.val.replace(val);
}
pub(crate) fn as_ref(&self) -> &T {
self.val.as_ref().expect("already detached")
}
pub(crate) fn as_mut(&mut self) -> &mut T {
self.val.as_mut().expect("already detached")
}
pub(crate) fn take(mut self) -> T {
*self.val.take().expect("already detached")
}
}
impl<T> From<T> for Detach<T> {
fn from(val: T) -> Self {
Self {
val: Some(Box::new(val)),
}
}
}
#[derive(Debug)]
pub struct Detached<K, T> {
key: K,
val: Box<T>,
}
impl<K, T> Detached<K, T>
where
K: Copy,
{
fn new(key: K, val: Box<T>) -> Self {
Self { key, val }
}
pub fn key(det: &Detached<K, T>) -> K {
det.key
}
}
impl<K, T> Deref for Detached<K, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.val.as_ref()
}
}
impl<K, T> DerefMut for Detached<K, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.val.as_mut()
}
}
#[cfg(test)]
mod tests {
use crate::ds::detach::Detach;
#[test]
fn test_detach() {
let mut dd = Detach::new("fop");
assert_eq!(dd.is_detached(), false);
assert_eq!(*dd.as_ref(), "fop");
assert_eq!(*dd.as_mut(), "fop");
let d = dd.detach(0u32);
assert_eq!(*d, "fop");
assert_eq!(d.trim(), "fop");
assert_eq!(dd.is_detached(), true);
dd.attach(d);
assert_eq!(dd.is_detached(), false);
let tt = dd.take();
assert_eq!(tt, "fop");
}
}