1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use serde::de::{Error, Visitor};
3
4type StrBuf = str_buf::StrBuf<36>;
5
6use core::fmt;
7
8#[derive(Debug, PartialEq, Clone, Hash, Eq)]
10pub enum Id {
11 Num(u64),
13 Str(StrBuf),
15}
16
17impl Serialize for Id {
18 #[inline]
19 fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
20 match self {
21 Id::Num(id) => ser.serialize_u64(*id),
22 Id::Str(id) => ser.serialize_str(id.as_str()),
23 }
24 }
25}
26
27impl<'a> Deserialize<'a> for Id {
28 #[inline]
29 fn deserialize<D: Deserializer<'a>>(des: D) -> Result<Self, D::Error> {
30 #[cfg(all(feature = "id-number-only", feature = "id-str-only"))]
31 compile_error!("You MUST select either 'id-number-only' or 'id-str-only' feature");
32
33 #[cfg(not(any(feature = "id-number-only", feature = "id-str-only")))]
34 {
35 des.deserialize_any(IdVisitor)
36 }
37 #[cfg(feature = "id-str-only")]
38 {
39 des.deserialize_str(IdVisitor)
40 }
41 #[cfg(feature = "id-number-only")]
42 {
43 des.deserialize_u64(IdVisitor)
44 }
45 }
46}
47
48struct IdVisitor;
49
50impl<'a> Visitor<'a> for IdVisitor {
51 type Value = Id;
52
53 #[inline]
54 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
55 formatter.write_str("Identifier must be either unsigned integer or 36 character long string")
56 }
57
58 #[inline]
59 fn visit_u64<E: Error>(self, id: u64) -> Result<Self::Value, E> {
60 Ok(Id::Num(id))
61 }
62
63 #[inline]
64 fn visit_i64<E: Error>(self, id: i64) -> Result<Self::Value, E> {
65 if id < 0 {
66 Err(Error::invalid_value(serde::de::Unexpected::Signed(id), &self))
67 } else {
68 Ok(Id::Num(id as u64))
69 }
70 }
71
72 #[inline]
73 fn visit_f64<E: Error>(self, id: f64) -> Result<Self::Value, E> {
74 Err(Error::invalid_value(serde::de::Unexpected::Float(id), &self))
75 }
76
77 #[inline]
78 fn visit_str<E: Error>(self, id: &str) -> Result<Self::Value, E> {
79 if id.len() > StrBuf::capacity() {
80 Err(Error::invalid_length(id.len(), &self))
81 } else {
82 let mut res = StrBuf::new();
83 unsafe {
84 res.push_str_unchecked(id);
85 }
86 Ok(Id::Str(res))
87 }
88 }
89}