use serde::de::{Deserialize, Deserializer}; use serde::ser::{Serialize, Serializer}; use serde_cbor::tags::Tagged; use serde_cbor::Value; use serde_derive::{Deserialize, Serialize}; use std::error::Error; /// https://tools.ietf.org/html/rfc7049#section-2.4.1 #[derive(Debug, PartialEq)] struct Date(String); impl Serialize for Date { fn serialize(&self, s: S) -> Result { Tagged::new(Some(0), &self.0).serialize(s) } } impl<'de> Deserialize<'de> for Date { fn deserialize>(deserializer: D) -> Result { let tagged = Tagged::::deserialize(deserializer)?; match tagged.tag { Some(0) | None => Ok(Date(tagged.value)), Some(_) => Err(serde::de::Error::custom("unexpected tag")), } } } /// https://tools.ietf.org/html/rfc7049#section-2.4.4.3 #[derive(Debug, PartialEq)] struct Uri(String); impl Serialize for Uri { fn serialize(&self, s: S) -> Result { Tagged::new(Some(32), &self.0).serialize(s) } } impl<'de> Deserialize<'de> for Uri { fn deserialize>(deserializer: D) -> Result { let tagged = Tagged::::deserialize(deserializer)?; match tagged.tag { // allow deserialization even if there is no tag. Allows roundtrip via other formats such as json Some(0) | None => Ok(Uri(tagged.value)), Some(_) => Err(serde::de::Error::custom("unexpected tag")), } } } #[derive(Debug, Serialize, Deserialize, PartialEq)] struct Bookmark { title: String, link: Uri, created: Date, } fn main() -> Result<(), Box> { let bookmark = Bookmark { title: "The Example Domain".into(), link: Uri("http://example.org/".into()), created: Date("2003-12-13T18:30:02Z".into()), }; // serialize the struct to bytes let bytes1 = serde_cbor::to_vec(&bookmark)?; // deserialize to a serde_cbor::Value let value1: Value = serde_cbor::from_slice(&bytes1)?; println!("{:?}", value1); // serialize the value to bytes let bytes2 = serde_cbor::to_vec(&value1)?; // deserialize to a serde_cbor::Value let value2: Value = serde_cbor::from_slice(&bytes2)?; println!("{:?}", value2); // deserialize to a Bookmark let result: Bookmark = serde_cbor::from_slice(&bytes2)?; // check that the roundtrip was successful assert_eq!(value1, value2); assert_eq!(bookmark, result); // check that going via a format that does not support tags does work // let json = serde_json::to_vec(&bookmark)?; // let result: Bookmark = serde_json::from_slice(&json)?; // assert_eq!(bookmark, result); Ok(()) }