1mod error;
73#[cfg(any(feature = "serde", feature = "csv_export"))]
74mod export;
75mod field_parser;
76mod header;
77mod parser;
78mod schema;
79mod schema_discovery;
80mod schema_loader;
81mod stringblock;
82mod types;
83mod versions;
84mod writer;
85
86#[cfg(feature = "mmap")]
87mod mmap;
88
89mod lazy;
90
91#[cfg(feature = "parallel")]
92mod parallel;
93
94#[cfg(feature = "cli")]
95pub mod dbd;
96
97pub use error::Error;
98pub use header::DbcHeader;
99pub use lazy::{LazyDbcParser, LazyRecordIterator};
100pub use parser::{DbcParser, Record, RecordSet, Value};
101pub use schema::{FieldType, Schema, SchemaField};
102pub use schema_discovery::{Confidence, DiscoveredField, DiscoveredSchema, SchemaDiscoverer};
103pub use stringblock::{CachedStringBlock, StringBlock};
104pub use types::*;
105
106#[cfg(feature = "yaml")]
107pub use schema_loader::{SchemaDefinition, SchemaFieldDefinition};
108
109#[cfg(feature = "serde")]
110pub use export::export_to_json;
111
112#[cfg(feature = "csv_export")]
113pub use export::export_to_csv;
114
115#[cfg(feature = "mmap")]
116pub use mmap::MmapDbcFile;
117
118#[cfg(feature = "parallel")]
119pub use parallel::parse_records_parallel;
120
121pub use versions::{DbcVersion, Wdb2Header, Wdb5Header};
122pub use writer::DbcWriter;
123
124pub type Result<T> = std::result::Result<T, Error>;
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130 use std::io::Cursor;
131
132 fn create_test_dbc() -> Vec<u8> {
133 let mut data = Vec::new();
134
135 data.extend_from_slice(b"WDBC"); data.extend_from_slice(&2u32.to_le_bytes()); data.extend_from_slice(&3u32.to_le_bytes()); data.extend_from_slice(&12u32.to_le_bytes()); data.extend_from_slice(&19u32.to_le_bytes()); data.extend_from_slice(&1u32.to_le_bytes()); data.extend_from_slice(&0u32.to_le_bytes()); data.extend_from_slice(&100u32.to_le_bytes()); data.extend_from_slice(&2u32.to_le_bytes()); data.extend_from_slice(&6u32.to_le_bytes()); data.extend_from_slice(&200u32.to_le_bytes()); data.extend_from_slice(b"First\0Second\0Extra\0"); data
157 }
158
159 #[test]
160 fn test_header_parsing() {
161 let data = create_test_dbc();
162 let mut cursor = Cursor::new(&data);
163
164 let header = DbcHeader::parse(&mut cursor).unwrap();
165
166 assert_eq!(header.magic, *b"WDBC");
167 assert_eq!(header.record_count, 2);
168 assert_eq!(header.field_count, 3);
169 assert_eq!(header.record_size, 12);
170 assert_eq!(header.string_block_size, 19);
171 }
172
173 #[test]
174 fn test_schema_validation() {
175 let data = create_test_dbc();
176 let mut cursor = Cursor::new(&data);
177
178 let parser = DbcParser::parse(&mut cursor).unwrap();
179 let header = parser.header();
180
181 let mut schema = Schema::new("Test");
182 schema.add_field(SchemaField::new("ID", FieldType::UInt32));
183 schema.add_field(SchemaField::new("Name", FieldType::String));
184 schema.add_field(SchemaField::new("Value", FieldType::UInt32));
185 schema.set_key_field("ID");
186
187 assert!(
189 schema
190 .validate(header.field_count, header.record_size)
191 .is_ok()
192 );
193
194 let mut invalid_schema = Schema::new("Invalid");
196 invalid_schema.add_field(SchemaField::new("ID", FieldType::UInt32));
197 invalid_schema.add_field(SchemaField::new("Name", FieldType::String));
198 assert!(
201 invalid_schema
202 .validate(header.field_count, header.record_size)
203 .is_err()
204 );
205 }
206
207 #[test]
208 fn test_value_display() {
209 use crate::Value;
210
211 assert_eq!(format!("{}", Value::Int32(42)), "42");
213 assert_eq!(format!("{}", Value::UInt32(100)), "100");
214 assert_eq!(format!("{}", Value::Float32(3.5)), "3.5");
215 assert_eq!(format!("{}", Value::Bool(true)), "true");
216 assert_eq!(format!("{}", Value::Bool(false)), "false");
217 assert_eq!(format!("{}", Value::UInt8(255)), "255");
218 assert_eq!(format!("{}", Value::Int8(-128)), "-128");
219 assert_eq!(format!("{}", Value::UInt16(65535)), "65535");
220 assert_eq!(format!("{}", Value::Int16(-32768)), "-32768");
221 assert_eq!(
222 format!("{}", Value::StringRef(StringRef::new(42))),
223 "StringRef(42)"
224 );
225
226 let array = Value::Array(vec![Value::Int32(1), Value::Int32(2), Value::Int32(3)]);
228 assert_eq!(format!("{array}"), "[1, 2, 3]");
229
230 let empty_array = Value::Array(vec![]);
232 assert_eq!(format!("{empty_array}"), "[]");
233 }
234
235 #[test]
236 fn test_record_parsing() {
237 let data = create_test_dbc();
238
239 let parser = DbcParser::parse_bytes(&data).unwrap();
240
241 let mut schema = Schema::new("Test");
242 schema.add_field(SchemaField::new("ID", FieldType::UInt32));
243 schema.add_field(SchemaField::new("Name", FieldType::String));
244 schema.add_field(SchemaField::new("Value", FieldType::UInt32));
245 schema.set_key_field("ID");
246
247 let parser = parser.with_schema(schema).unwrap();
248 let record_set = parser.parse_records().unwrap();
249
250 assert_eq!(record_set.len(), 2);
251
252 let record = record_set.get_record(0).unwrap();
254 if let Value::UInt32(id) = record.get_value_by_name("ID").unwrap() {
255 assert_eq!(*id, 1);
256 } else {
257 panic!("Expected UInt32 for ID");
258 }
259
260 if let Value::StringRef(name_ref) = record.get_value_by_name("Name").unwrap() {
261 let name = record_set.get_string(*name_ref).unwrap();
262 assert_eq!(name, "First");
263 } else {
264 panic!("Expected StringRef for Name");
265 }
266
267 if let Value::UInt32(value) = record.get_value_by_name("Value").unwrap() {
268 assert_eq!(*value, 100);
269 } else {
270 panic!("Expected UInt32 for Value");
271 }
272
273 let record = record_set.get_record_by_key(2).unwrap();
275 if let Value::StringRef(name_ref) = record.get_value_by_name("Name").unwrap() {
276 let name = record_set.get_string(*name_ref).unwrap();
277 assert_eq!(name, "Second");
278 } else {
279 panic!("Expected StringRef for Name");
280 }
281 }
282}