Help find way arround incopatible types

please help, how would you solve this, i am stuck and not sure how to approach it. I have the following types. I understand what the error mean, no not sure what other way to go around it

#[derive(Debug)]
pub enum PduType {
    GetRequest,
    GetNextRequest,
    GetBulkRequest,
}

#[derive(Debug, Default, Clone, PartialEq)]
pub enum SnmpVersion {
    #[default]
    V2,
    V3,
}

i also have a function create_message(oids: Vec<ObjectIdentifier>, version: SnmpVersion, ptype: PduType)

inside this function there is a

use rasn_snmp::{
    v1::GetRequest,
    v2::{GetBulkRequest, GetNextRequest, GetRequest},
};

> pub fn create_message(oids: Vec<ObjectIdentifier>, version: SnmpVersion, ptype: PduType) -> SnmpMessage<PduType> {
    let pdu = Pdu {
        request_id: generate_id() as i32,
        error_index: 0u32,
        error_status: 0u32,
        variable_bindings: oids
            .into_iter()
            .map(|oid| VarBind {
                name: oid,
                value: VarBindValue::Unspecified,
            })
            .collect(),
    };
    // my issue is here, incompatible type, but i need to use the PduType.
    // i understand what the error mean, but not sure how else to do it
    let pdu_type = match ptype {
        PduType::GetRequest => GetRequest(pdu),
        PduType::GetNextRequest => GetNextRequest(pdu),
        PduType::GetBulkRequest => GetBulkRequest(pdu),
    };

    let encoded = match version {
        SnmpVersion::V2 => {
            let message = Message {
                version: Integer::from_slice(Sign::Plus, &[2]),
                community: Bytes::from("public"),
                data: pdu_type,    // << this is data: T  so generic
            };
            InnerSnmpMessage::V2(message)
        }
        SnmpVersion::V3 => {
            // skiped ...
        }
    };

    let message = SnmpMessage::msg(encoded);
}

here is the type for Message

pub struct Message<T> {
    pub version: Integer,
    pub community: OctetString,
    pub data: T,
}

The naive solution is to put everything inside the match ptype. Functionally, this is necessary since you're trying to lift a runtime branch (the enum) into a compile-time branch (the type of pdu_type). However, you can make a generic function avoid code duplication.

pub fn create_message(
    oids: Vec<ObjectIdentifier>,
    version: SnmpVersion,
    ptype: PduType,
) -> SnmpMessage<PduType> {
    let pdu = Pdu {
        request_id: generate_id() as i32,
        error_index: 0u32,
        error_status: 0u32,
        variable_bindings: oids
            .into_iter()
            .map(|oid| VarBind {
                name: oid,
                value: VarBindValue::Unspecified,
            })
            .collect(),
    };

    fn message_with_pdu_type<T>(pdu_type: T, version: SnmpVersion) -> SnmpMessage<PduType> {
        let encoded = match version {
            SnmpVersion::V2 => {
                let message = Message {
                    version: Integer::from_slice(Sign::Plus, &[2]),
                    community: Bytes::from("public"),
                    data: pdu_type, // << this is data: T  so generic
                };
                InnerSnmpMessage::V2(message)
            }
            SnmpVersion::V3 => {
                // skiped ...
            }
        };

        SnmpMessage::msg(encoded)
    }

    match ptype {
        PduType::GetRequest => message_with_pdu_type(GetRequest(pdu), version),
        PduType::GetNextRequest => message_with_pdu_type(GetNextRequest(pdu), version),
        PduType::GetBulkRequest => message_with_pdu_type(GetBulkRequest(pdu), version),
    }
}

You'll need add some kind of bound to T, probably the same ones that are on SnmpMessage::msg.

When asking for help and there is a compiler error, be sure to always post the full error message you get from running cargo build in the terminal.

But I took a look at the crate you're using and I'm guessing that instead of your PduType you should use Pdus from the crate. Pdus is an enum that can hold any of the objects you want. Then the Message::data can be type Pdus and does not need to be generic.

Just a guess.

1 Like

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.