How can I make something like this work:
struct FooStruct<A, B> where A : B, B : ?Sized {...}
I searched for some type marker to tell the compiler that S
must be a trait, searched the Rust documentation for some example of this pattern, and couldn't find other people having the same problem. Here is my code:
trait Factory<S> where S : ?Sized {
fn create(&mut self) -> Rc<S>;
}
trait Singleton<T> {
fn create() -> T;
}
struct SingletonFactory<T> {
instance: Option<Rc<T>>
}
impl<S, T> Factory<S> for SingletonFactory<T> where S : ?Sized, T : S + Singleton<T> {
fn create(&mut self) -> Rc<S> {
if let Some(ref instance_rc) = self.instance {
return instance_rc.clone();
}
let new_instance = Rc::new(T::create());
self.instance = Some(new_instance.clone());
new_instance
}
}
The compiler fails with the following error :
--> src/lib.rs:15:57
|
15 | impl<S, T> Factory<S> for SingletonFactory<T> where T : S + Singleton<T> {
| ^ not a trait
I managed to find an answer: the std::marker::Unsize<T>
trait, although not a stable feature in the current version of Rust (1.14.0).
pub trait Unsize<T> where T: ?Sized { }
Types that can be "unsized" to a dynamically-sized type.
This is broader than the "implements" semantic, but it is what I should have been searching for from the beginning, as the generic parameters in the example code can be other things than a struct and a trait or two traits (say sized and unsized arrays).
The generic example in the question can be written:
struct FooStruct<A, B>
where A: Unsize<B>,
B: ?Sized,
{
// ...
}
And my code :
impl<S, T> Factory<S> for SingletonFactory<T>
where S: ?Sized,
T: Unsize<S> + Singleton<T>,
{
// ...
}