I'm new to traits and struggling with what might be an impossible ask.
I want a collection/struct (TroveHistory) which is generic on a type which must implement the trait Trove, but I don't want the collection to accept any type which implements Trove. So put together some test code to try and figure out if this is possible.
In the following code I have the trait Trove, two structs which implement it (Website and Webpage) and a collection TroveHistory. I want TroveHistory to be generic so I anyone can use it to hold a type which implements Trove.
I'm not sure how to specify that it should only be generic for something which implements Trove (maybe struct TroveHistory<T: Trove>
) and that it should only accept one type rather than any type which implements Trove.
I've tried a few variations on the generic such as <T>
(in the code below) <T: Trove>
and so on but can't get everything right in both the definitions and the test function.
Here's one attempt to test this which has two compilation errors (commented) and at the bottom a test function which also explains what I'm trying to achieve.
/// A snapshot of a generic item, struct or collection which has a
/// type and can be stored or loaded from storage.
pub trait Trove {
fn trove_type(&self) -> u32;
fn trove_store(&self) -> bool;
fn trove_load() -> Self;
}
/// An ordered collection of Trove objects.
pub struct TroveHistory<T: Trove> {
troves: Vec<T>,
}
impl TroveHistory<T> {
// error above: cannot find type `T` in this scope
pub fn new() -> TroveHistory<T> {
// error above: cannot find type `T` in this scope
TroveHistory { troves: vec![] }
}
pub fn trove_add(&self, trove: &impl Trove) {
self.troves.push(trove);
}
}
// A struct which will can be held in a TroveHistory
pub struct Website {
content: String,
}
impl Website {
pub fn new() -> Website {
Website {
content: String::from(""),
}
}
pub fn content(&self) -> String {
return self.content.clone();
}
}
impl Trove for Website {
fn trove_type(&self) -> u32 {
1
}
fn trove_store(&self) -> bool {
true
}
fn trove_load() -> Self {
Website {
content: String::from("Some content"),
}
}
}
// A second struct which will can be held in a TroveHistory
pub struct WebPage {
content: String,
}
impl WebPage {
pub fn new() -> WebPage {
WebPage {
content: String::from(""),
}
}
pub fn content(&self) -> String {
return self.content.clone();
}
}
impl Trove for WebPage {
fn trove_type(&self) -> u32 {
1
}
fn trove_store(&self) -> bool {
true
}
fn trove_load() -> Self {
WebPage {
content: String::from("Some content"),
}
}
}
#[test]
pub fn test() {
println!("TEST!");
let ws = Website::new();
let wp = WebPage::new();
let history = TroveHistory::new();
history.trove_add(&ws);
// Ideally the next line should not compile because I want
// pub struct TroveHistory<T: Trove> to restrict the trove
// parameter to TroveHistory<Website> rather than to
// any type which implement Trove. But at the moment
// I can't get it to compile due to errors indicated above
// at:
// impl TroveHistory<T> {
// pub fn new() -> TroveHistory<T> {
history.trove_add(&wp);
}