1#[macro_use]
2extern crate nom;
3#[macro_use]
4extern crate enum_primitive_derive;
5extern crate log;
6mod mat_error;
7#[cfg(feature = "ndarray")]
8pub mod ndarray;
9mod parse;
10mod writer;
11
12use std::io::Write;
13
14use bytes::{BufMut, BytesMut};
15use nom::number::Endianness;
16use parse::Header;
17
18use crate::mat_error::MatError;
19
20#[derive(Clone, Debug)]
21pub struct Array {
22 array_flags: parse::ArrayFlags,
23 name: String,
24 size: Vec<usize>,
25 data: NumericData,
26}
27impl Array {
28 pub fn name(&self) -> &str {
29 &self.name
30 }
31 pub fn size(&self) -> &Vec<usize> {
32 &self.size
33 }
34 pub fn ndims(&self) -> usize {
35 self.size.len()
36 }
37 pub fn data(&self) -> &NumericData {
38 &self.data
39 }
40 pub fn get_num_elements(&self) -> u32 {
41 let mut count = 1;
42 for val in self.size.iter() {
43 count *= val;
44 }
45 count as u32
46 }
47 pub fn check_index_bound(&self, index: usize, dim: usize) -> usize {
48 if index >= 0 && index < self.size[dim] {
49 index
50 } else {
51 dim
52 }
53 }
54 pub fn set_int8(&mut self, row: usize, col: usize, value: i8) {
55 let ix0 = self.check_index_bound(row, 0);
56 let ix1 = self.check_index_bound(col, 1);
57 let index = row + col * self.size[0];
58 match &mut self.data {
60 NumericData::Int8 { real, .. } => {
61 real[index] = value;
62 }
63 _ => {}
64 }
65 }
66
67 }
69
70#[derive(Clone, Debug)]
71pub enum NumericData {
72 Int8 {
73 real: Vec<i8>,
74 imag: Option<Vec<i8>>,
75 },
76 UInt8 {
77 real: Vec<u8>,
78 imag: Option<Vec<u8>>,
79 },
80 Int16 {
81 real: Vec<i16>,
82 imag: Option<Vec<i16>>,
83 },
84 UInt16 {
85 real: Vec<u16>,
86 imag: Option<Vec<u16>>,
87 },
88 Int32 {
89 real: Vec<i32>,
90 imag: Option<Vec<i32>>,
91 },
92 UInt32 {
93 real: Vec<u32>,
94 imag: Option<Vec<u32>>,
95 },
96 Int64 {
97 real: Vec<i64>,
98 imag: Option<Vec<i64>>,
99 },
100 UInt64 {
101 real: Vec<u64>,
102 imag: Option<Vec<u64>>,
103 },
104 Single {
105 real: Vec<f32>,
106 imag: Option<Vec<f32>>,
107 },
108 Double {
109 real: Vec<f64>,
110 imag: Option<Vec<f64>>,
111 },
112}
113impl NumericData {
114 fn to_numberic_bytes(&self, endianness: nom::number::Endianness) -> (BytesMut, BytesMut) {
115 let mut real_bytes = BytesMut::new();
116 let mut imag_bytes = BytesMut::new();
117 match self {
118 NumericData::Int8 { real, imag } => {
119 for v in real {
120 real_bytes.put_i8(v.to_owned());
121 }
122 }
123 NumericData::UInt8 { real, imag } => {
124 for v in real {
125 real_bytes.put_u8(v.to_owned());
126 }
127 }
128 NumericData::Int16 { real, imag } => {
129 for v in real {
130 if endianness == nom::number::Endianness::Big {
131 real_bytes.put_i16(v.to_owned());
132 } else {
133 real_bytes.put_i16_le(v.to_owned());
134 }
135 }
136 }
137 NumericData::UInt16 { real, imag } => {
138 for v in real {
139 if endianness == nom::number::Endianness::Big {
140 real_bytes.put_u16(v.to_owned());
141 } else {
142 real_bytes.put_u16_le(v.to_owned());
143 }
144 }
145 }
146 NumericData::Int32 { real, imag } => {
147 for v in real {
148 if endianness == nom::number::Endianness::Big {
149 real_bytes.put_i32(v.to_owned());
150 } else {
151 real_bytes.put_i32_le(v.to_owned());
152 }
153 }
154 }
155 NumericData::UInt32 { real, imag } => {
156 for v in real {
157 if endianness == nom::number::Endianness::Big {
158 real_bytes.put_u32(v.to_owned());
159 } else {
160 real_bytes.put_u32_le(v.to_owned());
161 }
162 }
163 }
164 NumericData::Int64 { real, imag } => {
165 for v in real {
166 if endianness == nom::number::Endianness::Big {
167 real_bytes.put_i64(v.to_owned());
168 } else {
169 real_bytes.put_i64_le(v.to_owned());
170 }
171 }
172 }
173 NumericData::UInt64 { real, imag } => {
174 for v in real {
175 if endianness == nom::number::Endianness::Big {
176 real_bytes.put_u64(v.to_owned());
177 } else {
178 real_bytes.put_u64_le(v.to_owned());
179 }
180 }
181 }
182 NumericData::Single { real, imag } => {
183 for v in real {
184 if endianness == nom::number::Endianness::Big {
185 real_bytes.put_f32(v.to_owned());
186 } else {
187 real_bytes.put_f32_le(v.to_owned());
188 }
189 }
190 }
191 NumericData::Double { real, imag } => {
192 for v in real {
193 if endianness == nom::number::Endianness::Big {
194 real_bytes.put_f64(v.to_owned());
195 } else {
196 real_bytes.put_f64_le(v.to_owned());
197 }
198 }
199 }
200 _ => {}
201 };
202 (real_bytes, imag_bytes)
203 }
204 fn to_numberic_size(&self) -> (usize, usize) {
205 match self {
206 NumericData::Int8 { real, imag } => {
207 (real.len(), if let Some(v) = imag { v.len() } else { 0 })
208 }
209 NumericData::UInt8 { real, imag } => {
210 (real.len(), if let Some(v) = imag { v.len() } else { 0 })
211 }
212 NumericData::Int16 { real, imag } => (
213 2 * real.len(),
214 if let Some(v) = imag { v.len() * 2 } else { 0 },
215 ),
216 NumericData::UInt16 { real, imag } => (
217 2 * real.len(),
218 if let Some(v) = imag { v.len() * 2 } else { 0 },
219 ),
220 NumericData::Int32 { real, imag } => (
221 4 * real.len(),
222 if let Some(v) = imag { v.len() * 4 } else { 0 },
223 ),
224 NumericData::UInt32 { real, imag } => (
225 4 * real.len(),
226 if let Some(v) = imag { v.len() * 4 } else { 0 },
227 ),
228 NumericData::Int64 { real, imag } => (
229 8 * real.len(),
230 if let Some(v) = imag { v.len() * 8 } else { 0 },
231 ),
232 NumericData::UInt64 { real, imag } => (
233 8 * real.len(),
234 if let Some(v) = imag { v.len() * 8 } else { 0 },
235 ),
236 NumericData::Single { real, imag } => (
237 4 * real.len(),
238 if let Some(v) = imag { v.len() * 4 } else { 0 },
239 ),
240 NumericData::Double { real, imag } => (
241 8 * real.len(),
242 if let Some(v) = imag { v.len() * 8 } else { 0 },
243 ),
244 _ => (0usize, 0usize),
245 }
246 }
247 fn to_real_size(&self) -> usize {
248 match self {
249 NumericData::Int8 { real, imag } => real.len(),
250 NumericData::UInt8 { real, imag } => real.len(),
251 NumericData::Int16 { real, imag } => 2 * real.len(),
252 NumericData::UInt16 { real, imag } => 2 * real.len(),
253 NumericData::Int32 { real, imag } => 4 * real.len(),
254 NumericData::UInt32 { real, imag } => 4 * real.len(),
255 NumericData::Int64 { real, imag } => 8 * real.len(),
256 NumericData::UInt64 { real, imag } => 8 * real.len(),
257 NumericData::Single { real, imag } => 4 * real.len(),
258 NumericData::Double { real, imag } => 8 * real.len(),
259 _ => 0,
260 }
261 }
262}
263
264fn try_convert_number_format(
265 target_type: parse::MatlabType,
266 data: parse::NumericData,
267) -> Result<parse::NumericData, MatError> {
268 match target_type {
269 parse::MatlabType::Double => match data {
270 parse::NumericData::UInt8(data) => Ok(parse::NumericData::Double(
271 data.into_iter().map(|x| x as f64).collect(),
272 )),
273 parse::NumericData::Int16(data) => Ok(parse::NumericData::Double(
274 data.into_iter().map(|x| x as f64).collect(),
275 )),
276 parse::NumericData::UInt16(data) => Ok(parse::NumericData::Double(
277 data.into_iter().map(|x| x as f64).collect(),
278 )),
279 parse::NumericData::Int32(data) => Ok(parse::NumericData::Double(
280 data.into_iter().map(|x| x as f64).collect(),
281 )),
282 parse::NumericData::Double(data) => Ok(parse::NumericData::Double(data)),
283 _ => Err(MatError::ConversionError),
284 },
285 parse::MatlabType::Single => match data {
286 parse::NumericData::UInt8(data) => Ok(parse::NumericData::Single(
287 data.into_iter().map(|x| x as f32).collect(),
288 )),
289 parse::NumericData::Int16(data) => Ok(parse::NumericData::Single(
290 data.into_iter().map(|x| x as f32).collect(),
291 )),
292 parse::NumericData::UInt16(data) => Ok(parse::NumericData::Single(
293 data.into_iter().map(|x| x as f32).collect(),
294 )),
295 parse::NumericData::Int32(data) => Ok(parse::NumericData::Single(
296 data.into_iter().map(|x| x as f32).collect(),
297 )),
298 parse::NumericData::Single(data) => Ok(parse::NumericData::Single(data)),
299 _ => Err(MatError::ConversionError),
300 },
301 parse::MatlabType::UInt64 => match data {
302 parse::NumericData::UInt8(data) => Ok(parse::NumericData::UInt64(
303 data.into_iter().map(|x| x as u64).collect(),
304 )),
305 parse::NumericData::Int16(data) => Ok(parse::NumericData::UInt64(
306 data.into_iter().map(|x| x as u64).collect(),
307 )),
308 parse::NumericData::UInt16(data) => Ok(parse::NumericData::UInt64(
309 data.into_iter().map(|x| x as u64).collect(),
310 )),
311 parse::NumericData::Int32(data) => Ok(parse::NumericData::UInt64(
312 data.into_iter().map(|x| x as u64).collect(),
313 )),
314 parse::NumericData::UInt64(data) => Ok(parse::NumericData::UInt64(data)),
315 _ => Err(MatError::ConversionError),
316 },
317 parse::MatlabType::Int64 => match data {
318 parse::NumericData::UInt8(data) => Ok(parse::NumericData::Int64(
319 data.into_iter().map(|x| x as i64).collect(),
320 )),
321 parse::NumericData::Int16(data) => Ok(parse::NumericData::Int64(
322 data.into_iter().map(|x| x as i64).collect(),
323 )),
324 parse::NumericData::UInt16(data) => Ok(parse::NumericData::Int64(
325 data.into_iter().map(|x| x as i64).collect(),
326 )),
327 parse::NumericData::Int32(data) => Ok(parse::NumericData::Int64(
328 data.into_iter().map(|x| x as i64).collect(),
329 )),
330 parse::NumericData::Int64(data) => Ok(parse::NumericData::Int64(data)),
331 _ => Err(MatError::ConversionError),
332 },
333 parse::MatlabType::UInt32 => match data {
334 parse::NumericData::UInt8(data) => Ok(parse::NumericData::UInt32(
335 data.into_iter().map(|x| x as u32).collect(),
336 )),
337 parse::NumericData::Int16(data) => Ok(parse::NumericData::UInt32(
338 data.into_iter().map(|x| x as u32).collect(),
339 )),
340 parse::NumericData::UInt16(data) => Ok(parse::NumericData::UInt32(
341 data.into_iter().map(|x| x as u32).collect(),
342 )),
343 parse::NumericData::UInt32(data) => Ok(parse::NumericData::UInt32(data)),
344 _ => Err(MatError::ConversionError),
345 },
346 parse::MatlabType::Int32 => match data {
347 parse::NumericData::UInt8(data) => Ok(parse::NumericData::Int32(
348 data.into_iter().map(|x| x as i32).collect(),
349 )),
350 parse::NumericData::Int16(data) => Ok(parse::NumericData::Int32(
351 data.into_iter().map(|x| x as i32).collect(),
352 )),
353 parse::NumericData::UInt16(data) => Ok(parse::NumericData::Int32(
354 data.into_iter().map(|x| x as i32).collect(),
355 )),
356 parse::NumericData::Int32(data) => Ok(parse::NumericData::Int32(data)),
357 _ => Err(MatError::ConversionError),
358 },
359 parse::MatlabType::UInt16 => match data {
360 parse::NumericData::UInt8(data) => Ok(parse::NumericData::UInt16(
361 data.into_iter().map(|x| x as u16).collect(),
362 )),
363 parse::NumericData::UInt16(data) => Ok(parse::NumericData::UInt16(data)),
364 _ => Err(MatError::ConversionError),
365 },
366 parse::MatlabType::Int16 => match data {
367 parse::NumericData::UInt8(data) => Ok(parse::NumericData::Int16(
368 data.into_iter().map(|x| x as i16).collect(),
369 )),
370 parse::NumericData::Int16(data) => Ok(parse::NumericData::Int16(data)),
371 _ => Err(MatError::ConversionError),
372 },
373 parse::MatlabType::UInt8 => match data {
374 parse::NumericData::UInt8(data) => Ok(parse::NumericData::UInt8(data)),
375 _ => Err(MatError::ConversionError),
376 },
377 parse::MatlabType::Int8 => match data {
378 parse::NumericData::Int8(data) => Ok(parse::NumericData::Int8(data)),
379 _ => Err(MatError::ConversionError),
380 },
381 _ => Err(MatError::ConversionError),
382 }
383}
384
385impl NumericData {
386 fn try_from(
387 target_type: parse::MatlabType,
388 real: parse::NumericData,
389 imag: Option<parse::NumericData>,
390 ) -> Result<Self, MatError> {
391 let real = try_convert_number_format(target_type, real)?;
392 let imag = match imag {
393 Some(imag) => Some(try_convert_number_format(target_type, imag)?),
394 None => None,
395 };
396 match (real, imag) {
397 (parse::NumericData::Double(real), None) => Ok(NumericData::Double {
398 real: real,
399 imag: None,
400 }),
401 (parse::NumericData::Double(real), Some(parse::NumericData::Double(imag))) => {
402 Ok(NumericData::Double {
403 real: real,
404 imag: Some(imag),
405 })
406 }
407 (parse::NumericData::Single(real), None) => Ok(NumericData::Single {
408 real: real,
409 imag: None,
410 }),
411 (parse::NumericData::Single(real), Some(parse::NumericData::Single(imag))) => {
412 Ok(NumericData::Single {
413 real: real,
414 imag: Some(imag),
415 })
416 }
417 (parse::NumericData::UInt64(real), None) => Ok(NumericData::UInt64 {
418 real: real,
419 imag: None,
420 }),
421 (parse::NumericData::UInt64(real), Some(parse::NumericData::UInt64(imag))) => {
422 Ok(NumericData::UInt64 {
423 real: real,
424 imag: Some(imag),
425 })
426 }
427 (parse::NumericData::Int64(real), None) => Ok(NumericData::Int64 {
428 real: real,
429 imag: None,
430 }),
431 (parse::NumericData::Int64(real), Some(parse::NumericData::Int64(imag))) => {
432 Ok(NumericData::Int64 {
433 real: real,
434 imag: Some(imag),
435 })
436 }
437 (parse::NumericData::UInt32(real), None) => Ok(NumericData::UInt32 {
438 real: real,
439 imag: None,
440 }),
441 (parse::NumericData::UInt32(real), Some(parse::NumericData::UInt32(imag))) => {
442 Ok(NumericData::UInt32 {
443 real: real,
444 imag: Some(imag),
445 })
446 }
447 (parse::NumericData::Int32(real), None) => Ok(NumericData::Int32 {
448 real: real,
449 imag: None,
450 }),
451 (parse::NumericData::Int32(real), Some(parse::NumericData::Int32(imag))) => {
452 Ok(NumericData::Int32 {
453 real: real,
454 imag: Some(imag),
455 })
456 }
457 (parse::NumericData::UInt16(real), None) => Ok(NumericData::UInt16 {
458 real: real,
459 imag: None,
460 }),
461 (parse::NumericData::UInt16(real), Some(parse::NumericData::UInt16(imag))) => {
462 Ok(NumericData::UInt16 {
463 real: real,
464 imag: Some(imag),
465 })
466 }
467 (parse::NumericData::Int16(real), None) => Ok(NumericData::Int16 {
468 real: real,
469 imag: None,
470 }),
471 (parse::NumericData::Int16(real), Some(parse::NumericData::Int16(imag))) => {
472 Ok(NumericData::Int16 {
473 real: real,
474 imag: Some(imag),
475 })
476 }
477 (parse::NumericData::UInt8(real), None) => Ok(NumericData::UInt8 {
478 real: real,
479 imag: None,
480 }),
481 (parse::NumericData::UInt8(real), Some(parse::NumericData::UInt8(imag))) => {
482 Ok(NumericData::UInt8 {
483 real: real,
484 imag: Some(imag),
485 })
486 }
487 (parse::NumericData::Int8(real), None) => Ok(NumericData::Int8 {
488 real: real,
489 imag: None,
490 }),
491 (parse::NumericData::Int8(real), Some(parse::NumericData::Int8(imag))) => {
492 Ok(NumericData::Int8 {
493 real: real,
494 imag: Some(imag),
495 })
496 }
497 _ => return Err(MatError::InternalError),
498 }
499 }
500}
501
502#[derive(Clone, Debug)]
503pub struct MatFile {
504 header: Header,
505 arrays: Vec<Array>,
506}
507impl MatFile {
508 pub fn add_array(&mut self, array: Array) -> &mut MatFile {
509 self.arrays.push(array);
510 self
511 }
512 pub fn find_by_name<'a>(&'a self, name: &'_ str) -> Option<&'a Array> {
513 for array in &self.arrays {
514 if array.name == name {
515 return Some(array);
516 }
517 }
518 None
519 }
520
521 pub fn new_mat_file() -> MatFile {
522 let v: u16 = 0x00ff;
524 let first_octet: u8 = unsafe {
525 let ptr = &v as *const u16;
526 let ptr = ptr as *const u8;
527 *ptr
528 };
529 MatFile {
530 arrays: vec![],
531 header: Header {
532 version: 1,
533 mat_identifier: "MATLAB 5.0 MAT-file".to_string(),
534 description: "".to_string(),
535 byte_order: if first_octet == 0xff {
536 Endianness::Little
537 } else {
538 Endianness::Big
539 },
540 subsys_offset: 0,
541 deflate_level: 1,
542 },
543 }
544 }
545 pub fn new_matrix(
546 name: &str,
547 rows: usize,
548 cols: usize,
549 complex: bool,
550 mat_type: parse::MatlabType,
551 ) -> Result<Array, MatError> {
552 let array_flags = parse::ArrayFlags {
553 complex: complex,
554 global: false,
555 logical: false,
556 class: mat_type,
557 nzmax: 0,
558 };
559 let real = if let Some(data) = parse::NumericData::try_from(mat_type, rows, cols) {
560 data
561 } else {
562 return Err(MatError::ParamsError("暂时不支持该数据类型".to_string()));
563 };
564 let imag = if complex {
565 parse::NumericData::try_from(mat_type, rows, cols)
566 } else {
567 None
568 };
569 let data = NumericData::try_from(mat_type, real, imag)?;
570 let array = Array {
571 array_flags: array_flags,
572 name: name.to_string(),
573 size: vec![rows, cols],
574 data: data,
575 };
576 Ok(array)
577 }
578 pub fn parse<R: std::io::Read>(mut read: R) -> Result<Self, MatError> {
579 let mut buf = Vec::new();
580 read.read_to_end(&mut buf)
581 .map_err(|err| MatError::IOError(err))?;
582 let (_remaining, parse_result) = parse::parse_all(&buf)
583 .map_err(|err| MatError::ParseError(parse::replace_err_slice(err, &[])))?;
584 let arrays: Result<Vec<Array>, MatError> = parse_result
585 .data_elements
586 .into_iter()
587 .filter_map(|data_element| match data_element {
588 parse::DataElement::NumericMatrix(flags, dims, name, real, imag) => {
589 let size = dims.into_iter().map(|d| d as usize).collect();
590 let numeric_data = match NumericData::try_from(flags.class, real, imag) {
591 Ok(numeric_data) => numeric_data,
592 Err(err) => return Some(Err(err)),
593 };
594 Some(Ok(Array {
595 array_flags: flags,
596 size: size,
597 name: name,
598 data: numeric_data,
599 }))
600 }
601 _ => None,
602 })
603 .collect();
604 let arrays = arrays?;
605 Ok(MatFile {
606 arrays: arrays,
607 header: Header {
608 version: 1,
609 mat_identifier: "".to_string(),
610 description: "".to_string(),
611 byte_order: Endianness::Little,
612 subsys_offset: 0,
613 deflate_level: 1,
614 },
615 })
616 }
617 pub fn save_matfile<T: AsRef<str>>(&self, path: T) -> Result<(), MatError> {
618 let mut file = std::fs::File::create(path.as_ref())?;
619 let header = writer::write_header(self)?;
620 let _r = file.write_all(header.as_ref());
621 let body = writer::write_body(self)?;
622 let _r = file.write_all(body.as_ref());
623 Ok(())
624 }
625}
626
627mod tests {
628
629 #[test]
630 fn write_matfile() -> std::result::Result<(), crate::mat_error::MatError> {
631 let mut new_matfile = super::MatFile::new_mat_file();
632 let rows = 4;
633 let cols = 5;
634 let mut matrix = super::MatFile::new_matrix(
635 "matrixIdentity",
636 rows,
637 cols,
638 false,
639 crate::parse::MatlabType::Int8,
640 )?;
641 let mut count = 1;
642 for i in 0..rows {
643 for j in 0..cols {
644 matrix.set_int8(i, j, count);
645 count += 1;
646 }
647 }
648 println!("matrix==>{:?}", matrix);
649 new_matfile.add_array(matrix);
650 let _r = new_matfile.save_matfile("d:/newmyfile.mat")?;
651 println!("加载生成文件");
652 let file = std::fs::File::open("d:/newmyfile.mat")?;
653 let matfile = super::MatFile::parse(file)?;
654 let array = matfile.find_by_name("matrixIdentity");
655 println!("matrixIdentity={:?}", array);
656 Ok(())
657 }
658 #[test]
659 fn read_matfile() -> std::result::Result<(), crate::mat_error::MatError> {
660 let file = std::fs::File::open("d:/myfile.mat")?;
661 let matfile = super::MatFile::parse(file)?;
662 let array = matfile.find_by_name("matrixIdentity");
663 println!("matrixIdentity={:?}", array);
664 let array = matfile.find_by_name("tout");
665 println!("tout={:?}", array);
666 let array = matfile.find_by_name("x");
667 println!("x={:?}", array);
668 let array = matfile.find_by_name("y");
669 println!("y={:?}", array);
670 Ok(())
671 }
672}