1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
5#[repr(u8)]
6pub enum FieldType {
7 Long = 0,
9 String = 1,
11 Float = 2,
13 UnsignedLong = 3,
15 Short = 4,
17 Char = 5,
19 StringOffset = 6,
21}
22
23impl FieldType {
24 pub const fn size(&self) -> usize {
26 match self {
27 FieldType::Long => 4,
28 FieldType::String => 32,
29 FieldType::Float => 4,
30 FieldType::UnsignedLong => 4,
31 FieldType::Short => 2,
32 FieldType::Char => 1,
33 FieldType::StringOffset => 4,
34 }
35 }
36
37 pub const fn default_mask(&self) -> u32 {
39 match self {
40 FieldType::Long => 0xFFFFFFFF,
41 FieldType::String => 0x00000000,
42 FieldType::Float => 0xFFFFFFFF,
43 FieldType::UnsignedLong => 0xFFFFFFFF,
44 FieldType::Short => 0x0000FFFF,
45 FieldType::Char => 0x000000FF,
46 FieldType::StringOffset => 0xFFFFFFFF,
47 }
48 }
49
50 pub const fn order(&self) -> u8 {
52 match self {
53 FieldType::String => 0,
54 FieldType::Float => 1,
55 FieldType::Long => 2,
56 FieldType::UnsignedLong => 3,
57 FieldType::Short => 4,
58 FieldType::Char => 5,
59 FieldType::StringOffset => 6,
60 }
61 }
62
63 pub fn from_raw(value: u8) -> Option<Self> {
65 match value {
66 0 => Some(FieldType::Long),
67 1 => Some(FieldType::String),
68 2 => Some(FieldType::Float),
69 3 => Some(FieldType::UnsignedLong),
70 4 => Some(FieldType::Short),
71 5 => Some(FieldType::Char),
72 6 => Some(FieldType::StringOffset),
73 _ => None,
74 }
75 }
76
77 pub fn csv_name(&self) -> &'static str {
79 match self {
80 FieldType::Long => "Int",
81 FieldType::String => "EmbeddedString",
82 FieldType::Float => "Float",
83 FieldType::UnsignedLong => "UnsignedInt",
84 FieldType::Short => "Short",
85 FieldType::Char => "Char",
86 FieldType::StringOffset => "String",
87 }
88 }
89
90 pub fn from_csv_name(name: &str) -> Option<Self> {
92 match name {
93 "Int" => Some(FieldType::Long),
94 "EmbeddedString" => Some(FieldType::String),
95 "Float" => Some(FieldType::Float),
96 "UnsignedInt" => Some(FieldType::UnsignedLong),
97 "Short" => Some(FieldType::Short),
98 "Char" => Some(FieldType::Char),
99 "String" => Some(FieldType::StringOffset),
100 _ => None,
101 }
102 }
103}
104
105impl fmt::Display for FieldType {
106 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
107 write!(f, "{}", self.csv_name())
108 }
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub enum FieldValue {
114 Int(i32),
116 Float(f32),
118 String(String),
120}
121
122impl FieldValue {
123 pub fn default_for(field_type: FieldType) -> Self {
125 match field_type {
126 FieldType::Long
127 | FieldType::UnsignedLong
128 | FieldType::Short
129 | FieldType::Char => FieldValue::Int(0),
130 FieldType::Float => FieldValue::Float(0.0),
131 FieldType::String | FieldType::StringOffset => FieldValue::String(String::new()),
132 }
133 }
134
135 pub fn is_compatible_with(&self, field_type: FieldType) -> bool {
137 match (self, field_type) {
138 (FieldValue::Int(_), FieldType::Long)
139 | (FieldValue::Int(_), FieldType::UnsignedLong)
140 | (FieldValue::Int(_), FieldType::Short)
141 | (FieldValue::Int(_), FieldType::Char) => true,
142 (FieldValue::Float(_), FieldType::Float) => true,
143 (FieldValue::String(_), FieldType::String)
144 | (FieldValue::String(_), FieldType::StringOffset) => true,
145 _ => false,
146 }
147 }
148
149 pub fn as_int(&self) -> Option<i32> {
151 match self {
152 FieldValue::Int(v) => Some(*v),
153 _ => None,
154 }
155 }
156
157 pub fn as_float(&self) -> Option<f32> {
159 match self {
160 FieldValue::Float(v) => Some(*v),
161 _ => None,
162 }
163 }
164
165 pub fn as_str(&self) -> Option<&str> {
167 match self {
168 FieldValue::String(v) => Some(v),
169 _ => None,
170 }
171 }
172
173 pub fn type_name(&self) -> &'static str {
175 match self {
176 FieldValue::Int(_) => "Int",
177 FieldValue::Float(_) => "Float",
178 FieldValue::String(_) => "String",
179 }
180 }
181}
182
183impl fmt::Display for FieldValue {
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 match self {
186 FieldValue::Int(v) => write!(f, "{}", v),
187 FieldValue::Float(v) => write!(f, "{}", v),
188 FieldValue::String(v) => write!(f, "{}", v),
189 }
190 }
191}
192
193impl From<i32> for FieldValue {
194 fn from(v: i32) -> Self {
195 FieldValue::Int(v)
196 }
197}
198
199impl From<f32> for FieldValue {
200 fn from(v: f32) -> Self {
201 FieldValue::Float(v)
202 }
203}
204
205impl From<String> for FieldValue {
206 fn from(v: String) -> Self {
207 FieldValue::String(v)
208 }
209}
210
211impl From<&str> for FieldValue {
212 fn from(v: &str) -> Self {
213 FieldValue::String(v.to_string())
214 }
215}
216
217#[derive(Debug, Clone)]
219pub struct Field {
220 pub hash: u32,
222 pub mask: u32,
224 pub offset: u16,
226 pub field_type: FieldType,
228 pub shift: u8,
230
231 pub default: FieldValue,
233}
234
235impl Field {
236 pub fn new(hash: u32, field_type: FieldType) -> Self {
238 Self {
239 hash,
240 field_type,
241 mask: field_type.default_mask(),
242 shift: 0,
243 offset: 0,
244 default: FieldValue::default_for(field_type),
245 }
246 }
247
248 pub fn with_default(hash: u32, field_type: FieldType, default: FieldValue) -> Self {
250 Self {
251 hash,
252 field_type,
253 mask: field_type.default_mask(),
254 shift: 0,
255 offset: 0,
256 default,
257 }
258 }
259
260 pub fn size(&self) -> usize {
262 self.field_type.size()
263 }
264}