1#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum FieldType {
6 Int32,
8 UInt32,
10 Float32,
12 String,
14 Bool,
16 UInt8,
18 Int8,
20 UInt16,
22 Int16,
24}
25
26impl FieldType {
27 pub fn size(&self) -> usize {
29 match self {
30 FieldType::Int32 => 4,
31 FieldType::UInt32 => 4,
32 FieldType::Float32 => 4,
33 FieldType::String => 4, FieldType::Bool => 4, FieldType::UInt8 => 1,
36 FieldType::Int8 => 1,
37 FieldType::UInt16 => 2,
38 FieldType::Int16 => 2,
39 }
40 }
41}
42
43#[derive(Debug, Clone)]
45pub struct SchemaField {
46 pub name: String,
48 pub field_type: FieldType,
50 pub is_array: bool,
52 pub array_size: Option<usize>,
54}
55
56impl SchemaField {
57 pub fn new(name: impl Into<String>, field_type: FieldType) -> Self {
59 Self {
60 name: name.into(),
61 field_type,
62 is_array: false,
63 array_size: None,
64 }
65 }
66
67 pub fn new_array(name: impl Into<String>, field_type: FieldType, array_size: usize) -> Self {
69 Self {
70 name: name.into(),
71 field_type,
72 is_array: true,
73 array_size: Some(array_size),
74 }
75 }
76
77 pub fn size(&self) -> usize {
79 if self.is_array {
80 self.field_type.size() * self.array_size.unwrap_or(0)
81 } else {
82 self.field_type.size()
83 }
84 }
85}
86
87#[derive(Debug, Clone)]
89pub struct Schema {
90 pub name: String,
92 pub fields: Vec<SchemaField>,
94 pub key_field_index: Option<usize>,
96 pub is_validated: bool,
98}
99
100impl Schema {
101 pub fn new(name: impl Into<String>) -> Self {
103 Self {
104 name: name.into(),
105 fields: Vec::new(),
106 key_field_index: None,
107 is_validated: false,
108 }
109 }
110
111 pub fn add_field(&mut self, field: SchemaField) -> &mut Self {
113 self.fields.push(field);
114 self.is_validated = false;
115 self
116 }
117
118 pub fn set_key_field_index(&mut self, index: usize) -> &mut Self {
120 self.key_field_index = Some(index);
121 self.is_validated = false;
122 self
123 }
124
125 pub fn set_key_field(&mut self, name: &str) -> &mut Self {
132 let index = self
133 .fields
134 .iter()
135 .position(|f| f.name == name)
136 .unwrap_or_else(|| panic!("Field not found: {name}"));
137 self.set_key_field_index(index)
138 }
139
140 pub fn try_set_key_field(&mut self, name: &str) -> Result<&mut Self, String> {
142 let index = self
143 .fields
144 .iter()
145 .position(|f| f.name == name)
146 .ok_or_else(|| format!("Field not found: {name}"))?;
147 Ok(self.set_key_field_index(index))
148 }
149
150 pub fn record_size(&self) -> usize {
152 self.fields.iter().map(|f| f.size()).sum()
153 }
154
155 pub fn validate(&mut self, field_count: u32, record_size: u32) -> Result<(), String> {
157 let schema_field_count = if self.fields.iter().any(|f| f.is_array) {
158 self.fields
160 .iter()
161 .map(|f| {
162 if f.is_array {
163 f.array_size.unwrap_or(0)
164 } else {
165 1
166 }
167 })
168 .sum::<usize>() as u32
169 } else {
170 self.fields.len() as u32
171 };
172
173 if schema_field_count != field_count {
174 return Err(format!(
175 "Field count mismatch: schema has {schema_field_count} fields, but DBC has {field_count} fields"
176 ));
177 }
178
179 let schema_record_size = self.record_size() as u32;
180 if schema_record_size != record_size {
181 return Err(format!(
182 "Record size mismatch: schema defines {schema_record_size} bytes, but DBC has {record_size} bytes per record"
183 ));
184 }
185
186 if let Some(index) = self.key_field_index {
187 if index >= self.fields.len() {
188 return Err(format!(
189 "Key field index out of bounds: {} (max: {})",
190 index,
191 self.fields.len() - 1
192 ));
193 }
194
195 let key_field = &self.fields[index];
196 match key_field.field_type {
197 FieldType::UInt32 | FieldType::Int32 => {}
198 _ => {
199 return Err(format!(
200 "Key field must be a 32-bit integer, but is {:?}",
201 key_field.field_type
202 ));
203 }
204 }
205
206 if key_field.is_array {
207 return Err("Key field cannot be an array".to_string());
208 }
209 }
210
211 self.is_validated = true;
212 Ok(())
213 }
214}