Strategy to create owned fields with generic types

The following compiles and expresses an intention but the issue is creation of the generic type. I want to create a Flexible class that uses a small set of traits and wants to take ownership of the implementors. Apologies up front for the silly illustration but the idea is Flexible uses one Grumbler, one Mumbler, and one Tumbler but each of those have two trait implementors. I can see how Flexible can do what it needs to with the traits as defined because this compiles and should work. The issue is how to create instances of Flexible assuming the json_config somehow contains the selections of which, e.g.:

{ "grumbler": "Grumbler1", "mumbler": "Mumbler2", "tumbler": "Tumbler2" }
/// This grumbles
pub trait Grumbler { fn grumble(&self); }
/// This mumbles
pub trait Mumbler { fn mumble(&self); }
/// This tumbles
pub trait Tumbler { fn tumble(&self); }

/// Must be super flexible, uses Grumbler, Mumbler, Tumbler.
pub struct Flexible<G, M, T>
{
    /// The grumbler
    pub the_grumbler: G,
    /// The mumbler
    pub the_mumbler: M,
    /// The tumbler
    pub the_tumbler: T,
}

pub struct Grumbler1 {}
pub struct Grumbler2 {}
pub struct Mumbler1 {}
pub struct Mumbler2 {}
pub struct Tumbler1 {}
pub struct Tumbler2 {}

////////////////////////////////////////////////////////////////////////////////////
// --- type impls ---
////////////////////////////////////////////////////////////////////////////////////
impl<G, M, T> Flexible<G, M, T>
where
    G: Grumbler,
    M: Mumbler,
    T: Tumbler,
{
    pub fn do_flexible_stuff(&self) {
        self.the_grumbler.grumble();
        self.the_mumbler.mumble();
        self.the_tumbler.tumble();
    }

    /// Create new one
    ///
    ///   * **json_config** - Create new `Flexible` selecting G from config.
    pub fn new(_json_config: &str) {}
    
    // Really would like to figure how to do this.
    // pub fn new(json_config: &str) -> Flexible<G, M, T> {
    //     Flexible {
    //         the_grumbler: Grumbler1{},
    //         the_mumbler: Mumbler2{},
    //         the_tumbler: Tumbler2{}
    //     }
    // }
}

impl Grumbler for Grumbler1 {
    /// Grumbles
    fn grumble(&self) {
    }
}

impl Grumbler for Grumbler2 {
    /// Grumbles
    fn grumble(&self) {
    }
}

impl Mumbler for Mumbler1 {
    /// Mumbles
    fn mumble(&self) {
    }
}

impl Mumbler for Mumbler2 {
    /// Mumbles
    fn mumble(&self) {
    }
}

impl Tumbler for Tumbler1 {
    /// Tumbles
    fn tumble(&self) {
    }
}

impl Tumbler for Tumbler2 {
    /// Tumbles
    fn tumble(&self) {
    }
}

Rust is statically typed, so something like

// M, T: Statically known
impl<M: Mumbler, T: Tumbler> {
    // G: Varies based on config
    pub fn new(json_config: &str) -> Flexible<G, M, T> where G: Grumbler {

(which decides the type of something at runtime) is not possible.

Assuming the traits are object safe [1], you could create a Flexible<Box<dyn Grumbler>, M, T> ; you'll need some code path for constructing each possible base grumbler and then type-erasing it into the Box<dyn Grumbler>.

Or perhaps an enum of possible Grumblers.


  1. and maybe with an implementation for Box<dyn Grumbler> ↩ī¸Ž

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.