tinc/private/
identifier.rs1use 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}