Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 330b6df7 authored by Henri Chataing's avatar Henri Chataing
Browse files

gd/rust: Migrate to the new pdl rust generator

Bug: 284980692
Test: mmm packages/modules/Bluetooth/system/gd
Change-Id: I9e2fede3b37be9df1cef5e9ef13f0fccfd561bb1
parent f6064259
Loading
Loading
Loading
Loading
+3 −47
Original line number Diff line number Diff line
@@ -575,16 +575,9 @@ genrule {

genrule {
    name: "BluetoothGeneratedPackets_rust",
    tools: [
        "bluetooth_packetgen",
    ],
    cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/gd --out=$(genDir) $(in) --rust",
    srcs: [
        "hci/hci_packets.pdl",
    ],
    out: [
        "hci/hci_packets.rs",
    ],
    defaults: ["pdl_rust_generator_defaults"],
    srcs: ["hci/hci_packets.pdl"],
    out: ["hci/hci_packets.rs"],
}

rust_library {
@@ -634,43 +627,6 @@ rust_test_host {
    ],
}

// Generate and run tests of rust pdl parser for tests packets
genrule {
    name: "TestGeneratedPackets_rust",
    tools: [
        "bluetooth_packetgen",
    ],
    cmd: "$(location bluetooth_packetgen) --include=packages/modules/Bluetooth/system/gd --out=$(genDir) $(in) --rust",
    srcs: [
        "packet/parser/test/rust_test_packets.pdl",
    ],
    out: [
        "packet/parser/test/rust_test_packets.rs",
    ],
}

rust_test_host {
    name: "packets_test_rust",
    defaults: [
        "gd_rust_defaults",
        "mts_defaults",
    ],
    srcs: [
        "rust/packets/test_lib.rs",

        ":TestGeneratedPackets_rust",
    ],
    test_suites: ["general-tests"],
    edition: "2018",
    proc_macros: ["libnum_derive"],
    rustlibs: [
        "libbytes",
        "liblog_rust",
        "libnum_traits",
        "libthiserror",
    ],
}

// Generates binary schema data to be bundled and source file generated
genrule {
    name: "BluetoothGeneratedDumpsysBinarySchema_bfbs",
+0 −164
Original line number Diff line number Diff line
little_endian_packets

custom_field Boolean: 8 "Boolean"
enum Enum : 8 {
  // Keep 0x0 as invalid value
  ONE = 1,
  TWO = 2,
}

struct Struct {
  v: Enum,
  u: 8,
}

packet TestEnum {
  v: Enum,
}

packet TestCustomField {
  v: Boolean,
}

packet TestArraySize {
  _size_(array) : 8,
  array : Struct[],
}

packet TestArrayCount {
  _count_(array) : 8,
  array : Struct[],
}

packet TestPayloadSize {
  _size_(_payload_) : 8,
  _payload_,
}

packet TestBodySize {
  _size_(_body_) : 8,
  _body_,
}

// Test Packets #1
enum OpCode: 8 {
    ADD_ERR = 0,
    SUB_ERR = 1,
    ADD_RES = 2,
    SUB_RES = 3,
    ADD = 4,
    SUB = 5,
}

packet Command {
  op_code : OpCode,
  _size_(_payload_) : 8,
  _payload_,
}

// Packets for interfaces

packet ComputeCommand : Command { _payload_, }
packet ResCommand: Command { _payload_, }
packet ErrCommand: Command { _payload_, }


packet AddRes: ResCommand (op_code = ADD_RES) {
}

packet SubRes: ResCommand (op_code = SUB_RES) {
}

packet AddCommand: ComputeCommand (op_code = ADD) {
}

packet SubCommand: ComputeCommand (op_code = SUB) {
}

packet AddErr: ErrCommand(op_code = ADD_ERR) {
}

packet SubErr: ErrCommand(op_code = SUB_ERR) {
}

test AddRes {
  "\x02\x00",
}

test SubRes {
  "\x03\x00",
}

test AddCommand {
  "\x04\x00",
}

test SubCommand {
  "\x05\x00",
}

test AddErr {
  "\x00\x00",
}

test SubErr {
  "\x01\x00",
}


// Test Packets #2
enum Number : 8 {
  ZERO = 0,
  ONE = 1,
  TWO = 2,
  THREE = 3,
  FOUR = 4,
}

packet GrandParent {
  field_one : Number,
  field_two : Number,
  field_three: Number,
  field_x: Number,
  _payload_,
}

packet Parent : GrandParent {
  field_four: Number,
  field_five: Number,
  field_y: Number,
  _payload_,
}


packet ChildOneTwo: Parent (field_one = ONE, field_two = TWO) {
}

packet ChildThreeFour : Parent (field_one = THREE, field_two = FOUR) {
}

packet ChildThree: Parent(field_three = THREE) {
  _fixed_  = 5 : 8,
}

packet GrandChildThreeFive: ChildThree(field_five = ZERO) {
}

packet GrandChildThreeY: ChildThree(field_y = FOUR) {
}

test ChildOneTwo {
  "\x01\x02\x03\x01\x01\x02\x03",
}

test ChildThreeFour {
  "\x03\x04\x03\x01\x03\x04\x03",
}

test ChildThree {
  "\x01\x04\x03\x04\x03\x00\x02\x05",
}

test GrandChildThreeFive {
  "\x01\x04\x03\x04\x03\x00\x02\x05",
}
+21 −42
Original line number Diff line number Diff line
@@ -14,20 +14,22 @@
//  limitations under the License.

use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::process::{Command, Stdio};

fn main() {
    let packets_prebuilt = match env::var("HCI_PACKETS_PREBUILT") {
        Ok(dir) => PathBuf::from(dir),
        Err(_) => PathBuf::from("hci_packets.rs"),
    };

    if Path::new(packets_prebuilt.as_os_str()).exists() {
        let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
        let outputted = out_dir.join("../../hci/hci_packets.rs");
        let out_file = out_dir.join("hci_packets.rs");
        std::fs::copy(
            packets_prebuilt.as_os_str().to_str().unwrap(),
            out_dir.join(outputted.file_name().unwrap()).as_os_str().to_str().unwrap(),
            out_file.as_os_str().to_str().unwrap(),
        )
        .unwrap();
    } else {
@@ -44,45 +46,22 @@ fn generate_packets() {
        Err(_) => PathBuf::from(env::current_dir().unwrap()).join("../..").canonicalize().unwrap(),
    };

    let input_files = [gd_root.join("hci/hci_packets.pdl")];
    let outputted = [out_dir.join("../../hci/hci_packets.rs")];

    // Find the packetgen tool. Expecting it at CARGO_HOME/bin
    let packetgen = match env::var("CARGO_HOME") {
        Ok(dir) => PathBuf::from(dir).join("bin").join("bluetooth_packetgen"),
        Err(_) => PathBuf::from("bluetooth_packetgen"),
    };

    if !Path::new(packetgen.as_os_str()).exists() {
        panic!(
            "Unable to locate bluetooth packet generator:{:?}",
            packetgen.as_os_str().to_str().unwrap()
        );
    }
    let in_file = gd_root.join("hci/hci_packets.pdl");
    let out_file = File::create(out_dir.join("hci_packets.rs")).unwrap();

    for i in 0..input_files.len() {
        println!("cargo:rerun-if-changed={}", input_files[i].display());
        let output = Command::new(packetgen.as_os_str().to_str().unwrap())
            .arg("--source_root=".to_owned() + gd_root.as_os_str().to_str().unwrap())
            .arg("--out=".to_owned() + out_dir.as_os_str().to_str().unwrap())
            .arg("--include=bt/gd")
            .arg("--rust")
            .arg(input_files[i].as_os_str().to_str().unwrap())
    // Expect pdlc to be in the PATH
    println!("cargo:rerun-if-changed={}", in_file.display());
    let output = Command::new("pdlc")
        .arg("--output-format")
        .arg("rust")
        .arg(in_file)
        .stdout(Stdio::from(out_file))
        .output()
        .unwrap();

    println!(
            "Status: {}, stdout: {}, stderr: {}",
        "Status: {}, stderr: {}",
        output.status,
            String::from_utf8_lossy(output.stdout.as_slice()),
        String::from_utf8_lossy(output.stderr.as_slice())
    );

        // File will be at ${OUT_DIR}/../../${input_files[i].strip('.pdl')}.rs
        std::fs::rename(
            outputted[i].as_os_str().to_str().unwrap(),
            out_dir.join(outputted[i].file_name().unwrap()).as_os_str().to_str().unwrap(),
        )
        .unwrap();
    }
}
+617 −4

File changed.

Preview size limit exceeded, changes collapsed.

+0 −108
Original line number Diff line number Diff line
//! reimport of generated packets (to go away once rust_genrule exists)

#![allow(clippy::all)]
#![allow(unused)]
#![allow(missing_docs)]

use std::convert::TryFrom;
use std::fmt;

pub mod test_packets {

    // Custom boolean type
    #[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Debug)]
    pub struct Boolean {
        pub value: u8,
    }

    impl fmt::Display for Boolean {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "{:02x}", self.value)
        }
    }

    #[derive(Debug, Clone)]
    pub struct InvalidBooleanError;

    impl TryFrom<&[u8]> for Boolean {
        type Error = InvalidBooleanError;

        fn try_from(slice: &[u8]) -> std::result::Result<Self, Self::Error> {
            if slice.len() != 1 || slice[0] > 1 {
                Err(InvalidBooleanError)
            } else {
                Ok(Boolean { value: slice[0] })
            }
        }
    }

    impl From<Boolean> for [u8; 1] {
        fn from(b: Boolean) -> [u8; 1] {
            [b.value]
        }
    }

    include!(concat!(env!("OUT_DIR"), "/rust_test_packets.rs"));
}

#[cfg(test)]
pub mod test {
    use crate::test_packets::*;

    #[test]
    fn test_invalid_enum_field_value() {
        // 0x0 is not a recognized Enum value.
        let input = [0x0];
        let res = TestEnumPacket::parse(&input);
        assert!(res.is_err());
    }

    #[test]
    fn test_invalid_custom_field_value() {
        // 0x2 is not a recognized Boolean value.
        let input = [0x2];
        let res = TestCustomFieldPacket::parse(&input);
        assert!(res.is_err());
    }

    #[test]
    fn test_invalid_array_size() {
        // Size 4, have 2.
        let input = [0x4, 0x0, 0x0];
        let res = TestArraySizePacket::parse(&input);
        assert!(res.is_err());
    }

    #[test]
    fn test_invalid_array_count() {
        // Count 2, have 1.
        let input = [0x2, 0x0, 0x0];
        let res = TestArrayCountPacket::parse(&input);
        assert!(res.is_err());
    }

    #[test]
    fn test_invalid_payload_size() {
        // Size 2, have 1.
        let input = [0x2, 0x0];
        let res = TestPayloadSizePacket::parse(&input);
        assert!(res.is_err());
    }

    #[test]
    fn test_invalid_body_size() {
        // Size 2, have 1.
        // Body does not have a concrete representation,
        // the size and payload are both discarded.
        let input = [0x2, 0x0];
        let res = TestBodySizePacket::parse(&input);
        assert!(res.is_ok());
    }

    #[test]
    fn test_invalid_grand_child_three_five_size() {
        let input = [0x1, 0x4, 0x3, 0x4, 0x3, 0x0, 0x2 /*, 0x5*/];
        let res = GrandParentPacket::parse(&input);
        assert!(res.is_err());
    }
}
Loading