use std::{fmt, sync};
use crate::ThreadAware;
use crate::affinity::Affinity;
pub(crate) struct ErasedCloneFn<T: ?Sized> {
value: sync::Arc<T>, adapter: sync::Arc<dyn ErasedClone<T>>, }
impl<T: ThreadAware + ?Sized + 'static> ErasedCloneFn<T> {
pub(crate) fn new<V: Send + Sync + 'static>(value: V, clone_fn: fn(&V) -> Box<T>) -> Self {
let initial = clone_fn(&value);
Self {
value: sync::Arc::from(initial),
adapter: sync::Arc::new(CloneAdapter { concrete: value, clone_fn }),
}
}
}
impl<T: ?Sized> ErasedCloneFn<T> {
pub(crate) fn clone_and_relocate(&self, source: Option<Affinity>, destination: Affinity) -> sync::Arc<T> {
let cloned = self.adapter.clone_and_relocate(source, destination);
sync::Arc::from(cloned)
}
pub(crate) fn arc(&self) -> &sync::Arc<T> {
&self.value
}
}
impl<T: ?Sized> fmt::Debug for ErasedCloneFn<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ErasedCloneFn").finish_non_exhaustive()
}
}
impl<T: ?Sized> Clone for ErasedCloneFn<T> {
fn clone(&self) -> Self {
Self {
value: sync::Arc::clone(&self.value),
adapter: sync::Arc::clone(&self.adapter),
}
}
}
trait ErasedClone<T: ?Sized>: Send + Sync {
fn clone_and_relocate(&self, source: Option<Affinity>, destination: Affinity) -> Box<T>;
}
struct CloneAdapter<V, T: ?Sized> {
concrete: V,
clone_fn: fn(&V) -> Box<T>,
}
impl<V: Send + Sync + 'static, T: ThreadAware + ?Sized + 'static> ErasedClone<T> for CloneAdapter<V, T> {
fn clone_and_relocate(&self, source: Option<Affinity>, destination: Affinity) -> Box<T> {
let mut cloned = (self.clone_fn)(&self.concrete);
cloned.relocate(source, destination);
cloned
}
}
impl<V, T: ?Sized> fmt::Debug for CloneAdapter<V, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("CloneAdapter").finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use crate::{Arc, PerCore, ThreadAware};
#[test]
fn mismatched_clone_fn_return_type_is_safe() {
let arc = Arc::<dyn ThreadAware, PerCore>::with_clone_fn(1_u32, |_x| Box::new(String::new()));
let _clone = arc.clone();
}
#[test]
fn erased_clone_fn_debug() {
let erased = super::ErasedCloneFn::<dyn ThreadAware>::new(1_u32, |x| Box::new(*x));
let dbg = format!("{erased:?}");
assert!(dbg.contains("ErasedCloneFn"), "{dbg}");
}
#[test]
fn clone_adapter_debug_and_clone_fn() {
let adapter = super::CloneAdapter::<u32, u32> {
concrete: 42,
clone_fn: |x| Box::new(*x),
};
let dbg = format!("{adapter:?}");
assert!(dbg.contains("CloneAdapter"), "{dbg}");
let boxed = (adapter.clone_fn)(&adapter.concrete);
assert_eq!(*boxed, 42);
}
}