Skip to content

Latest commit

 

History

History
222 lines (194 loc) · 16.7 KB

rust-generated-code-guide.rst

File metadata and controls

222 lines (194 loc) · 16.7 KB

Rust Generated Code Guide

Usage

The crate pdl_derive lets developers embed their grammar in a source module using the pdl proc_macro attribute. Example usage:

use pdl_derive::pdl;
use pdl_runtime::*;

#[pdl("my-protocol.pdl")]
mod my_protocol {
}

The pdl proc_macro attribute must be attached to a module declaration. pdl preserves the original name, attributes, and items of the associated module.

The backend can also be pre-generated from the pdlc tool, and compiled as source. Example invocation:

cargo run my-protocol.pdl --output-format rust > my-protocol.rs

Language bindings

This section contains the generated rust bindings for language constructs that are stabilized.

Warning

PDL authorizes the use of rust keywords as identifier. Keyword identifiers are generated as raw identifiers, e.g. type is generated as r#type.

Enum declarations

Private prevents users from creating arbitrary scalar values in situations where the value needs to be validated. Users can freely deref the value, but only the backend may create it.

#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Private<T>(T);

impl<T> std::ops::Deref for Private<T> { .. }
enum TestEnum : 8 {
    A = 1,
    B = 2,
}
#[repr(u64)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
enum TestEnum {
    A = 1,
    B = 2,
}

impl TryFrom<u8> for TestEnum { .. }
impl From<TestEnum> for u8 { .. }
impl From<TestEnum> for u16 { .. }
impl From<TestEnum> for u32 { .. }
impl From<TestEnum> for u64 { .. }
impl From<TestEnum> for i8 { .. }
impl From<TestEnum> for i16 { .. }
impl From<TestEnum> for i32 { .. }
impl From<TestEnum> for i64 { .. }
enum TestEnum : 8 {
    A = 1,
    B = 2..10 {
        C = 3,
    },
}
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
enum TestEnum {
    A,
    C,
    B(Private<u8>),
}

impl TryFrom<u8> for TestEnum { .. }
impl From<TestEnum> for u8 { .. }
impl From<TestEnum> for u16 { .. }
impl From<TestEnum> for u32 { .. }
impl From<TestEnum> for u64 { .. }
impl From<TestEnum> for i8 { .. }
impl From<TestEnum> for i16 { .. }
impl From<TestEnum> for i32 { .. }
impl From<TestEnum> for i64 { .. }
enum TestEnum : 8 {
    A = 1,
    B = 2,
    OTHER = ..,
}
#[repr(u64)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
enum TestEnum {
    A,
    B,
    Other(Private<u8>),
}

impl From<u8> for TestEnum { .. }
impl From<TestEnum> for u8 { .. }
impl From<TestEnum> for u16 { .. }
impl From<TestEnum> for u32 { .. }
impl From<TestEnum> for u64 { .. }
impl From<TestEnum> for i8 { .. }
impl From<TestEnum> for i16 { .. }
impl From<TestEnum> for i32 { .. }
impl From<TestEnum> for i64 { .. }

Packet declarations

Generated packet representations will all implement the Packet trait from the pdl_runtime crate, which declares methods for parsing and serializing packets:

pub trait Packet: Sized {
    fn decode(buf: &[u8]) -> Result<(Self, &[u8]), DecodeError>;
    fn encode(&self, buf: &mut impl BufMut) -> Result<(), EncodeError>;
    fn encoded_len(&self) -> usize;
}

Additional methods are generated depending on characteristics of the PDL declaration (see the table below).

  • derived packet declarations implement decode_partial (resp. encode_partial).
    These methods will decode (resp. encode) fields from the parent payload.
  • packets with child declarations implement specialize. This method will
    attempt to decode one of the child packets from the input packet based on the constraints that are available.
packet Parent {
    a:8,
    _paylolad_,
}

packet TestPacket : Parent {
    b: TestEnum,
    _payload_,
}
#[device(Debug, Clone, PartialEq, Eq)]
struct TestPacket {
    a: u8,
    b: TestEnum,
    payload: Vec<u8>,
}

impl TestPacket {
    pub fn a(&self) -> u8 { .. }
    pub fn b(&self) -> TestEnum { .. }
    pub fn payload(&self) -> &[u8] { .. }

    pub fn encode_partial(&self, buf: &mut impl BufMut)
        -> Result<(), EncodeError> { .. }

    pub fn decode_partial(parent: &Parent)
        -> Result<Self, DecoderError { .. }
}

impl pdl_runtime::Packet for TestPacket { .. }
impl TryFrom<&TestPacket> for Bytes { .. }
impl TryFrom<&TestPacket> for Vec<u8> { .. }
packet TestPacket {
    a: 8,
    _payload_,
}

packet Child1 : TestPacket {
    ..
}

packet Child2 : TestPacket {
    ..
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct TestPacket {
    a: u8,
    payload: Vec<u8>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct TestPacketChild {
    Child1(Child1),
    Child2(Child2),
    None,
}

impl TestPacket {
    pub fn a(&self) -> u8 { .. }
    pub fn payload(&self) -> &[u8] { .. }
    pub fn specialize(&self)
        -> Result<TestPacketChild, DecodeError> { .. }
}

impl pdl_runtime::Packet for TestPacket { .. }
impl TryFrom<&TestPacket> for Bytes { .. }
impl TryFrom<&TestPacket> for Vec<u8> { .. }

Field declarations

a: 8
b: 24
a: u8
b: u32
a: TestEnum,
b: TestStruct
a: TestEnum
b: TestStruct
a: 8[],
b: 16[128],
c: TestEnum[],
d: TestStruct[]
a: Vec<u8>
b: [u16; 128]
c: Vec<TestEnum>
d: Vec<TestStruct>
a: 8 if c_a = 1,
b: TestEnum if c_b = 1,
c: TestStruct if c_c = 1,
a: Option<u8>
b: Option<TestEnum>
c: Option<TestStruct>
_payload_,
payload: Vec<u8>