tinc/private/
identifier.rs

1use std::borrow::Cow;
2use std::str::FromStr;
3
4pub trait Identifier: FromStr + Copy + Eq + PartialEq + Ord + std::hash::Hash + PartialOrd {
5    const OPTIONS: &'static [&'static str];
6
7    fn name(&self) -> &'static str;
8}
9
10pub trait IdentifierFor {
11    const NAME: &'static str;
12
13    type Identifier: Identifier;
14}
15
16pub struct IdentifierDeserializer<F>(std::marker::PhantomData<F>);
17
18impl<F> Default for IdentifierDeserializer<F> {
19    fn default() -> Self {
20        Self(std::marker::PhantomData)
21    }
22}
23
24impl<F> IdentifierDeserializer<F> {
25    pub const fn new() -> Self {
26        Self(std::marker::PhantomData)
27    }
28}
29
30impl<F: Identifier> IdentifierDeserializer<F> {
31    fn visit_owned_borrowed_or_ref<'de>(self, v: OwnedBorrowedOrRef<'de, '_>) -> IdentifiedValue<'de, F> {
32        F::from_str(v.as_ref()).map_or_else(
33            |_| IdentifiedValue::Unknown(v.into_cow()),
34            |field| IdentifiedValue::Found(field),
35        )
36    }
37}
38
39impl<'a, F: Identifier> serde::de::Visitor<'a> for IdentifierDeserializer<F> {
40    type Value = IdentifiedValue<'a, F>;
41
42    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
43    where
44        E: serde::de::Error,
45    {
46        Ok(self.visit_owned_borrowed_or_ref(OwnedBorrowedOrRef::Ref(v)))
47    }
48
49    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
50    where
51        E: serde::de::Error,
52    {
53        Ok(self.visit_owned_borrowed_or_ref(OwnedBorrowedOrRef::Owned(v)))
54    }
55
56    fn visit_borrowed_str<E>(self, v: &'a str) -> Result<Self::Value, E>
57    where
58        E: serde::de::Error,
59    {
60        Ok(self.visit_owned_borrowed_or_ref(OwnedBorrowedOrRef::Borrowed(v)))
61    }
62
63    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
64        write!(formatter, "a field name")
65    }
66}
67
68impl<'de, F> serde::de::DeserializeSeed<'de> for IdentifierDeserializer<F>
69where
70    F: Identifier,
71{
72    type Value = IdentifiedValue<'de, F>;
73
74    #[inline]
75    fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
76    where
77        D: serde::Deserializer<'de>,
78    {
79        deserializer.deserialize_identifier(self)
80    }
81}
82
83pub enum IdentifiedValue<'a, F> {
84    Found(F),
85    Unknown(Cow<'a, str>),
86}
87
88enum OwnedBorrowedOrRef<'de, 'a> {
89    Owned(String),
90    Borrowed(&'de str),
91    Ref(&'a str),
92}
93
94impl AsRef<str> for OwnedBorrowedOrRef<'_, '_> {
95    fn as_ref(&self) -> &str {
96        match self {
97            Self::Owned(s) => s.as_str(),
98            Self::Borrowed(s) => s,
99            Self::Ref(s) => s,
100        }
101    }
102}
103
104impl<'de> OwnedBorrowedOrRef<'de, '_> {
105    fn into_cow(self) -> Cow<'de, str> {
106        match self {
107            Self::Owned(s) => Cow::Owned(s),
108            Self::Borrowed(s) => Cow::Borrowed(s),
109            Self::Ref(s) => Cow::Owned(s.to_string()),
110        }
111    }
112}
113
114impl<T: IdentifierFor> IdentifierFor for Option<T> {
115    type Identifier = T::Identifier;
116
117    const NAME: &'static str = T::NAME;
118}
119
120impl<T: IdentifierFor> IdentifierFor for Box<T> {
121    type Identifier = T::Identifier;
122
123    const NAME: &'static str = T::NAME;
124}