How to constrain by AsRef<T: Trait>?

But

struct S<T> {
    s: T
}

needs to own a value, and a reference wouldn't allow it to own that value.

The problem would then occur later when you want to use the value. A function might require that T: Deref<Target = U>, U: Tr. Then, if T is an Rc<i32>, it works. But if T is an i32, it won't work. And if we make T to be a &'a i32, we introduce another lifetime (and need to store the integer somewhere else).

Yes, that's what I meant with "unwieldy". It's not very nice. I do see Deref as an alternative, but then you need something like deref_owned::Owned if you want to store an owned value directly (or resort to Box or Cow::Owned as workaround).


Example:

use std::borrow::Borrow;
use std::marker::PhantomData;
use std::ops::Deref;

trait Tr {
    fn use_tr(&self);
}
impl Tr for i32 {
    fn use_tr(&self) {
        println!("I'm integer {}.", self);
    }
}

struct S<T, U> {
    s: T,
    phantom: PhantomData<fn(&T) -> &U>,
}

impl<T, U> S<T, U> {
   fn new(s: T) -> Self {
        Self {
           s,
           phantom: PhantomData,
        }
   }
}

impl<T, U> S<T, U>
where
    T: Borrow<U>,
    U: Tr,
{
   fn foo(&self) {
       self.s.borrow().use_tr();
   }
}

struct SWithDeref<T> {
    s: T,
}

impl<T> SWithDeref<T> {
   fn new(s: T) -> Self {
        Self {
           s,
        }
   }
}

impl<T, U> SWithDeref<T>
where
    T: Deref<Target = U>,
    U: Tr,
{
   fn foo(&self) {
       self.s.use_tr();
   }
}

fn main() {
    let a = S::new(45i32);
    a.foo();
    let b = S::<_, i32>::new(std::rc::Rc::new(49i32));
    b.foo();
    //let c = SWithDeref::new(45i32); // fails
    let c = SWithDeref::new(std::borrow::Cow::Owned::<i32>(99i32));
    c.foo();
    let d = SWithDeref::new(std::rc::Rc::new(101i32));
    d.foo();
}

(Playground)

Agreed, and I did it in the above Playground.


Alternatively you could use:

-    let c = SWithDeref::new(std::borrow::Cow::Owned::<i32>(99i32));
+    let c = SWithDeref::new(Box::new(99i32));

But that's an extra heap allocation.

Or you use another more simple "deref owned" wrapper, which has no type parameter.