use std::rc::Rc;
#[derive(Debug, Clone)]
pub enum LazyClonableContent<T:Clone> {
Ref(Rc<T>),
Computed(Rc<T>)
}
#[derive(Debug)]
pub struct LazyClonable<T:Clone> {
content: LazyClonableContent<T>
}
impl<T:Clone> LazyClonable<T> {
pub fn new(t:T) -> Self {
Self {
content: LazyClonableContent::Computed(Rc::new(t))
}
}
pub fn lazy_get(&mut self) -> Rc<T> {
match &self.content {
LazyClonableContent::Ref(r) => {
let r2 = Rc::new(r.as_ref().clone());
self.content = LazyClonableContent::Computed(r2.clone());
r2
}, LazyClonableContent::Computed(r) => { r.clone() }
}
}
pub fn lazy_clone(&self) -> Self {
Self {
content: LazyClonableContent::Ref(
match &self.content {
LazyClonableContent::Ref(r) => r.clone(),
LazyClonableContent::Computed(r) => r.clone()
}
)
}
}
pub fn is_cloned(&self) -> bool {
match &self.content {
LazyClonableContent::Ref(_) => false,
LazyClonableContent::Computed(_) => true
}
}
}
impl<T:Clone> Clone for LazyClonable<T> {
fn clone(&self) -> Self {
self.lazy_clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple_construct() {
let mut a = LazyClonable::new(42);
assert!(a.is_cloned());
assert_eq!(*(a.lazy_get().as_ref()), 42);
}
#[test]
fn simple_clone() {
let a = LazyClonable::new(42);
assert!(a.is_cloned());
let mut b = a.lazy_clone();
assert!(!b.is_cloned());
assert_eq!(*b.lazy_get().as_ref(), 42);
assert!(b.is_cloned());
}
}