use std::sync::Arc;
pub struct Shared<T: ?Sized>(Arc<T>);
impl<T> Shared<T> {
pub fn new(value: T) -> Self {
Shared(Arc::new(value))
}
pub fn into_arc(self) -> Arc<T> {
self.0
}
}
impl<T: ?Sized> Shared<T> {
pub fn ptr_eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl<T: ?Sized> From<Arc<T>> for Shared<T> {
fn from(arc: Arc<T>) -> Self {
Shared(arc)
}
}
impl<T: ?Sized> std::ops::Deref for Shared<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
impl<T: ?Sized> AsRef<T> for Shared<T> {
fn as_ref(&self) -> &T {
&self.0
}
}
impl<T: ?Sized> Clone for Shared<T> {
fn clone(&self) -> Self {
Shared(self.0.clone())
}
}
impl<T: ?Sized> PartialEq for Shared<T> {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0, &other.0)
}
}
impl<T: ?Sized> Eq for Shared<T> {}
impl<T: Default> Default for Shared<T> {
fn default() -> Self {
Shared::new(T::default())
}
}
impl<T: ?Sized + std::fmt::Debug> std::fmt::Debug for Shared<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(&*self.0, f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn clones_share_identity() {
let a = Shared::new(vec![1, 2, 3]);
let b = a.clone();
assert_eq!(a, b);
assert!(a.ptr_eq(&b));
}
#[test]
fn equal_contents_in_separate_allocations_are_not_equal() {
let a = Shared::new(vec![1, 2, 3]);
let b = Shared::new(vec![1, 2, 3]);
assert_ne!(a, b);
}
#[test]
fn does_not_require_the_payload_to_be_partial_eq() {
#[derive(Debug)]
struct NotComparable(#[allow(dead_code)] u32);
let a = Shared::new(NotComparable(1));
let b = a.clone();
assert!(a.ptr_eq(&b));
}
#[test]
fn derefs_to_the_payload() {
let s = Shared::new(String::from("hello"));
assert_eq!(s.len(), 5);
assert_eq!(&*s, "hello");
}
#[test]
fn default_allocates_a_default_payload() {
let s: Shared<Vec<u8>> = Shared::default();
assert!(s.is_empty());
}
#[test]
fn two_defaults_are_not_equal() {
let a: Shared<Vec<u8>> = Shared::default();
let b: Shared<Vec<u8>> = Shared::default();
assert_ne!(a, b);
}
#[test]
fn round_trips_through_arc() {
let arc = Arc::new(7u32);
let shared = Shared::from(arc.clone());
assert!(Arc::ptr_eq(&shared.clone().into_arc(), &arc));
}
#[test]
fn debug_shows_the_payload_not_the_pointer() {
let s = Shared::new(vec![1, 2]);
assert_eq!(format!("{s:?}"), "[1, 2]");
}
}