5 releases

Uses new Rust 2024

new 0.2.0 Dec 16, 2025
0.1.3 Nov 13, 2025
0.1.2 Oct 10, 2025
0.1.1 Oct 10, 2025
0.1.0 Oct 10, 2025

#2033 in Procedural macros

22 downloads per month
Used in 4 crates (via rusmpp-core)

MIT/Apache

55KB
1K SLoC

Rusmpp-Macros

Build Status crates.io Crates.io (MSRV) docs.rs Crates.io (Downloads) Crates.io (License)

Procedural macros for rusmpp-core. Used to derive traits defined in rusmpp-core and implement boilerplate code for SMPP types.

Note

This crate assumes that the traits are defined in the crate itself under the modules decode, encode and tests.

You should not depend on this crate directly as it is strongly coupled with rusmpp-core.

Example

#[derive(Rusmpp)]
#[rusmpp(decode = owned)]
pub struct Command {
    id: CommandId,
    pub status: CommandStatus,
    pub sequence_number: u32,
    #[rusmpp(key = id, length = "unchecked")]
    pdu: Option<Pdu>,
}

This will expand to:

#[derive(Debug)]
pub struct CommandParts {
    pub id: CommandId,
    pub status: CommandStatus,
    pub sequence_number: u32,
    pub pdu: Option<Pdu>,
}

impl CommandParts {
    #[inline]
    #[allow(clippy::too_many_arguments)]
    pub const fn new(
        id: CommandId,
        status: CommandStatus,
        sequence_number: u32,
        pdu: Option<Pdu>,
    ) -> Self {
        Self {
            id,
            status,
            sequence_number,
            pdu,
        }
    }
    #[inline]
    #[allow(unused_parens)]
    pub fn raw(self) -> (CommandId, CommandStatus, u32, Option<Pdu>) {
        (self.id, self.status, self.sequence_number, self.pdu)
    }
}

impl Command {
    #[inline]
    pub fn into_parts(self) -> CommandParts {
        CommandParts {
            id: self.id,
            status: self.status,
            sequence_number: self.sequence_number,
            pdu: self.pdu,
        }
    }
}

impl crate::encode::Length for Command {
    fn length(&self) -> usize {
        let mut length = 0;
        length += crate::encode::Length::length(&self.id);
        length += crate::encode::Length::length(&self.status);
        length += crate::encode::Length::length(&self.sequence_number);
        length += crate::encode::Length::length(&self.pdu);
        length
    }
}

impl crate::encode::Encode for Command {
    fn encode(&self, dst: &mut [u8]) -> usize {
        let size = 0;
        let size = crate::encode::EncodeExt::encode_move(&self.id, dst, size);
        let size = crate::encode::EncodeExt::encode_move(&self.status, dst, size);
        let size = crate::encode::EncodeExt::encode_move(&self.sequence_number, dst, size);
        let size = crate::encode::EncodeExt::encode_move(&self.pdu, dst, size);
        size
    }
}

impl crate::decode::owned::DecodeWithLength for Command {
    fn decode(src: &[u8], length: usize) -> Result<(Self, usize), crate::decode::DecodeError> {
        let size = 0;
        let (id, size) = crate::decode::DecodeErrorExt::map_as_source(
            crate::decode::owned::DecodeExt::decode_move(src, size),
            crate::fields::SmppField::id,
        )?;
        let (status, size) = crate::decode::DecodeErrorExt::map_as_source(
            crate::decode::owned::DecodeExt::decode_move(src, size),
            crate::fields::SmppField::status,
        )?;
        let (sequence_number, size) = crate::decode::DecodeErrorExt::map_as_source(
            crate::decode::owned::DecodeExt::decode_move(src, size),
            crate::fields::SmppField::sequence_number,
        )?;
        let (pdu, size) = crate::decode::DecodeErrorExt::map_as_source(
            crate::decode::owned::DecodeWithKeyOptionalExt::decode_move(
                id,
                src,
                length.saturating_sub(size),
                size,
            ),
            crate::fields::SmppField::pdu,
        )?
        .map(|(this, size)| (Some(this), size))
        .unwrap_or((None, size));
        Ok((
            Self {
                id,
                status,
                sequence_number,
                pdu,
            },
            size,
        ))
    }
}

Notice the crate prefix. This is because the macro assumes that the traits are defined in the same crate.

Macro attributes are documented in the macro code itself.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~155–560KB
~13K SLoC