Help needed with enums/traits/generics

#1

Hi, I hope someone can help me with this: I’ve been struggling quite a bit with dealing with trying to iterate over different types.

I have tried so many different ways, but everything seems to have some issue:

  • Creating an Vec<Filter> where Filter is an enum containing a Config struct - issue was that all over my code now I need to match against every single variant, and the enum has probably 30 variants. This combined with the fact I also have Vec<Input> and Vec<Output> made my codebase gigantic.
  • Vec<Box<dyn Config>> where Config is a trait - this caused issues down the road because I was trying to have Config return a reference to Self, which evidently is not allowed. I think I need to do this because each Config (e.g. MutateConfig, GeoipConfig) needs to be able to process(Value) as well as reference itself so that it knows how to process the Value.

Would someone be able to take a look at my code and see if you could make any suggestions? I’m really stuck with this one.

I created the refactor branch because I think my previous implementation of Tokio/Streams (on master) was wrong and causing a memory leak.

Any help would be greatly appreciated. I think there must be some much better way than what I have tried in the past, but I’m just not getting something.

#2

The high level overview of what I’m trying to do is:

  1. Parse TOML into various structs (e.g. MutateConfig, HttpPollerConfig, GrokConfig)
  2. Iterate over each of those configs asynchronously, passing a message from the first all the way down to the last
  3. Use the config struct values to process that message in different ways.
#3

You can return &[mut] dyn Config instead of &[mut] Self;
with that change the Vec<Ptr<dyn Config>> (where Ptr<T> may be Box<T>, &T, &mut T, Rc<T>, etc.) should work.

Example

#![deny(bare_trait_objects, elided_lifetimes_in_paths)]

use ::serde_json::Value;

pub
struct Message<'filter> {
    filter: &'filter dyn Config,
    value: Value,
}

pub
trait Config {
    fn process (&'_ self) -> Message<'_>;
}

pub
struct MutateConfig {
    // ...
}

impl Config for MutateConfig {
    fn process (self: &'_ Self) -> Message<'_>
    {
        let value = unimplemented!("example");
        Message {
            filter: self /* as &dyn Config */, // implicit coercion */
            value,
        }
    }
}
#4

Thanks! I’ll try this out.

What do underscore lifetimes mean?

#5

They are inferred lifetimes, these will be resolved through the rules of lifetime elision. It’s a way to show the lifetimes exist, without having to explicitly name them.