//! # The Swift↔Rust hardware wire contract (v5) //! //! The macOS IOKit collector is a sibling Swift package (`macos-collector/`) //! that speaks this crate's wire format. Swift and Rust are two independent //! implementations of the same byte layout, so the contract needs a test that //! pins the *exact bytes* both sides must agree on — not just a Rust round trip. //! //! This test hand-encodes, per the documented frame layout //! (`signal_schema::wire`), the canonical hardware frame the Swift collector //! emits, and asserts: //! 1. `wire::decode` parses those exact bytes into the expected [`Signal`] //! (this is signald's parse path — signald decodes hardware frames with the //! same function), and //! 2. `wire::encode` reproduces those exact bytes from the [`Signal`]. //! //! The identical byte array is asserted on the Swift side in //! `macos-collector/Tests/CollectorCoreTests/WireTests.swift`, so both languages //! independently commit to the same wire. Cross-*process* execution of the Swift //! binary is not required to prove agreement — the shared literal is the proof. //! //! Privacy note: a hardware frame carries the same `f64`-only payload as every //! other signal. `CpuLoad` is untagged (`tag_present == 0`); there is no content //! field. The privacy invariant is intact for hardware signals by construction. use signal_schema::{wire, Signal, SignalName, Source, Value, SCHEMA_VERSION}; /// The canonical hardware test vector, shared verbatim with the Swift side. /// /// Signal: schema_version=5, ts=0, source=Hardware(3), name=CpuLoad(10), /// value=0.5 (`f64`), tag=None. /// /// Frame bytes (little-endian throughout): /// ```text /// 15 00 00 00 body_len = 21 (u32) /// 05 00 schema_version = 5 (u16) /// 00 00 00 00 00 00 00 00 ts = 0 (u64) /// 03 source = Hardware (u8) /// 0A name = CpuLoad = 10 (u8) /// 00 00 00 00 00 00 E0 3F value = 0.5 (f64) /// 00 tag_present = 0 (u8) /// ``` const CANONICAL_FRAME: [u8; 25] = [ 0x15, 0x00, 0x00, 0x00, // body_len = 21 0x05, 0x00, // schema_version = 5 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ts = 0 0x03, // source = Hardware 0x0A, // name = CpuLoad (10) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x3F, // value = 0.5 0x00, // tag_present = 0 ]; fn canonical_signal() -> Signal { Signal { schema_version: SCHEMA_VERSION, ts: 0, source: Source::Hardware, name: SignalName::CpuLoad, value: Value(0.5), tag: None, } } /// signald parses a hardware frame produced to the documented byte layout. #[test] fn signald_decodes_the_swift_hardware_frame() { let decoded = wire::decode(&CANONICAL_FRAME).expect("signald must decode the hardware frame"); assert_eq!(decoded, canonical_signal()); // The privacy boundary holds for hardware signals too: f64 payload, no tag. assert_eq!(decoded.value, Value(0.5)); assert!(decoded.tag.is_none(), "aggregate hardware scalar carries no tag"); } /// The Rust encoder reproduces the exact bytes the Swift encoder commits to. #[test] fn rust_encoder_matches_the_shared_byte_vector() { assert_eq!(wire::encode(&canonical_signal()), CANONICAL_FRAME.to_vec()); } /// The aggregate CPU metric is untagged and frozen at discriminant 10. #[test] fn cpu_load_is_untagged_and_stable() { assert_eq!(SignalName::CpuLoad.to_u8(), 10); assert_eq!(SignalName::from_u8(10), Some(SignalName::CpuLoad)); assert!(!SignalName::CpuLoad.allows_tag(), "aggregate CPU load is never tagged"); }