I tried my best to simulate my Draft: Named impl with Implementation Selection Variant in current edition. The orginal idea is from wild hacked named impls by withoutboats
use std::marker::PhantomData;
pub trait NamedImplBase {
type Receiver: ?Sized;
}
// newtype wrapper
//#[fundamental]
#[repr(transparent)]
pub struct Wrap<NamedImpl>
where NamedImpl: NamedImplBase,
NamedImpl::Receiver: Sized
{
pub value: NamedImpl::Receiver,
pub phantom: PhantomData<NamedImpl>,
}
//#[fundamental]
#[repr(transparent)]
pub struct WrapRef<'a, NamedImpl>
where NamedImpl: NamedImplBase
{
pub value: &'a NamedImpl::Receiver,
pub phantom: PhantomData<NamedImpl>,
}
// convert methods and trait
impl<NamedImpl> Wrap<NamedImpl>
where NamedImpl: NamedImplBase,
NamedImpl::Receiver: Sized
{
pub fn new(value: NamedImpl::Receiver) -> Wrap<NamedImpl> {
Wrap {
value,
phantom: PhantomData,
}
}
}
impl<'a, NamedImpl> WrapRef<'a, NamedImpl>
where NamedImpl: NamedImplBase
{
pub fn new(value: &'a NamedImpl::Receiver) -> WrapRef<'a, NamedImpl> {
WrapRef {
value,
phantom: PhantomData,
}
}
}
// TODO WrapRefMut
// TODO impl Deref DerefMut From Into
// named impl base for ToString
pub trait NamedToString : NamedImplBase {
fn to_string(this: &Self::Receiver) -> String;
}
impl<NamedImpl> std::string::ToString for Wrap<NamedImpl>
where NamedImpl: NamedToString,
NamedImpl::Receiver: Sized
{
fn to_string(&self) -> String {
NamedImpl::to_string(&self.value)
}
}
impl<'a, NamedImpl> std::string::ToString for WrapRef<'a, NamedImpl>
where NamedImpl: NamedToString
{
fn to_string(&self) -> String {
NamedImpl::to_string(&self.value)
}
}
// third party crate 1
//impl ToString for [i32] use ToStringForIntSlice1 {}
pub enum ToStringForIntSlice1 {}
impl NamedImplBase for ToStringForIntSlice1 {
type Receiver = [i32];
}
impl NamedToString for ToStringForIntSlice1 {
fn to_string(this: &[i32]) -> String {
String::from("ToStringForIntSlice1")
}
}
// third party crate 2
//impl ToString for [i32] use ToStringForIntSlice2 {}
pub enum ToStringForIntSlice2 {}
impl NamedImplBase for ToStringForIntSlice2 {
type Receiver = [i32];
}
impl NamedToString for ToStringForIntSlice2 {
fn to_string(this: &[i32]) -> String {
String::from("ToStringForIntSlice2")
}
}
// proxy / decorator
pub struct ToStringProxy<T: ToString>(PhantomData<T>);
impl<T: ToString> NamedImplBase for ToStringProxy<T> {
type Receiver = T;
}
impl<T: ToString> NamedToString for ToStringProxy<T> {
fn to_string(this: &T) -> String {
let mut str = String::new();
str.push_str("before ");
str.push_str(&this.to_string());
str.push_str(" after");
return str;
}
}
// bin
fn main() {
let arr = [1,2,3];
//let a1 = &arr as &([i32] + ToStringForIntSlice1);
let arr_with_alter_impl1 = WrapRef::<'_, ToStringForIntSlice1>::new(&arr);
dbg!(arr_with_alter_impl1.to_string());
let dyn_arr1: &dyn ToString = &arr_with_alter_impl1;
dbg!(dyn_arr1.to_string());
let arr_with_alter_impl2 = WrapRef::<'_, ToStringForIntSlice2>::new(&arr);
dbg!(arr_with_alter_impl2.to_string());
let dyn_arr2: &dyn ToString = &arr_with_alter_impl2;
dbg!(dyn_arr2.to_string());
let num = 42;
dbg!(num.to_string());
let num_proxy = Wrap::<ToStringProxy<i32>>::new(num);
dbg!(num_proxy.to_string());
}