Moin,
I'm creating a plugin system. The desired interface may look like this:
fn main() {
let mars = Mars{};
// Desired interface
let plugin = Plugin::new("Mars")
.provider(ProviderType::Air(mars)) // mars.clone()?
.provider(ProviderType::Food(mars));
}
Now I'm stuck with how to store trait objects. I commented the code where I need help with design decision. Please excuse the fact that it's a bit contrary at a few points.
// Containers for example data
struct Food {
glycemic_index: u32
}
struct Air {
oxygen_level: u32
}
// Marker trait for storing itself in a container as trait objects.
// Or shall I use an enum?
trait Provider {}
// In the Plugin implementation I want to be able to call the traits' methods via matching.
// What's the best way here? Shall I store trait objects of type Provider or match over this enum?
enum ProviderType {
Air(AirProvider), // Won't work like this
Food(FoodProvider),
}
// Example Provider trait
trait FoodProvider: Provider {
fn food(&self) -> Food;
}
// Another example Provider trait
trait AirProvider: Provider {
fn air(&self) -> Air;
}
// Plugin = multiple Providers composed
struct Plugin {
name: String,
// What's the best way to store trait objects?
// Vec<Box<Provider>> ?
// Vec<&'a (Provider + 'a)> ?
// Vec<ProviderType> ?
// ... ?
providers: Vec<ProviderType>,
}
// Apply builder pattern. See main() for desired interface
impl Plugin {
fn new(name: &str) -> Self {
Self {
name: name.into(),
providers: Vec::new(),
}
}
// What's the best way to implement this function? Regarding function signature and body
fn provider(mut self, provider: &ProviderType) -> Self {
self.providers.push(provider);
self
}
}
// Specific Provider
struct Mars {}
impl Provider for Mars {}
impl AirProvider for Mars {
fn air(&self) -> Air {
Air {
oxygen_level: 55
}
}
}
impl FoodProvider for Mars {
fn food(&self) -> Food {
Food {
glycemic_index: 7
}
}
}
Thanks in advance