Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust Constraints for Generic Type Reference

Here's the scenario: I have a structure and trait pair as follows:

trait Operation {
    fn operation(self) -> u32
}

struct Container<T: Sized + Operation> {
    x:T
}

impl <T: Sized + Operation> for Container<T> {
    fn do_thing(&self) -> u32 {
        // Do something with the field x.
    }
}

The operation requires a pass-by-value call whenever used, and the issue comes with anything similar to "do_thing." I would prefer to not have to enforce copy semantics for the type T and would like a workaround for this. Essentially I would like to know the following:

  1. Is it possible to enforce trait constraints on references of type parameters? Something along the lines of: struct Container<T: Sized + Operation> where &T: Operation { ... }. I've tried mucking with the syntax a bit, and I've not had any success.
  2. If the above is not currently possible, is it theoretically possible; i.e. it doesn't violate any require coherence properties or something along those lines?
  3. Would it be possible to create a second trait, say Middle: Operation, where Middle can require that any implementers of Middle, T, to also be required to implement Operation for &T.
  4. If neither of the above are possible, is there some other common workaround for this?

Some Notes:

  • I don't have access to change the Operation trait, it's given and it's what I'm to work with.
  • There's an old RFC that talks about some modifications to where clauses, but I didn't find anything related to reference constraints.
  • compiler version: rustc 1.8.0 (db2939409 2016-04-11)
like image 570
CSan Avatar asked Apr 21 '16 04:04

CSan


1 Answers

Yes, you can restrict &T to be Sized + Operation. You need to use Higher-Rank Trait Bounds and where.

trait Operation {
    fn operation(self) -> u32;
}

struct Container<T>
    where for<'a> &'a T: Sized + Operation
{
    x: T,
}

impl<T> Container<T>
    where for<'a> &'a T: Sized + Operation
{
    fn do_thing(&self) -> u32 {
        self.x.operation()
    }
}

impl<'a> Operation for &'a u32 {
    fn operation(self) -> u32 {
        *self
    }
}

fn main() {
    let container = Container { x: 1 };
    println!("{}", container.do_thing());
}

prints

1
like image 76
Dogbert Avatar answered Oct 01 '22 04:10

Dogbert