Skip to content

Commit 378c089

Browse files
committed
Allow using postcard without serde derive
1 parent d036248 commit 378c089

2 files changed

Lines changed: 183 additions & 4 deletions

File tree

source/postcard/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ optional = true
3333
[dependencies.serde]
3434
version = "1.0.100"
3535
default-features = false
36-
features = ["derive"]
3736

3837
[dependencies.cobs]
3938
version = "0.3.0"
@@ -67,6 +66,11 @@ version = "0.33.0"
6766
optional = true
6867
default-features = false
6968

69+
[dev-dependencies.serde]
70+
version = "1.0.100"
71+
default-features = false
72+
features = ["derive"]
73+
7074
[features]
7175
default = ["heapless-cas"]
7276

source/postcard/src/error.rs

Lines changed: 178 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use core::fmt::{Display, Formatter};
2-
use serde::{Deserialize, Serialize};
1+
use core::fmt::{self, Display, Formatter};
2+
use serde::de::{
3+
Deserialize, DeserializeSeed, Deserializer, EnumAccess, Unexpected, VariantAccess as _, Visitor,
4+
};
5+
use serde::ser::{Serialize, Serializer};
36

47
/// This is the error type used by Postcard
5-
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
8+
#[derive(Clone, Debug, Eq, PartialEq)]
69
#[cfg_attr(feature = "use-defmt", derive(defmt::Format))]
710
#[non_exhaustive]
811
pub enum Error {
@@ -40,6 +43,27 @@ pub enum Error {
4043
CollectStrError,
4144
}
4245

46+
/// Names used for the serialized representation of `Error` in human-readable
47+
/// formats.
48+
const VARIANT_NAMES: [&str; 16] = [
49+
"WontImplement",
50+
"NotYetImplemented",
51+
"SerializeBufferFull",
52+
"SerializeSeqLengthUnknown",
53+
"DeserializeUnexpectedEnd",
54+
"DeserializeBadVarint",
55+
"DeserializeBadBool",
56+
"DeserializeBadChar",
57+
"DeserializeBadUtf8",
58+
"DeserializeBadOption",
59+
"DeserializeBadEnum",
60+
"DeserializeBadEncoding",
61+
"DeserializeBadCrc",
62+
"SerdeSerCustom",
63+
"SerdeDeCustom",
64+
"CollectStrError",
65+
];
66+
4367
impl Display for Error {
4468
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
4569
use Error::*;
@@ -94,3 +118,154 @@ impl serde::de::Error for Error {
94118
}
95119

96120
impl serde::ser::StdError for Error {}
121+
122+
impl Serialize for Error {
123+
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
124+
where
125+
S: Serializer,
126+
{
127+
serializer.serialize_unit_variant(
128+
"Error",
129+
self.clone() as u32,
130+
VARIANT_NAMES[self.clone() as usize],
131+
)
132+
}
133+
}
134+
135+
impl<'de> Deserialize<'de> for Error {
136+
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
137+
where
138+
D: Deserializer<'de>,
139+
{
140+
struct ErrorVisitor;
141+
142+
impl<'de> DeserializeSeed<'de> for ErrorVisitor {
143+
type Value = Error;
144+
145+
fn deserialize<D>(self, deserializer: D) -> core::result::Result<Self::Value, D::Error>
146+
where
147+
D: Deserializer<'de>,
148+
{
149+
deserializer.deserialize_identifier(self)
150+
}
151+
}
152+
153+
impl<'de> Visitor<'de> for ErrorVisitor {
154+
type Value = Error;
155+
156+
fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
157+
formatter.write_str("postcard Error")
158+
}
159+
160+
fn visit_enum<D>(self, data: D) -> core::result::Result<Self::Value, D::Error>
161+
where
162+
D: EnumAccess<'de>,
163+
{
164+
let (variant, contents) = data.variant_seed(self)?;
165+
contents.unit_variant()?;
166+
Ok(variant)
167+
}
168+
169+
fn visit_u64<E>(self, value: u64) -> core::result::Result<Self::Value, E>
170+
where
171+
E: serde::de::Error,
172+
{
173+
match value {
174+
0 => Ok(Error::WontImplement),
175+
1 => Ok(Error::NotYetImplemented),
176+
2 => Ok(Error::SerializeBufferFull),
177+
3 => Ok(Error::SerializeSeqLengthUnknown),
178+
4 => Ok(Error::DeserializeUnexpectedEnd),
179+
5 => Ok(Error::DeserializeBadVarint),
180+
6 => Ok(Error::DeserializeBadBool),
181+
7 => Ok(Error::DeserializeBadChar),
182+
8 => Ok(Error::DeserializeBadUtf8),
183+
9 => Ok(Error::DeserializeBadOption),
184+
10 => Ok(Error::DeserializeBadEnum),
185+
11 => Ok(Error::DeserializeBadEncoding),
186+
12 => Ok(Error::DeserializeBadCrc),
187+
13 => Ok(Error::SerdeSerCustom),
188+
14 => Ok(Error::SerdeDeCustom),
189+
15 => Ok(Error::CollectStrError),
190+
_ => Err(E::invalid_value(
191+
Unexpected::Unsigned(value),
192+
&"variant index 0 <= i < 16",
193+
)),
194+
}
195+
}
196+
197+
fn visit_str<E>(self, value: &str) -> core::result::Result<Self::Value, E>
198+
where
199+
E: serde::de::Error,
200+
{
201+
match value {
202+
"WontImplement" => Ok(Error::WontImplement),
203+
"NotYetImplemented" => Ok(Error::NotYetImplemented),
204+
"SerializeBufferFull" => Ok(Error::SerializeBufferFull),
205+
"SerializeSeqLengthUnknown" => Ok(Error::SerializeSeqLengthUnknown),
206+
"DeserializeUnexpectedEnd" => Ok(Error::DeserializeUnexpectedEnd),
207+
"DeserializeBadVarint" => Ok(Error::DeserializeBadVarint),
208+
"DeserializeBadBool" => Ok(Error::DeserializeBadBool),
209+
"DeserializeBadChar" => Ok(Error::DeserializeBadChar),
210+
"DeserializeBadUtf8" => Ok(Error::DeserializeBadUtf8),
211+
"DeserializeBadOption" => Ok(Error::DeserializeBadOption),
212+
"DeserializeBadEnum" => Ok(Error::DeserializeBadEnum),
213+
"DeserializeBadEncoding" => Ok(Error::DeserializeBadEncoding),
214+
"DeserializeBadCrc" => Ok(Error::DeserializeBadCrc),
215+
"SerdeSerCustom" => Ok(Error::SerdeSerCustom),
216+
"SerdeDeCustom" => Ok(Error::SerdeDeCustom),
217+
"CollectStrError" => Ok(Error::CollectStrError),
218+
_ => Err(E::unknown_variant(value, &VARIANT_NAMES)),
219+
}
220+
}
221+
}
222+
223+
deserializer.deserialize_enum("Error", &VARIANT_NAMES, ErrorVisitor)
224+
}
225+
}
226+
227+
#[cfg(test)]
228+
mod tests {
229+
use super::Error;
230+
use core::fmt::{self, Display, Formatter};
231+
use serde::{Deserialize as _, Serialize as _};
232+
233+
struct DisplayEnumUsingSerde(Error);
234+
235+
impl Display for DisplayEnumUsingSerde {
236+
fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
237+
Error::serialize(&self.0, formatter)
238+
}
239+
}
240+
241+
#[test]
242+
fn test_serde() {
243+
for i in 0.. {
244+
// Deserialize from integer to Error
245+
let de = serde::de::value::U32Deserializer::<Error>::new(i);
246+
let Ok(error) = Error::deserialize(de) else {
247+
assert_eq!(i, super::VARIANT_NAMES.len() as u32);
248+
break;
249+
};
250+
251+
// Verify integer representation matches discriminant
252+
assert_eq!(i, error.clone() as u32);
253+
254+
// Serialize from Error to integer
255+
let mut buf = [0u8; 1];
256+
crate::to_slice(&error, &mut buf).unwrap();
257+
assert_eq!(i, buf[0] as u32);
258+
259+
// Serialize from Error to string
260+
let string = DisplayEnumUsingSerde(error.clone()).to_string();
261+
262+
// Verify string representation matches derived Debug impl
263+
assert_eq!(string, format!("{error:?}"));
264+
265+
// Deserialize from string to Error
266+
let de = serde::de::value::StrDeserializer::<Error>::new(&string);
267+
let error2 = Error::deserialize(de).unwrap();
268+
assert_eq!(error, error2);
269+
}
270+
}
271+
}

0 commit comments

Comments
 (0)