From 13ac3f947f089c037873b9bddf36245c1d663b9d Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 25 Mar 2024 20:47:47 +0000 Subject: [PATCH 1/3] Derive Hash for Code. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6ae4e10..10d0ed0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ pub enum Error { } /// A decoded RF button code. -#[derive(Clone, Eq, PartialEq)] +#[derive(Clone, Eq, Hash, PartialEq)] pub struct Code { /// The decoded value. pub value: u32, From f3ab99016d69120d825942f3d8c80c0b84f6d9bc Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 25 Mar 2024 20:48:05 +0000 Subject: [PATCH 2/3] Implement serde traits for Code. --- CHANGELOG.md | 8 ++++++ Cargo.toml | 6 ++++ src/lib.rs | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e990334..5560cf7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +### New features + +- Implemented `Hash` for `Code`. +- Implemented `serde::Serialize` and `serde::Deserialize` for `Code`, behind new `serde` feature + flag. + ## 0.1.0 Initial release. diff --git a/Cargo.toml b/Cargo.toml index 7ae5511..caa7070 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ categories = ["hardware-support", "parser-implementations"] [dependencies] thiserror = "1.0.30" +serde = { version = "1.0.197", optional = true } [dev-dependencies] cc1101 = { version = "0.1.3", features = ["std"] } @@ -21,3 +22,8 @@ eyre = "0.6.9" log = "0.4.20" pretty_env_logger = "0.5.0" rppal = { version = "0.17.1", features = ["hal"] } +serde_test = "1.0.176" + +[features] +default = ["serde"] +serde = ["dep:serde"] diff --git a/src/lib.rs b/src/lib.rs index 10d0ed0..d959379 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,44 @@ impl Debug for Code { } } +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for Code { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + if s.len() > 8 { + return Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Str(&s), + &"no more than 8 characters", + )); + } + let value = + u32::from_str_radix(&s, 16).map_err(|e| serde::de::Error::custom(e.to_string()))?; + Ok(Self { + value, + length: s.len() as u8 * 4, + }) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for Code { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + if self.length % 4 != 0 { + return Err(serde::ser::Error::custom( + "Only codes with length a multiple of 4 can be serialized.", + )); + } + let s = format!("{:01$x}", self.value, usize::from(self.length) / 4); + serializer.serialize_str(&s) + } +} + /// Given a sequence of pulse durations in microseconds (starting with a high pulse), try to decode /// a button code. pub fn decode(pulses: &[u16]) -> Result { @@ -153,4 +191,46 @@ mod tests { }) ); } + + #[cfg(feature = "serde")] + #[test] + fn serde_code() { + use serde_test::{assert_tokens, Token}; + + assert_tokens( + &Code { + value: 0, + length: 12, + }, + &[Token::Str("000")], + ); + assert_tokens( + &Code { + value: 0xf, + length: 4, + }, + &[Token::Str("f")], + ); + assert_tokens( + &Code { + value: 0x123456, + length: 24, + }, + &[Token::Str("123456")], + ); + assert_tokens( + &Code { + value: 0xabcdef, + length: 24, + }, + &[Token::Str("abcdef")], + ); + assert_tokens( + &Code { + value: 0xff112233, + length: 32, + }, + &[Token::Str("ff112233")], + ); + } } From a4979344645630c6873d544d3e597239bb5810b1 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Mon, 25 Mar 2024 20:51:27 +0000 Subject: [PATCH 3/3] Build and test with no features too. --- .github/workflows/rust.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 96c81c8..21a364c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -14,10 +14,14 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Build + - name: Build with all features run: cargo build --all-features - - name: Run tests + - name: Run tests with all features run: cargo test --all-features + - name: Build with no features + run: cargo build --no-default-features + - name: Run tests with no features + run: cargo test --no-default-features - name: Run clippy uses: actions-rs/clippy-check@v1 with: