From 3b6dad2084e939d076eb5b0204e8d188d494c66d Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 5 Jan 2021 14:17:04 +1100 Subject: [PATCH] Allow SecretKey to be deserialized from an owned string Deserializing directly into a borrowed string only covers the edge case in which one passes a borrowed string to the deserializer. If we are given an owned version, the deserialization fails with: invalid type: string "foobar", expected a borrowed string' --- src/macros.rs | 66 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index a8258be5c..28ef53c68 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -65,9 +65,23 @@ macro_rules! serde_impl( use ::serde::de::Error; use core::str::FromStr; + struct Visitor; + + impl<'de> ::serde::de::Visitor<'de> for Visitor { + type Value = $t; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(formatter, "a string") + } + + fn visit_str(self, v: &str) -> Result where + E: Error, { + $t::from_str(v).map_err(E::custom) + } + } + if d.is_human_readable() { - let sl: &str = ::serde::Deserialize::deserialize(d)?; - $t::from_str(sl).map_err(D::Error::custom) + d.deserialize_str(Visitor) } else { let sl: &[u8] = ::serde::Deserialize::deserialize(d)?; if sl.len() != $len { @@ -161,3 +175,51 @@ macro_rules! serde_impl_from_slice { macro_rules! serde_impl_from_slice( ($t:ident) => () ); + +#[cfg(all(test, feature = "serde"))] +mod tests { + use std::{str::FromStr, fmt, io}; + use serde_test::*; + + #[derive(Debug)] + struct Foo([u8; 6]); + serde_impl!(Foo, 6); + impl_array_newtype!(Foo, u8, 6); + + impl FromStr for Foo { + type Err = io::Error; // some dummy value to satisfy the compiler + + fn from_str(s: &str) -> Result { + let x = s.bytes().take(6).collect::>(); + + Ok(Foo([x[0], x[1], x[2], x[3], x[4], x[5]])) + } + } + + impl fmt::Display for Foo { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + unimplemented!() + } + } + + + #[test] + fn deserialize_from_borrowed_string() { + let value = Foo(*b"foobar"); + let tokens = [ + Token::BorrowedStr("foobar") + ]; + + assert_de_tokens(&value.readable(), &tokens) + } + + #[test] + fn deserialize_from_owned_string() { + let value = Foo(*b"foobar"); + let tokens = [ + Token::String("foobar") + ]; + + assert_de_tokens(&value.readable(), &tokens) + } +}