prost_helper/
id.rs

1use bytes::Bytes;
2use serde::{de, ser, ser::SerializeSeq, Deserialize, Deserializer, Serializer};
3use uuid7::Uuid;
4
5pub fn serialize_id<S, T>(bytes: T, serializer: S) -> Result<S::Ok, S::Error>
6where
7    S: Serializer,
8    T: AsRef<[u8]>,
9{
10    let bytes = bytes.as_ref();
11    if bytes.is_empty() {
12        return serializer.serialize_str("");
13    }
14    if bytes.len() != 16 {
15        return Err(ser::Error::custom("invalid id length"));
16    }
17    let id = u128::from_be_bytes(bytes.try_into().map_err(ser::Error::custom)?);
18    serializer.collect_str(&Uuid::from(id).to_string())
19}
20
21pub fn deserialize_id_vec<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
22where
23    D: Deserializer<'de>,
24{
25    let s = String::deserialize(deserializer)?;
26    if s.is_empty() {
27        return Ok(vec![]);
28    }
29    let id: Uuid = s.parse().map_err(de::Error::custom)?;
30    Ok(id.as_bytes().to_vec())
31}
32
33pub fn deserialize_id_bytes<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
34where
35    D: Deserializer<'de>,
36{
37    deserialize_id_vec(deserializer).map(Bytes::from)
38}
39
40pub fn serialize_repeat_id<S, T>(data: &[T], serializer: S) -> Result<S::Ok, S::Error>
41where
42    S: Serializer,
43    T: AsRef<[u8]>,
44{
45    let mut seq = serializer.serialize_seq(Some(data.len()))?;
46    for item in data {
47        let bytes = item.as_ref();
48        if bytes.is_empty() {
49            seq.serialize_element("")?;
50            continue;
51        }
52        if bytes.len() != 16 {
53            return Err(ser::Error::custom("invalid id length"));
54        }
55        let id = u128::from_be_bytes(item.as_ref().try_into().map_err(ser::Error::custom)?);
56        let e = Uuid::from(id).to_string();
57        seq.serialize_element(&e)?;
58    }
59    seq.end()
60}
61
62pub fn deserialize_repeat_id_vec<'de, D>(deserializer: D) -> Result<Vec<Vec<u8>>, D::Error>
63where
64    D: Deserializer<'de>,
65{
66    struct Visitor;
67
68    impl<'de> ::serde::de::Visitor<'de> for Visitor {
69        type Value = Vec<Vec<u8>>;
70
71        fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
72            write!(f, "a sequence of uuid7 ASCII text")
73        }
74
75        fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
76        where
77            S: de::SeqAccess<'de>,
78        {
79            let mut data: Vec<Vec<u8>> = Vec::with_capacity(seq.size_hint().unwrap_or(0));
80            while let Some(s) = seq.next_element::<String>()? {
81                if s.is_empty() {
82                    data.push(vec![]);
83                    continue;
84                }
85                let id: Uuid = s.parse().map_err(de::Error::custom)?;
86                data.push(id.as_bytes().to_vec());
87            }
88            Ok(data)
89        }
90    }
91
92    deserializer.deserialize_seq(Visitor)
93}
94
95pub fn deserialize_repeat_id_bytes<'de, D>(deserializer: D) -> Result<Vec<Bytes>, D::Error>
96where
97    D: Deserializer<'de>,
98{
99    struct Visitor;
100
101    impl<'de> ::serde::de::Visitor<'de> for Visitor {
102        type Value = Vec<Bytes>;
103
104        fn expecting(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
105            write!(f, "a sequence of uuid7 ASCII text")
106        }
107
108        fn visit_seq<S>(self, mut seq: S) -> Result<Self::Value, S::Error>
109        where
110            S: de::SeqAccess<'de>,
111        {
112            let mut data: Vec<Bytes> = Vec::with_capacity(seq.size_hint().unwrap_or(0));
113            while let Some(s) = seq.next_element::<String>()? {
114                if s.is_empty() {
115                    data.push(Bytes::new());
116                    continue;
117                }
118                let id: Uuid = s.parse().map_err(de::Error::custom)?;
119                data.push(Bytes::from(id.as_bytes().to_vec()));
120            }
121            Ok(data)
122        }
123    }
124
125    deserializer.deserialize_seq(Visitor)
126}
127
128#[cfg(all(feature = "id", feature = "json"))]
129#[cfg(test)]
130mod tests {
131    use std::str::FromStr;
132
133    use super::*;
134    use prost::{Message, Oneof};
135    use serde::{Deserialize, Serialize};
136
137    #[derive(serde::Serialize, serde::Deserialize)]
138    #[serde(default)]
139    #[derive(Clone, PartialEq, Eq, ::prost::Message)]
140    pub struct Hello {
141        #[prost(string, tag = "1")]
142        pub msg: String,
143        #[serde(
144            serialize_with = "serialize_id",
145            deserialize_with = "deserialize_id_vec"
146        )]
147        #[prost(bytes, tag = "2")]
148        pub value_vec: ::prost::alloc::vec::Vec<u8>,
149        #[serde(
150            serialize_with = "serialize_repeat_id",
151            deserialize_with = "deserialize_repeat_id_vec"
152        )]
153        #[prost(bytes = "vec", repeated, tag = "3")]
154        pub list_vec: Vec<Vec<u8>>,
155        #[serde(
156            serialize_with = "serialize_id",
157            deserialize_with = "deserialize_id_bytes"
158        )]
159        #[prost(bytes, tag = "4")]
160        pub value_bytes: ::prost::bytes::Bytes,
161        #[serde(
162            serialize_with = "serialize_repeat_id",
163            deserialize_with = "deserialize_repeat_id_bytes"
164        )]
165        #[prost(bytes = "bytes", repeated, tag = "5")]
166        pub list_bytes: ::prost::alloc::vec::Vec<::prost::bytes::Bytes>,
167    }
168
169    #[derive(serde::Serialize, serde::Deserialize)]
170    #[serde(default)]
171    #[derive(Clone, PartialEq, Eq, Message)]
172    pub struct ObjectId {
173        /// the value of the id
174        #[prost(oneof = "Data", tags = "2, 3")]
175        pub data: ::core::option::Option<Data>,
176    }
177
178    #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Oneof)]
179    pub enum Data {
180        #[prost(string, tag = "2")]
181        Result(String),
182        #[serde(
183            serialize_with = "serialize_id",
184            deserialize_with = "deserialize_id_vec"
185        )]
186        #[prost(bytes, tag = "3")]
187        Value(Vec<u8>),
188    }
189
190    #[test]
191    fn vec_u8_encoded_with_uuid7() {
192        let hello = Hello {
193            msg: "world".to_owned(),
194            value_vec: uuid_vec(),
195            ..Default::default()
196        };
197        let s = serde_json::to_string(&hello).unwrap();
198        assert_eq!(
199            s,
200            r#"{"msg":"world","value_vec":"018c8afb-43d7-7f73-be38-95ed30027670","list_vec":[],"value_bytes":"","list_bytes":[]}"#
201        );
202    }
203
204    #[test]
205    fn vec_u8_in_enum_encoded_with_uuid7() {
206        let data = ObjectId {
207            data: Some(Data::Value(uuid_vec())),
208        };
209        let s = serde_json::to_string(&data).unwrap();
210        assert_eq!(
211            s,
212            r#"{"data":{"Value":"018c8afb-43d7-7f73-be38-95ed30027670"}}"#
213        );
214    }
215
216    #[test]
217    fn repeat_vec_u8_encoded_with_uuid7() {
218        let hello = Hello {
219            msg: "world".to_owned(),
220            list_vec: vec![uuid_vec(), vec![]],
221            ..Default::default()
222        };
223        let s = serde_json::to_string(&hello).unwrap();
224        assert_eq!(
225            s,
226            r#"{"msg":"world","value_vec":"","list_vec":["018c8afb-43d7-7f73-be38-95ed30027670",""],"value_bytes":"","list_bytes":[]}"#
227        );
228    }
229
230    #[test]
231    fn bytes_encoded_with_uuid7() {
232        let hello = Hello {
233            msg: "world".to_owned(),
234            value_bytes: uuid_vec().into(),
235            ..Default::default()
236        };
237        let s = serde_json::to_string(&hello).unwrap();
238        assert_eq!(
239            s,
240            r#"{"msg":"world","value_vec":"","list_vec":[],"value_bytes":"018c8afb-43d7-7f73-be38-95ed30027670","list_bytes":[]}"#
241        );
242        let data = serde_json::from_str::<Hello>(&s).unwrap();
243        assert_eq!(data, hello);
244    }
245
246    #[test]
247    fn repeat_bytes_encoded_with_uuid7() {
248        let hello = Hello {
249            msg: "world".to_owned(),
250            list_bytes: vec![uuid_vec().into(), Bytes::new()],
251            ..Default::default()
252        };
253        let s = serde_json::to_string(&hello).unwrap();
254        assert_eq!(
255            s,
256            r#"{"msg":"world","value_vec":"","list_vec":[],"value_bytes":"","list_bytes":["018c8afb-43d7-7f73-be38-95ed30027670",""]}"#
257        );
258    }
259
260    fn uuid() -> &'static str {
261        "018c8afb-43d7-7f73-be38-95ed30027670"
262    }
263
264    fn uuid_vec() -> Vec<u8> {
265        Uuid::from_str(uuid()).unwrap().as_bytes().to_vec()
266    }
267}