Search code examples
rustvectortypes

Workaround for a vector of types in rust?



pub trait Props {
   // ...
}

// One, Two and Three implement Props
pub type One = LengthyServiceDefWithGenerics<...>;
pub type Two = AnotherServiceDefWithGenerics<...>;
pub type Three = YetAnother<...>;


impl Builder {
   pub fn build_it<P: Props>(&self) -> Elem<P> {
     Elem::new(self);
   }
}

// somewhere else in the codebase
// there might be more instances to be built than just a, b, c
let builder = Builder.new();
let a = builder.build_it::<One>();
let b = builder.build_it::<Two>();
let c = builder.build_it::<Three>();

This is existing code, quite simplified, in a large code base, and it runs.

As a rust rookie, I first naively thought I could just abstract this away by doing something like

impl Outer {
  pub fn new(props: Vec<Props>) {
     let builder = Builder::new();
     for p in props.iter() {
        builder.build_it::<p>();
     }
  }
}

but I guess that has several issues:

  • As far as I know there is no way to make a vector of just types in rust. Types don't take space in memory.
  • Even if they did, the iteration would pick an instance of that vector which probably can't just be passed to the function like this build_it::<p>

Is there a way to achieve this? I guess it needs to be done in a very different way.

I invested quite some time in simplifying quite a large codebase involved for this question, but there might things missing in this simplification, or the simplification stopped to make sense. I sincerely apoologise if this is the case. I also searched quite some time around to see if there are already existing questions, but "vector of types" yields results with quite different contexts.

I still hope it became clear what I want to do.


Solution

  • IIUC, a macro like the following is equivalent to your Outer::new:

    macro_rules! build_all {
       ($($t:ty),*) => {
          let builder = Builder::new();
          $(builder.build_it::<$t>();)*
       }
    }
    
    fn main() {
        build_all!(i32, f32, String);
    }
    

    Playground

    Note however that this can only be a compile-time construct. There is no way in Rust to build and use a list of types dynamically at run-time.