use std::rc::Rc;
use std::sync::{Arc, mpsc};
#[cfg(feature = "derive")]
pub use handle_trait_derive::Handle;
pub trait Handle: Clone {
#[inline]
#[must_use = "creating a handle without using it has no effect"]
fn handle(&self) -> Self {
self.clone()
}
}
impl<T: ?Sized> Handle for &T {}
impl<T: ?Sized> Handle for Rc<T> {}
impl<T: ?Sized> Handle for Arc<T> {}
impl<T> Handle for mpsc::Sender<T> {}
impl<T> Handle for mpsc::SyncSender<T> {}
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
use std::sync::atomic::{AtomicU32, Ordering};
#[test]
fn test_shared_reference_handle() {
let value = 42;
let ref1 = &value;
let ref2 = ref1.handle();
assert_eq!(*ref1, *ref2);
assert_eq!(*ref1, 42);
}
#[test]
fn test_rc_handle_entanglement() {
let data = Rc::new(RefCell::new(vec![1, 2, 3]));
let handle1 = data.handle();
let handle2 = data.handle();
assert_eq!(Rc::strong_count(&data), 3);
data.borrow_mut().push(4);
assert_eq!(*handle1.borrow(), vec![1, 2, 3, 4]);
assert_eq!(*handle2.borrow(), vec![1, 2, 3, 4]);
}
#[test]
fn test_arc_handle_entanglement() {
let counter = Arc::new(AtomicU32::new(0));
let handle1 = counter.handle();
let handle2 = counter.handle();
assert_eq!(Arc::strong_count(&counter), 3);
counter.fetch_add(1, Ordering::SeqCst);
handle1.fetch_add(1, Ordering::SeqCst);
handle2.fetch_add(1, Ordering::SeqCst);
assert_eq!(counter.load(Ordering::SeqCst), 3);
assert_eq!(handle1.load(Ordering::SeqCst), 3);
assert_eq!(handle2.load(Ordering::SeqCst), 3);
}
#[test]
fn test_mpsc_sender_handle() {
let (tx, rx) = mpsc::channel();
let tx_handle = tx.handle();
tx.send(1).unwrap();
tx_handle.send(2).unwrap();
assert_eq!(rx.recv().unwrap(), 1);
assert_eq!(rx.recv().unwrap(), 2);
}
#[test]
fn test_handle_is_clone() {
let rc = Rc::new(42);
let via_handle = rc.handle();
let via_clone = rc.clone();
assert_eq!(*via_handle, *via_clone);
assert_eq!(Rc::strong_count(&rc), 3);
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_basic() {
use std::sync::atomic::{AtomicU32, Ordering};
#[derive(Clone, Handle)]
struct MyHandle {
inner: Arc<AtomicU32>,
}
let h1 = MyHandle {
inner: Arc::new(AtomicU32::new(0)),
};
let h2 = h1.handle();
h1.inner.fetch_add(1, Ordering::SeqCst);
h2.inner.fetch_add(1, Ordering::SeqCst);
assert_eq!(h1.inner.load(Ordering::SeqCst), 2);
assert_eq!(h2.inner.load(Ordering::SeqCst), 2);
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_with_generics() {
#[derive(Clone, Handle)]
struct GenericHandle<T: Clone> {
inner: Arc<T>,
}
let h1 = GenericHandle {
inner: Arc::new(vec![1, 2, 3]),
};
let h2 = h1.handle();
assert_eq!(Arc::strong_count(&h1.inner), 2);
assert_eq!(*h1.inner, vec![1, 2, 3]);
assert_eq!(*h2.inner, vec![1, 2, 3]);
}
#[cfg(feature = "derive")]
#[test]
fn test_derive_with_where_clause() {
use std::fmt::Display;
#[derive(Clone, Handle)]
struct BoundedHandle<T>
where
T: Display + Clone,
{
inner: Arc<T>,
}
let h1 = BoundedHandle {
inner: Arc::new(42),
};
let _h2 = h1.handle();
assert_eq!(Arc::strong_count(&h1.inner), 2);
}
}