Stuck with structs

I am querying NETCONF for Nokia's. The platforms may have different versions, so I did my structs like so:

 pub struct Config {
        pub error: Option<RpcError>,
        pub xconfig: Option<XConfigRpcReply>,
        pub sconfig: Option<SConfigRpcReply>,
    }

    impl Config {
        fn new(error: Option<RpcError>,
               xconfig: Option<XConfigRpcReply>,
               sconfig: Option<SConfigRpcReply>,) -> Config {

            return
                Config {
                    error,
                    xconfig,
                    sconfig,
                }
       }
    }
   #[derive(Debug)]
    pub struct XConfigRpcReply {
        pub config: nokia_ixr_x_config::RpcReply,
    }
    #[derive(Debug)]
    pub struct SConfigRpcReply {
        pub config: nokia_ixr_s_config::RpcReply,
    }

This all works quite well until I have to get the data out of these. Do I have an XConfig or SConfig? Trying to match doesn't seem to work because match takes the first arm as the expected type and the second arm becomes a mismatched type.

I am wondering how to solve this. Would a Traits with for the two Config types do it?

I'm not familiar with the protocol, but if you can have an XConfig XOR an SConfig XOR an RpcError, wouldn't it be better to represent Config as an enum?

pub enum Config {
    Error(RpcError),
    XConfig(XConfigRpcReply),
    SConfig(SConfigRpcReply),
}

Would you mind elaborating? Maybe with a snippet? Can you do something like the following?

impl Config {
   fn rpc_reply(&self) -> Option<&RpcReply> {
       if let Some(x) = &self.xconfig {
           return Some(&x.config);
       }
       if let Some(s) = &self.sconfig {
           return Some(&s.config);
       }
       None
   }
}

I guess the next question is how do I get the config out of this?

conf = {netconf::netconf::Config::SConfigRpcReply} 
 0 = {netconf::netconf::SConfigRpcReply} 
  config = {response::nokia_ixr_s_config::RpcReply} 
   xmlns = {alloc::string::String} "urn:ietf:params:xml:ns:netconf:base:1.0"
   message_id = {alloc::string::String} "102"
   text = {core::option::Option<alloc::string::String>::None} None
   data = {response::nokia_ixr_s_config::Data} 

I think I got it to work, however, I don't understand exactly how I got it to work. I definitely need to understand what is going on under the hood when creating enums of structs as well as items behind a shared reference. But here's ultimately what I came up with:

In tests, I called like so:

let result = nc.get_config("running", None);
                if result.is_some() {
                  let c = result.unwrap();
                  let d = c.rpc_reply(&c);

My rpc_reply method looks like so:

pub enum Config {
        Error(RpcError),
        XConfig(XConfigRpcReply),
        SConfig(SConfigRpcReply),
    }

    impl Config {
        fn rpc_reply(&self, data: &Config) -> RpcReply {
            use Config::*;

            match &self {
                SConfig(data) => {
                    let reply = RpcReply::SConfig(data.config.clone());
                    return reply;
                },
                XConfig(data) => {
                    let reply = RpcReply::XConfig(data.config.clone());
                    return reply;
                },
                Error(data) => {
                    let reply = RpcReply::RpcError(data.error.clone());
                    return reply;
                },
            }
        }
    }

Thanks for pointing me in this direction!

I suspect you are confused about methods.

They take a special self parameter (or &self or &mut self).

The reason it is special is that it refers to the struct whose method is being called. It doesn't need passing in, it's passed in for you!

c.rpc_reply()

This is equivalent to

Config::rpc_reply(&c)

Hope that helps!

1 Like

I removed the parameter, data. Works as you said. Is that something specific to enums?

&self is not specific to enums, I meant to mention the exact same applies to structs too (both structs and enums)