Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_namex/src/id.rs

6.4 KiB, 24 runs

created by r1870400018:521, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_core::{
2 prelude::*,
3 rand::RanDef,
4};
5use oxedyne_fe2o3_jdat::{
6 prelude::*,
7};
8
9use std::{
10 collections::BTreeMap,
11 fmt,
12};
13
14
15new_type!(LocalId, u8, Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd);
16
17impl fmt::Display for LocalId {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 write!(f, "{}", self.0)
20 }
21}
22
23impl ToDat for LocalId {
24 fn to_dat(&self) -> Outcome<Dat> {
25 Ok(dat!(self.0))
26 }
27}
28
29impl FromDat for LocalId {
30 fn from_dat(dat: Dat) -> Outcome<Self> {
31 Ok(Self(try_extract_dat!(dat, U8)))
32 }
33}
34
35new_type!(NamexId, B32, Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd);
36
37impl From<B32> for NamexId {
38 fn from(b: B32) -> Self {
39 Self(b)
40 }
41}
42
43impl From<&B32> for NamexId {
44 fn from(b: &B32) -> Self {
45 Self(*b)
46 }
47}
48
49impl TryFrom<&Dat> for NamexId {
50 type Error = Error<ErrTag>;
51
52 fn try_from(dat: &Dat) -> std::result::Result<Self, Self::Error> {
53 Ok(match dat {
54 Dat::B32(a) => Self::from(a),
55 // The canonical textual form of a Namex id is standard base64, which is what
56 // `Display` emits and what callers pass to `TryFrom<&str>`.
57 Dat::Str(s) => res!(Self::try_from(s.as_str())),
58 _ => return Err(err!(
59 "Expected a daticle of kind {:?} or {:?}, received a {:?}.",
60 Kind::B32, Kind::Str, dat.kind();
61 Invalid, Input, Mismatch)),
62 })
63 }
64}
65
66impl ToDat for NamexId {
67 fn to_dat(&self) -> Outcome<Dat> {
68 Ok(Dat::B32(self.0))
69 }
70}
71
72impl FromDat for NamexId {
73 fn from_dat(dat: Dat) -> Outcome<Self> {
74 Ok(match dat {
75 Dat::B32(a) => Self::from(a),
76 Dat::Str(ref s) => res!(Self::try_from(s.as_str())),
77 _ => return Err(err!(
78 "Expected a daticle of kind {:?} or {:?}, received a {:?}.",
79 Kind::B32, Kind::Str, dat.kind();
80 Invalid, Input, Mismatch)),
81 })
82 }
83}
84
85impl TryFrom<&str> for NamexId {
86 type Error = Error<ErrTag>;
87
88 fn try_from(s: &str) -> std::result::Result<Self, Self::Error> {
89 let byts = res!(base64::decode(s));
90 let id = res!(Self::try_from(&byts[..]));
91 Ok(id)
92 }
93}
94
95impl TryFrom<&[u8]> for NamexId {
96 type Error = Error<ErrTag>;
97
98 fn try_from(b: &[u8]) -> std::result::Result<Self, Self::Error> {
99 let id = Self::from(res!(B32::from_bytes(&b[..])).0);
100 Ok(id)
101 }
102}
103
104impl RanDef for NamexId {
105 fn randef() -> Self {
106 let a = B32::randef();
107 Self(a)
108 }
109}
110
111impl fmt::Display for NamexId {
112 fn fmt (&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113 write!(f, "{}", base64::encode_config(&self[..], base64::STANDARD))
114 }
115}
116
117pub struct NameIndex {
118 s2i: BTreeMap<&'static str, NamexId>,
119 i2s: BTreeMap<NamexId, &'static str>,
120}
121
122impl NameIndex {
123
124 pub fn by_name(&self, name: &str) -> Option<&NamexId> {
125 self.s2i.get(name)
126 }
127
128 pub fn contains_name(&self, name: &str) -> bool {
129 self.s2i.contains_key(name)
130 }
131
132 pub fn names(&self) -> Vec<&'static str> {
133 self.s2i.keys().cloned().collect()
134 }
135
136 pub fn by_id(&self, id: &NamexId) -> Option<&'static str> {
137 self.i2s.get(id).copied()
138 }
139
140 pub fn contains_id(&self, id: &NamexId) -> bool {
141 self.i2s.contains_key(id)
142 }
143
144 pub fn ids(&self) -> Vec<NamexId> {
145 self.i2s.keys().cloned().collect()
146 }
147}
148
149pub trait InNamex {
150
151 /// The universal identifier, using a type so large that randomly selected ids have a very low
152 /// chance of collision.
153 fn name_id(&self) -> Outcome<NamexId>;
154
155 /// A shorter id for local use. Use 0 for "unknown" or "none".
156 fn local_id(&self) -> LocalId { LocalId::default() }
157
158 /// Allow the name to be associated with groups of other names, for specific purposes. This
159 /// returns a vector of Namex ids as base64 strings.
160 fn assoc_names_base64(
161 _gname: &'static str,
162 )
163 -> Outcome<Option<Vec<(
164 &'static str,
165 &'static str,
166 )>>>
167 {
168 Ok(None)
169 }
170
171 /// Returns binary Namex ids based on user-specified base64 ids, indexed by name.
172 fn assoc_names_index(
173 gname: &'static str,
174 )
175 -> Outcome<Option<NameIndex>>
176 {
177 Ok(match res!(Self::assoc_names_base64(gname)) {
178 Some(ids) => {
179 let mut s2i = BTreeMap::new();
180 let mut i2s = BTreeMap::new();
181 for (name, idstr) in ids {
182 let id = res!(NamexId::try_from(idstr));
183 s2i.insert(name, id.clone());
184 i2s.insert(id, name);
185 }
186 if s2i.len() == 0 {
187 None
188 } else {
189 Some(NameIndex { s2i, i2s })
190 }
191 },
192 None => None,
193 })
194 }
195
196 ///// Provides a search-by-name functionality with scope and ordering defined by the implementor.
197 //fn by_name<'a>(
198 // &self,
199 // gname: &'static str,
200 // name: &'static str,
201 // ndb: &'a Namex<M1, M2>,
202 //)
203 // -> Outcome<Option<(B32, &'a Entity)>>
204 //{
205 // match res!(self.assoc_as_ids(gname)) {
206 // Some(ids) => {
207 // for id in ids {
208 // match ndb.by_id(&id) {
209 // Some(entity) => {
210 // for nam in &entity.nams {
211 // if nam == name {
212 // return Ok(Some((id, entity)));
213 // }
214 // }
215 // },
216 // None => return Err(err!(
217 // "Namex entry '{}' does not have a (nams) field, which is required.",
218 // Namex::<M1, M2>::id_to_string(&id),
219 // ), Invalid, Input, Missing)),
220 // }
221 // }
222 // },
223 // None => (),
224 // }
225 // Ok(None)
226 //}
227}
228
229impl InNamex for () {
230 fn name_id(&self) -> Outcome<NamexId> { Ok(NamexId::default()) }
231 fn assoc_names_base64(
232 _gname: &'static str,
233 )
234 -> Outcome<Option<Vec<(
235 &'static str,
236 &'static str,
237 )>>>
238 {
239 Ok(None)
240 }
241 fn assoc_names_index(
242 _gname: &'static str,
243 )
244 -> Outcome<Option<NameIndex>>
245 {
246 Ok(None)
247 }
248}