Syntax help: simplifying initialization of generated structures

I'm still learning Rust and have just started working with Protobuf definitions via Prost. The definitions are pre-existing (used in a number of projects already) so I can't alter those; I'm looking for help with better / more ideomatic Rust syntax for consuming the structures Prost generates.

In particular, here's a simplification of one scenario I'm dealing with:

#[derive(Default)]
pub struct A {
    id: Option<i64>,
}

#[derive(Default)]
pub struct B {
    parent: Option<A>,
}

#[derive(Default)]
pub struct C {
    parent: Option<B>,
    foo: Option<bool>,
}

...

let c = C { 
    foo: Some(true), 
    ..Default::default() 
}

if let Some(b) = c.parent {
    if let Some(a) = b.parent {
        a.id = Some(999);
    }
}

In initializing c, can I:

  • simplify Some(true) (i.e. some sort of auto-boxing?)
  • specify grandparent id either:
    a) directly in the struct initializer?
    b) by some terser syntax than the nested if let ... sequence?

For your auto-boxing, you can make a constructor. As for the nested if, you can use Option::and_then

if let Some(a) = c.get_parent().and_then(|b| b.get_parent())

Here I've added an get_parent that should return Option<&ParentType>, which you can implement using Option::as_ref.

Where did you add get_parent, given that the structs A, B and C are Prost generated code (and so can't be modified directly)?

You can add methods to any type by creating your own trait and implementing it for that type.

You can also add inherent methods to a type by putting an impl anywhere in the crate where the type is defined, even in a different module.

Impl blocks do not have to be in the same file as the struct definition, so you could just try putting this somewhere?

impl B {
    fn get_parent(&self) -> Option<&A> {
        self.parent.as_ref()
    }
}
1 Like

That's very helpful to know, I can tailor the generated API to my taste that way! Thanks!