Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_jdat/src/usr.rs

6.0 KiB, 21 runs

created by r1870400018:491, 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

1//! The `Dat::Usr` and `Kind::Usr` variants make use of `UsrKIndId` in order to allow custom user
2//! daticles.
3
4use crate::{
5 Dat,
6 Kind,
7};
8
9use oxedyne_fe2o3_core::{
10 prelude::*,
11 map::MapMut,
12};
13
14use std::{
15 fmt::{
16 self,
17 Debug,
18 },
19};
20
21pub type UsrKindCode = u16;
22
23#[derive(Clone, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
24pub struct UsrKind {
25 label: String,
26 kind: Option<Box<Kind>>,
27}
28
29impl UsrKind {
30
31 pub fn new(code: UsrKindCode) -> Self {
32 Self {
33 label: Self::code_to_label(code),
34 kind: None,
35 }
36 }
37
38 pub fn code_to_label(code: UsrKindCode) -> String {
39 fmt!("{}{}", Kind::USR_LABEL_PREFIX, Self::fmt_code(code))
40 }
41
42 pub fn fmt_code(code: UsrKindCode) -> String {
43 fmt!("0x{:04x}", code)
44 }
45
46}
47
48#[derive(Clone, Debug, Default, Ord, PartialOrd)]
49pub struct UsrKindId {
50 code: UsrKindCode,
51 ukind: UsrKind,
52}
53
54impl PartialEq for UsrKindId {
55 fn eq(&self, other: &Self) -> bool {
56 self.code == other.code
57 }
58}
59impl Eq for UsrKindId {}
60
61impl From<UsrKindCode> for UsrKindId {
62 fn from(code: UsrKindCode) -> Self {
63 Self {
64 code,
65 ukind: UsrKind::new(code),
66 }
67 }
68}
69
70impl UsrKindId {
71
72 pub const CODE_BYTE_LEN: usize = std::mem::size_of::<UsrKindCode>();
73
74 pub fn new(
75 code: UsrKindCode,
76 lab_opt: Option<&str>,
77 kind_opt: Option<Kind>,
78 )
79 -> Self
80 {
81 let label = match lab_opt {
82 Some(lab) => lab.to_string(),
83 None => UsrKind::code_to_label(code),
84 };
85 Self {
86 code,
87 ukind: UsrKind {
88 label,
89 kind: match kind_opt {
90 None => None,
91 Some(kind) => Some(Box::new(kind)),
92 },
93 },
94 }
95 }
96
97 pub fn code(&self) -> UsrKindCode {
98 self.code
99 }
100
101 pub fn label(&self) -> &str {
102 &self.ukind.label
103 }
104
105 pub fn kind(&self) -> &Option<Box<Kind>> {
106 &self.ukind.kind
107 }
108
109 pub fn label_to_code(label: &str) -> Outcome<UsrKindCode> {
110
111 let prefix = Kind::USR_LABEL_PREFIX;
112
113 if label.starts_with(prefix) {
114 let rest = &label[prefix.len()..];
115 if rest.starts_with("0x") {
116 match UsrKindCode::from_str_radix(&rest[2..], 16) {
117 Ok(code) => Ok(code),
118 Err(e) => Err(err!(e,
119 "Suffix '{}' of label '{}' cannot be interpreted as a u{}.",
120 rest, label, Self::CODE_BYTE_LEN * 8;
121 Input, Invalid, String)),
122 }
123 } else {
124 Err(err!(
125 "The code in label '{}' should start with a '0x'.", label;
126 Input, Invalid, String))
127 }
128 } else {
129 Err(err!(
130 "Label '{}' does not start with prefix '{}'.",
131 label, prefix;
132 Input, Invalid, String))
133 }
134 }
135
136 pub fn byte_prefix(&self) -> [u8; Self::CODE_BYTE_LEN] {
137 self.code.to_be_bytes()
138 }
139
140 /// The caller must check that the given byte slice is at least as long as
141 /// `UsrKindId::BYTE_LEN`.
142 pub fn prefix_matches(prefix: [u8; Self::CODE_BYTE_LEN], byts: &[u8]) -> bool {
143 prefix[0] == byts[0] &&
144 prefix[1] == byts[1]
145 }
146
147 pub fn dat<D: Into<Dat>>(&self, optd: Option<D>) -> Dat {
148 Dat::Usr(self.clone(), match optd {
149 None => None,
150 Some(d) => Some(Box::new(d.into())),
151 })
152 }
153}
154
155#[derive(Clone, Debug, Default)]
156pub struct UsrKinds<
157 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
158 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
159>{
160 c2k: M1,
161 s2i: M2,
162}
163
164impl<
165 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
166 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
167>
168 From<(M1, M2)> for UsrKinds<M1, M2>
169{
170 fn from((c2k, s2i): (M1, M2)) -> Self {
171 Self {
172 c2k,
173 s2i,
174 }
175 }
176}
177
178impl<
179 M1: MapMut<UsrKindCode, UsrKind> + Clone + fmt::Debug + Default,
180 M2: MapMut<String, UsrKindId> + Clone + fmt::Debug + Default,
181>
182 UsrKinds<M1, M2>
183{
184 pub fn new(c2k: M1, s2i: M2) -> Self {
185 Self {
186 c2k,
187 s2i,
188 }
189 }
190
191 pub fn code_to_kind_map(&self) -> &M1 {
192 &self.c2k
193 }
194
195 pub fn label_to_id_map(&self) -> &M2 {
196 &self.s2i
197 }
198
199 pub fn add(&mut self, ukid: UsrKindId) -> Outcome<()> {
200 let code = ukid.code();
201 let label = ukid.label().to_string();
202 match Kind::from_str(&label) {
203 Ok(k) => Err(err!(
204 "Label '{}' matches existing standard JDAT type, which \
205 represents '{}'", label, k.desc();
206 Input, Exists, Invalid)),
207 Err(_) => {
208 if self.c2k.contains_key(&code) {
209 Err(err!(
210 "{:?} is already registered as a user kind.", ukid;
211 Input, Exists))
212 } else {
213 self.c2k.insert(code, ukid.ukind.clone());
214 self.s2i.insert(label, UsrKindId {
215 code,
216 ukind: ukid.ukind,
217 });
218 Ok(())
219 }
220 },
221 }
222 }
223
224 /// Looks for an entry matching the given string.
225 pub fn get_label(&self, label: &str) -> Option<&UsrKindId> {
226 let label = label.to_string();
227 self.s2i.get(&label)
228 //match self.s2i.get(&label) {
229 // Some(id) => Some(id.clone()),
230 // None => None,
231 //}
232 }
233
234 /// Looks for an entry matching the given code.
235 pub fn get_code(&self, code: &UsrKindCode) -> Option<UsrKindId> {
236 match self.c2k.get(&code) {
237 Some(ukind) => Some(UsrKindId {
238 code: *code,
239 ukind: ukind.clone(),
240 }),
241 None => None,
242 }
243 }
244
245}