Rust: generic (smart) pointers using GATs.
Generic associated types (GATs) allow you to define type, lifetime or const generics on associated types. An example use case can be found below:
use std::ops::Deref;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
trait SmartPointer {
type Pointer<Target>: Deref<Target = Target> + Clone;
fn new<T>(value: T) -> Self::Pointer<T>;
}
struct NonAtomic;
impl SmartPointer for NonAtomic {
type Pointer<Target> = Rc<Target>;
fn new<T>(value: T) -> Rc<T> {
Rc::new(value)
}
}
struct Atomic;
impl SmartPointer for Atomic {
type Pointer<Target> = Arc<Target>;
fn new<T>(value: T) -> Arc<T> {
Arc::new(value)
}
}
#[derive(Debug)]
struct Foo<P: SmartPointer> {
value: P::Pointer<Mutex<u32>>,
}
impl<P: SmartPointer> Clone for Foo<P> {
fn clone(&self) -> Self {
Self {
value: self.value.clone(),
}
}
}
impl<P: SmartPointer> Foo<P> {
fn new(value: u32) -> Self {
Self {
value: P::new(Mutex::new(value)),
}
}
}
fn main() {
let rc = Foo::<NonAtomic>::new(0);
*rc.value.lock().unwrap() = 42;
let arc = Foo::<Atomic>::new(0);
*arc.value.lock().unwrap() = 42;
println!("Foo<Atomic>: {:?}", *rc.value.lock().unwrap());
println!("Foo<NonAtomic>: {:?}", *arc.value.lock().unwrap());
}