Skip to content

Commit

Permalink
Deserializing BDAddr from non-borrowed string without clone (#415)
Browse files Browse the repository at this point in the history
* Deserializing `BDAddr` from non-borrowed string without clone (70ee65c)

* remove import `Cow`
  • Loading branch information
ekuinox authored Dec 19, 2024
1 parent 5f64e11 commit 6c3de80
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 13 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ rand = "0.8.5"
pretty_env_logger = "0.5.0"
tokio = { version = "1.40.0", features = ["macros", "rt", "rt-multi-thread"] }
serde_json = "1.0.128"
toml = "0.8.19"
66 changes: 53 additions & 13 deletions src/api/bdaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ impl BDAddr {
/// Different de-/serialization formats for [`BDAddr`].
#[cfg(feature = "serde")]
pub mod serde {
use std::borrow::Cow;
use std::fmt::{self, Write as _};

use serde::{
Expand Down Expand Up @@ -266,12 +265,11 @@ pub mod serde {
where
D: Deserializer<'de>,
{
let buf = d.deserialize_str(ColonDelimVisitor)?;
BDAddr::from_str_delim(&buf).map_err(D::Error::custom)
d.deserialize_str(ColonDelimVisitor)
}

impl<'de> Visitor<'de> for ColonDelimVisitor {
type Value = Cow<'de, str>;
type Value = BDAddr;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
Expand All @@ -284,21 +282,21 @@ pub mod serde {
where
E: DeError,
{
Ok(v.to_string().into())
BDAddr::from_str_delim(v).map_err(E::custom)
}

fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: DeError,
{
Ok(v.into())
BDAddr::from_str_delim(v).map_err(E::custom)
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: DeError,
{
Ok(v.into())
BDAddr::from_str_delim(&v).map_err(E::custom)
}
}
}
Expand Down Expand Up @@ -343,12 +341,11 @@ pub mod serde {
where
D: Deserializer<'de>,
{
let buf = d.deserialize_str(NoDelimVisitor)?;
BDAddr::from_str_no_delim(&buf).map_err(D::Error::custom)
d.deserialize_str(NoDelimVisitor)
}

impl<'de> Visitor<'de> for NoDelimVisitor {
type Value = Cow<'de, str>;
type Value = BDAddr;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(
Expand All @@ -361,21 +358,21 @@ pub mod serde {
where
E: DeError,
{
Ok(v.to_string().into())
BDAddr::from_str_no_delim(v).map_err(E::custom)
}

fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
where
E: DeError,
{
Ok(v.into())
BDAddr::from_str_no_delim(v).map_err(E::custom)
}

fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: DeError,
{
Ok(v.into())
BDAddr::from_str_no_delim(&v).map_err(E::custom)
}
}
}
Expand Down Expand Up @@ -481,4 +478,47 @@ mod tests {
let addr_back: BDAddr = addr_as_hex.try_into().unwrap();
assert_eq!(ADDR, addr_back);
}

#[cfg(feature = "serde")]
#[test]
fn deserialize_toml_delim_bdaddr_with_struct() {
use serde_cr::Deserialize;

#[derive(Deserialize, PartialEq, Copy, Clone, Debug)]
#[serde(crate = "serde_cr")]
struct Data {
addr: BDAddr,
}

let data = Data {
addr: BDAddr::from([0xff, 0x00, 0xff, 0x00, 0xff, 0x00]),
};

assert_eq!(toml::from_str(r#"addr = "ff:00:ff:00:ff:00""#), Ok(data));
assert!(
matches!(toml::from_str::<Data>(r"addr = 0"), Err(e) if e.message().contains("A colon seperated Bluetooth address, like `00:11:22:33:44:55`"))
);
}

#[cfg(feature = "serde")]
#[test]
fn deserialize_toml_nodelim_bdaddr_with_struct() {
use serde_cr::Deserialize;

#[derive(Deserialize, PartialEq, Copy, Clone, Debug)]
#[serde(crate = "serde_cr")]
struct Data {
#[serde(with = "crate::serde::bdaddr::no_delim")]
addr: BDAddr,
}

let data = Data {
addr: BDAddr::from([0xff, 0x00, 0xff, 0x00, 0xff, 0x00]),
};

assert_eq!(toml::from_str(r#"addr = "ff00ff00ff00""#), Ok(data));
assert!(
matches!(toml::from_str::<Data>(r"addr = 0"), Err(e) if e.message().contains("A Bluetooth address without any delimiters, like `001122334455`")),
);
}
}

0 comments on commit 6c3de80

Please sign in to comment.