1mod se;
10
11use quick_xml::de;
12use std::convert::{TryFrom, TryInto};
13use std::io::{BufRead, Write};
14use std::path::Path;
15
16use serde::{Deserialize, Serialize};
17
18use crate::model;
19
20type Result<T> = std::result::Result<T, Error>;
21
22#[derive(Debug)]
23pub enum Error {
24 XML(quick_xml::Error),
25 Base64Decode(base64::DecodeError),
26 Validation(ValidationError),
27 Model(model::Error),
28 IO(std::io::Error),
29 Deserialization(de::DeError),
30 InvalidVersion,
31 TypeExtensionMismatch,
32 InvalidType,
33 InvalidByteOrder,
34 UnexpectedElement(String),
37 Unknown,
38}
39
40impl std::fmt::Display for Error {
41 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
42 match self {
43 Error::XML(source) => write!(f, "XML error: {:?}", source),
44 Error::Base64Decode(source) => write!(f, "Base64 decode error: {:?}", source),
45 Error::Validation(source) => write!(f, "Validation error: {:?}", source),
46 Error::Model(source) => write!(f, "Model processing error: {:?}", source),
47 Error::IO(source) => write!(f, "I/O error: {:?}", source),
48 Error::Deserialization(source) => write!(f, "Deserialization error: {:?}", source),
49 Error::InvalidVersion => write!(f, "VTK version must be in \"major.minor\" format"),
50 Error::InvalidByteOrder => write!(
51 f,
52 "Byte order must be one of \"BigEndian\" or \"LittleEndian\""
53 ),
54 Error::InvalidType => write!(f, "Invalid VTKFile type detected"),
55 Error::TypeExtensionMismatch => write!(
60 f,
61 "The extension of the VTK file doesn't match the type specified in the VTKFile tag"
62 ),
63 Error::UnexpectedElement(elem) => write!(f, "Unexpected XML Element: {}", elem),
64 Error::Unknown => write!(f, "Internal error"),
65 }
66 }
67}
68
69impl std::error::Error for Error {
70 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
71 match self {
72 Error::XML(source) => Some(source),
73 Error::Base64Decode(source) => Some(source),
74 Error::Validation(source) => Some(source),
75 Error::Model(source) => Some(source),
76 Error::IO(source) => Some(source),
77 Error::Deserialization(source) => Some(source),
78 _ => None,
79 }
80 }
81}
82
83impl From<model::Error> for Error {
84 fn from(e: model::Error) -> Error {
85 Error::Model(e)
86 }
87}
88
89impl From<base64::DecodeError> for Error {
90 fn from(e: base64::DecodeError) -> Error {
91 Error::Base64Decode(e)
92 }
93}
94
95impl From<quick_xml::Error> for Error {
96 fn from(e: quick_xml::Error) -> Error {
97 Error::XML(e)
98 }
99}
100
101impl From<ValidationError> for Error {
102 fn from(e: ValidationError) -> Error {
103 Error::Validation(e)
104 }
105}
106
107impl From<de::DeError> for Error {
108 fn from(e: de::DeError) -> Error {
109 Error::Deserialization(e)
110 }
111}
112
113impl From<std::io::Error> for Error {
114 fn from(e: std::io::Error) -> Error {
115 Error::IO(e)
116 }
117}
118
119mod compressor {
121 use super::Compressor;
122 use serde::de::{self, Deserialize, Deserializer, Visitor};
123 use serde::ser::{Serialize, Serializer};
124 use std::fmt;
125
126 struct CompressorVisitor;
127
128 impl<'de> Visitor<'de> for CompressorVisitor {
129 type Value = Compressor;
130
131 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
132 formatter.write_str("a string identifying the vtk data compressor")
133 }
134
135 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
136 where
137 E: de::Error,
138 {
139 Ok(match v {
140 "vtkZLibDataCompressor" => Compressor::ZLib,
141 "vtkLZ4DataCompressor" => Compressor::LZ4,
142 "vtkLZMADataCompressor" => Compressor::LZMA,
143 _ => Compressor::None,
144 })
145 }
146 }
147
148 impl Serialize for Compressor {
149 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
150 where
151 S: Serializer,
152 {
153 let compressor = match self {
154 Compressor::ZLib => "vtkZLibDataCompressor",
155 Compressor::LZ4 => "vtkLZ4DataCompressor",
156 Compressor::LZMA => "vtkLZMADataCompressor",
157 Compressor::None => return s.serialize_none(),
158 };
159 s.serialize_str(compressor)
160 }
161 }
162 impl<'de> Deserialize<'de> for Compressor {
163 fn deserialize<D>(d: D) -> Result<Compressor, D::Error>
164 where
165 D: Deserializer<'de>,
166 {
167 d.deserialize_str(CompressorVisitor)
168 }
169 }
170}
171
172mod extent {
174 use super::Extent;
175 use serde::de::{self, Deserialize, Deserializer, Visitor};
176 use serde::ser::{Serialize, Serializer};
177 use std::fmt;
178
179 struct ExtentVisitor;
180
181 impl<'de> Visitor<'de> for ExtentVisitor {
182 type Value = [i32; 6];
183
184 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
185 formatter.write_str("a space separated sequence of 6 integers")
186 }
187
188 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
189 where
190 E: de::Error,
191 {
192 let mut iter = v.split_ascii_whitespace();
193 let mut count = 0;
194 let mut advance = |i: &mut std::str::SplitAsciiWhitespace| {
195 let elem = i.next().ok_or(de::Error::invalid_length(count, &self))?;
196 count += 1;
197 elem.parse()
198 .map_err(|e| de::Error::custom(&format!("failed to parse integer: {}", e)))
199 };
200 Ok([
201 advance(&mut iter)?,
202 advance(&mut iter)?,
203 advance(&mut iter)?,
204 advance(&mut iter)?,
205 advance(&mut iter)?,
206 advance(&mut iter)?,
207 ])
208 }
209 }
210
211 impl Serialize for Extent {
212 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
213 where
214 S: Serializer,
215 {
216 let Extent([a, b, c, d, e, f]) = self;
217 s.collect_str(&format_args!("{} {} {} {} {} {}", a, b, c, d, e, f))
218 }
219 }
220
221 impl<'de> Deserialize<'de> for Extent {
222 fn deserialize<D>(d: D) -> Result<Self, D::Error>
223 where
224 D: Deserializer<'de>,
225 {
226 Ok(Extent(d.deserialize_str(ExtentVisitor)?))
227 }
228 }
229}
230
231mod vector3 {
233 use serde::de::{self, Deserialize, Deserializer, Visitor};
234 use serde::ser::{Serialize, Serializer};
235 use std::fmt;
236
237 struct Vector3Visitor;
238
239 impl<'de> Visitor<'de> for Vector3Visitor {
240 type Value = [f32; 3];
241
242 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
243 formatter.write_str("a space separated sequence of 3 floats")
244 }
245
246 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
247 where
248 E: de::Error,
249 {
250 let mut iter = v.split_whitespace();
251 let mut count = 0;
252 let mut advance = |i: &mut std::str::SplitWhitespace| {
253 let elem = i
254 .next()
255 .ok_or_else(|| de::Error::invalid_length(count, &self))?;
256 count += 1;
257 elem.parse()
258 .map_err(|e| de::Error::custom(&format!("failed to parse float: {}", e)))
259 };
260 Ok([
261 advance(&mut iter)?,
262 advance(&mut iter)?,
263 advance(&mut iter)?,
264 ])
265 }
266 }
267
268 pub struct Vector3(pub [f32; 3]);
269
270 impl Serialize for Vector3 {
271 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
272 where
273 S: Serializer,
274 {
275 let Vector3([a, b, c]) = self;
276 s.collect_str(&format_args!("{} {} {}", a, b, c))
277 }
278 }
279
280 impl<'de> Deserialize<'de> for Vector3 {
281 fn deserialize<D>(d: D) -> Result<Vector3, D::Error>
282 where
283 D: Deserializer<'de>,
284 {
285 d.deserialize_str(Vector3Visitor).map(Vector3)
286 }
287 }
288
289 pub fn deserialize<'de, D>(d: D) -> Result<[f32; 3], D::Error>
290 where
291 D: Deserializer<'de>,
292 {
293 d.deserialize_str(Vector3Visitor)
294 }
295}
296
297mod version {
300 use super::model::Version;
301 use serde::de::{self, Deserialize, Deserializer, Visitor};
302 use serde::ser::{Serialize, Serializer};
303 use std::fmt;
304
305 struct VersionVisitor;
306
307 impl<'de> Visitor<'de> for VersionVisitor {
308 type Value = Version;
309
310 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
311 formatter.write_str("a dot separated pair of integers")
312 }
313
314 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
315 where
316 E: de::Error,
317 {
318 let mut iter = v.split('.');
319 let advance = |i: &mut std::str::Split<'_, char>| {
320 let elem = i
321 .next()
322 .ok_or(de::Error::custom("need a major and minor version numbers"))?;
323 elem.parse()
324 .map_err(|e| de::Error::custom(&format!("failed to parse version: {}", e)))
325 };
326 Ok(Version::new((advance(&mut iter)?, advance(&mut iter)?)))
327 }
328 }
329
330 impl Serialize for Version {
331 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
332 where
333 S: Serializer,
334 {
335 let Version { major, minor } = self;
336 s.collect_str(&format_args!("{}.{}", major, minor))
337 }
338 }
339 impl<'de> Deserialize<'de> for Version {
340 fn deserialize<D>(d: D) -> Result<Version, D::Error>
341 where
342 D: Deserializer<'de>,
343 {
344 d.deserialize_str(VersionVisitor)
345 }
346 }
347}
348
349mod pcoordinates {
350 use super::{PCoordinates, PDataArray};
351 use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
352 use serde::ser::{Serialize, Serializer};
353 use std::fmt;
354
355 #[derive(Debug, serde::Deserialize)]
356 #[serde(field_identifier)]
357 enum Field {
358 PDataArray,
359 }
360
361 struct PCoordinatesVisitor;
362
363 impl<'de> Visitor<'de> for PCoordinatesVisitor {
364 type Value = PCoordinates;
365
366 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
367 formatter.write_str("an array of 3 PDataArrays")
368 }
369
370 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
371 where
372 A: MapAccess<'de>,
373 {
374 let invalid_len_err = |n| <A::Error as serde::de::Error>::invalid_length(n, &self);
375 let (_, x) = map
376 .next_entry::<Field, PDataArray>()?
377 .ok_or_else(|| invalid_len_err(0))?;
378 let (_, y) = map
379 .next_entry::<Field, PDataArray>()?
380 .ok_or_else(|| invalid_len_err(1))?;
381 let (_, z) = map
382 .next_entry::<Field, PDataArray>()?
383 .ok_or_else(|| invalid_len_err(2))?;
384 Ok(PCoordinates([x, y, z]))
385 }
386 }
387
388 impl Serialize for PCoordinates {
389 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
390 where
391 S: Serializer,
392 {
393 use serde::ser::SerializeStruct;
394 let PCoordinates([x, y, z]) = self;
395 let mut ss = s.serialize_struct("PCoordinates", 3)?;
396 ss.serialize_field("PDataArray", x)?;
397 ss.serialize_field("PDataArray", y)?;
398 ss.serialize_field("PDataArray", z)?;
399 ss.end()
400 }
401 }
402 impl<'de> Deserialize<'de> for PCoordinates {
403 fn deserialize<D>(d: D) -> Result<PCoordinates, D::Error>
404 where
405 D: Deserializer<'de>,
406 {
407 d.deserialize_struct("PCoordinates", &["PDataArray"; 3], PCoordinatesVisitor)
408 }
409 }
410}
411
412mod coordinates {
413 use super::{Coordinates, DataArray};
414 use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
415 use serde::ser::{Serialize, Serializer};
416 use std::fmt;
417
418 #[derive(Debug, serde::Deserialize)]
419 #[serde(field_identifier)]
420 enum Field {
421 DataArray,
422 }
423
424 struct CoordinatesVisitor;
425
426 impl<'de> Visitor<'de> for CoordinatesVisitor {
427 type Value = Coordinates;
428
429 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
430 formatter.write_str("an array of 3 DataArrays")
431 }
432
433 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
434 where
435 A: MapAccess<'de>,
436 {
437 let invalid_len_err = |n| <A::Error as serde::de::Error>::invalid_length(n, &self);
438 let (_, x) = map
440 .next_entry::<Field, DataArray>()?
441 .ok_or_else(|| invalid_len_err(0))?;
442 let (_, y) = map
443 .next_entry::<Field, DataArray>()?
444 .ok_or_else(|| invalid_len_err(1))?;
445 let (_, z) = map
446 .next_entry::<Field, DataArray>()?
447 .ok_or_else(|| invalid_len_err(2))?;
448 Ok(Coordinates([x, y, z]))
449 }
450 }
451
452 impl Serialize for Coordinates {
453 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
454 where
455 S: Serializer,
456 {
457 use serde::ser::SerializeStruct;
458 let Coordinates([x, y, z]) = self;
459 let mut ss = s.serialize_struct("Coordinates", 3)?;
460 ss.serialize_field("DataArray", x)?;
461 ss.serialize_field("DataArray", y)?;
462 ss.serialize_field("DataArray", z)?;
463 ss.end()
464 }
465 }
466 impl<'de> Deserialize<'de> for Coordinates {
467 fn deserialize<D>(d: D) -> Result<Coordinates, D::Error>
468 where
469 D: Deserializer<'de>,
470 {
471 d.deserialize_struct("Coordinates", &["DataArray"; 3], CoordinatesVisitor)
472 }
473 }
474}
475
476mod data {
477 use super::{AppendedData, Data, Encoding, RawData};
478 use serde::{
479 de::{self, Deserialize, Deserializer, MapAccess, Visitor},
480 Serialize, Serializer,
481 };
482 use std::fmt;
483 fn is_whitespace(b: u8) -> bool {
485 match b {
486 b' ' | b'\r' | b'\n' | b'\t' => true,
487 _ => false,
488 }
489 }
490
491 #[derive(Debug, serde::Deserialize)]
492 #[serde(field_identifier)]
493 enum Field {
494 #[serde(rename = "encoding")]
495 Encoding,
496 #[serde(rename = "$value")]
497 Value,
498 }
499
500 struct DataVisitor;
505
506 impl<'de> Visitor<'de> for DataVisitor {
507 type Value = Data;
508
509 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
510 formatter.write_str("Data string in base64 or ASCII format")
511 }
512
513 fn visit_map<A>(self, _map: A) -> Result<Self::Value, A::Error>
514 where
515 A: MapAccess<'de>,
516 {
517 Ok(Data::Meta {
519 information_key: (),
520 })
521 }
522 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
523 where
524 E: de::Error,
525 {
526 Ok(Data::Data(v.trim_end().to_string()))
527 }
528 }
529
530 impl<'de> Deserialize<'de> for Data {
533 fn deserialize<D>(d: D) -> Result<Self, D::Error>
534 where
535 D: Deserializer<'de>,
536 {
537 Ok(d.deserialize_any(DataVisitor)?)
538 }
539 }
540
541 struct AppendedDataVisitor;
545
546 impl<'de> Visitor<'de> for AppendedDataVisitor {
547 type Value = AppendedData;
548
549 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
550 formatter.write_str("Appended bytes or base64 data")
551 }
552
553 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
554 where
555 A: MapAccess<'de>,
556 {
557 let make_err = || {
558 <A::Error as serde::de::Error>::custom(
559 "AppendedData element must contain only a single \"encoding\" attribute",
560 )
561 };
562 let mut encoding = None;
563 let mut data = RawData::default();
564 if let Some((key, value)) = map.next_entry::<Field, Encoding>()? {
565 match key {
566 Field::Encoding => encoding = Some(value),
567 _ => return Err(make_err()),
568 }
569 }
570 if let Some((key, value)) = map.next_entry::<Field, RawData>()? {
571 match key {
572 Field::Value => data = value,
573 _ => return Err(make_err()),
574 }
575 }
576 if let Some(Encoding::Base64) = encoding {
577 if let Some(end) = data.0.iter().rposition(|&b| !is_whitespace(b)) {
579 data = RawData(data.0[..=end].to_vec());
580 }
581 }
582 Ok(AppendedData {
583 encoding: encoding.unwrap_or(Encoding::Raw),
584 data,
585 })
586 }
587 }
588
589 impl<'de> Deserialize<'de> for AppendedData {
592 fn deserialize<D>(d: D) -> Result<Self, D::Error>
593 where
594 D: Deserializer<'de>,
595 {
596 Ok(d.deserialize_struct("AppendedData", &["encoding", "$value"], AppendedDataVisitor)?)
597 }
598 }
599
600 struct RawDataVisitor;
605
606 impl<'de> Visitor<'de> for RawDataVisitor {
607 type Value = RawData;
608
609 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
610 formatter.write_str("Raw byte data")
611 }
612
613 fn visit_bytes<E: serde::de::Error>(self, v: &[u8]) -> Result<Self::Value, E> {
614 if v.is_empty() {
616 return Ok(RawData(Vec::new()));
617 }
618 if v[0] != b'_' {
619 return Err(serde::de::Error::custom("Missing preceeding underscore"));
620 }
621 Ok(RawData(v[1..].to_vec()))
622 }
623 }
624
625 impl Serialize for RawData {
626 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
627 where
628 S: Serializer,
629 {
630 if !self.0.is_empty() {
631 let mut v = Vec::with_capacity(self.0.len() + 1);
632 v.push(b'_');
633 v.extend_from_slice(&self.0);
634 s.serialize_bytes(&v)
635 } else {
636 s.serialize_bytes(&[])
637 }
638 }
639 }
640
641 impl<'de> Deserialize<'de> for RawData {
642 fn deserialize<D>(d: D) -> Result<Self, D::Error>
643 where
644 D: Deserializer<'de>,
645 {
646 Ok(d.deserialize_bytes(RawDataVisitor)?)
647 }
648 }
649}
650
651mod data_set {
652 use super::*;
653 use serde::ser::{Serialize, SerializeStruct, Serializer};
654
655 impl Serialize for ImageData {
656 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
657 where
658 S: Serializer,
659 {
660 let mut ss = s.serialize_struct("ImageData", 3 + self.pieces.len())?;
661 ss.serialize_field("WholeExtent", &self.whole_extent)?;
662 ss.serialize_field("Origin", &vector3::Vector3(self.origin))?;
663 ss.serialize_field("Spacing", &vector3::Vector3(self.spacing))?;
664 for p in &self.pieces {
665 ss.serialize_field("Piece", p)?;
666 }
667 ss.end()
668 }
669 }
670
671 impl Serialize for Grid {
672 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
673 where
674 S: Serializer,
675 {
676 let mut ss = s.serialize_struct("Grid", 1 + &self.pieces.len())?;
677 ss.serialize_field("WholeExtent", &self.whole_extent)?;
678 for p in &self.pieces {
679 ss.serialize_field("Piece", p)?;
680 }
681 ss.end()
682 }
683 }
684
685 impl Serialize for Unstructured {
686 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
687 where
688 S: Serializer,
689 {
690 let mut ss = s.serialize_struct("Unstructured", self.pieces.len())?;
691 for p in &self.pieces {
692 ss.serialize_field("Piece", p)?;
693 }
694 ss.end()
695 }
696 }
697
698 impl Serialize for PImageData {
699 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
700 where
701 S: Serializer,
702 {
703 let mut ss = s.serialize_struct("PImageData", 6 + self.pieces.len())?;
704 ss.serialize_field("GhostLevel", &self.ghost_level)?;
705 ss.serialize_field("WholeExtent", &self.whole_extent)?;
706 ss.serialize_field("Origin", &vector3::Vector3(self.origin))?;
707 ss.serialize_field("Spacing", &vector3::Vector3(self.spacing))?;
708 ss.serialize_field("PPointData", &self.point_data)?;
709 ss.serialize_field("PCellData", &self.cell_data)?;
710 for p in &self.pieces {
711 ss.serialize_field("Piece", p)?;
712 }
713 ss.end()
714 }
715 }
716
717 impl Serialize for PUnstructured {
718 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
719 where
720 S: Serializer,
721 {
722 let mut ss = s.serialize_struct("PUnstructured", 4 + self.pieces.len())?;
723 ss.serialize_field("GhostLevel", &self.ghost_level)?;
724 ss.serialize_field("PPointData", &self.point_data)?;
725 ss.serialize_field("PCellData", &self.cell_data)?;
726 ss.serialize_field("PPoints", &self.points)?;
727 for p in &self.pieces {
728 ss.serialize_field("Piece", p)?;
729 }
730 ss.end()
731 }
732 }
733
734 impl Serialize for PRectilinearGrid {
735 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
736 where
737 S: Serializer,
738 {
739 let mut ss = s.serialize_struct("PRectilinearGrid", 5 + self.pieces.len())?;
740 ss.serialize_field("GhostLevel", &self.ghost_level)?;
741 ss.serialize_field("WholeExtent", &self.whole_extent)?;
742 ss.serialize_field("PPointData", &self.point_data)?;
743 ss.serialize_field("PCellData", &self.cell_data)?;
744 ss.serialize_field("PCoordinates", &self.coords)?;
745 for p in &self.pieces {
746 ss.serialize_field("Piece", p)?;
747 }
748 ss.end()
749 }
750 }
751
752 impl Serialize for PStructuredGrid {
753 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
754 where
755 S: Serializer,
756 {
757 let mut ss = s.serialize_struct("PStructuredGrid", 5 + self.pieces.len())?;
758 ss.serialize_field("GhostLevel", &self.ghost_level)?;
759 ss.serialize_field("WholeExtent", &self.whole_extent)?;
760 ss.serialize_field("PPointData", &self.point_data)?;
761 ss.serialize_field("PCellData", &self.cell_data)?;
762 ss.serialize_field("PPoints", &self.points)?;
763 for p in &self.pieces {
764 ss.serialize_field("Piece", p)?;
765 }
766 ss.end()
767 }
768 }
769}
770
771mod topo {
772 use super::{Cells, DataArray, Topo};
773 use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
774 use std::fmt;
775
776 #[derive(Debug, serde::Deserialize)]
777 #[serde(field_identifier)]
778 enum Field {
779 DataArray,
780 }
781
782 struct TopoVisitor;
783
784 impl<'de> Visitor<'de> for TopoVisitor {
785 type Value = Topo;
786
787 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
788 formatter.write_str("topo data")
789 }
790
791 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
792 where
793 A: MapAccess<'de>,
794 {
795 let make_err = || {
796 <A::Error as serde::de::Error>::custom(
797 "Topo data arrays must contain two DataArrays named \"connectivity\" and \"offsets\""
798 )
799 };
800 let mut connectivity = None;
801 let mut offsets = None;
802 while let Some((_, field)) = map.next_entry::<Field, DataArray>()? {
803 match field.name.as_str() {
804 "connectivity" => connectivity = Some(field),
805 "offsets" => offsets = Some(field),
806 _ => return Err(make_err()),
807 }
808 }
809 let connectivity = connectivity.ok_or_else(|| make_err())?;
810 let offsets = offsets.ok_or_else(|| make_err())?;
811 Ok(Topo {
812 connectivity,
813 offsets,
814 })
815 }
816 }
817
818 impl<'de> Deserialize<'de> for Topo {
819 fn deserialize<D>(d: D) -> Result<Self, D::Error>
820 where
821 D: Deserializer<'de>,
822 {
823 Ok(d.deserialize_struct("Topo", &["DataArray"; 2], TopoVisitor)?)
824 }
825 }
826
827 struct CellsVisitor;
828
829 impl<'de> Visitor<'de> for CellsVisitor {
830 type Value = Cells;
831
832 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
833 formatter.write_str("topo data")
834 }
835
836 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
837 where
838 A: MapAccess<'de>,
839 {
840 let make_err = || {
841 <A::Error as serde::de::Error>::custom(
842 "Cells data arrays must contain three DataArrays named \"connectivity\", \"offsets\" and \"types\""
843 )
844 };
845 let mut connectivity = None;
846 let mut offsets = None;
847 let mut types = None;
848 while let Some((_, field)) = map.next_entry::<Field, DataArray>()? {
849 match field.name.as_str() {
850 "connectivity" => connectivity = Some(field),
851 "offsets" => offsets = Some(field),
852 "types" => types = Some(field),
853 _ => return Err(make_err()),
854 }
855 }
856
857 let connectivity = connectivity.ok_or_else(make_err)?;
858 let offsets = offsets.ok_or_else(make_err)?;
859 let types = types.ok_or_else(make_err)?;
860 Ok(Cells {
861 connectivity,
862 offsets,
863 types,
864 })
865 }
866 }
867
868 impl<'de> Deserialize<'de> for Cells {
869 fn deserialize<D>(d: D) -> Result<Self, D::Error>
870 where
871 D: Deserializer<'de>,
872 {
873 Ok(d.deserialize_struct("Cells", &["DataArray"; 3], CellsVisitor)?)
874 }
875 }
876}
877
878mod piece {
879 use super::{AttributeData, Cells, Coordinates, Extent, Piece, Points, Topo};
880 use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
881 use std::fmt;
882
883 #[derive(Debug, serde::Deserialize)]
884 #[serde(field_identifier)]
885 enum Field {
886 Extent,
887 NumberOfPoints,
888 NumberOfCells,
889 NumberOfLines,
890 NumberOfStrips,
891 NumberOfPolys,
892 NumberOfVerts,
893 PointData,
894 CellData,
895 Polys,
896 Points,
897 Cells,
898 Verts,
899 Lines,
900 Strips,
901 Coordinates,
902 }
903
904 struct PieceVisitor;
905
906 impl<'de> Visitor<'de> for PieceVisitor {
907 type Value = Piece;
908
909 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
910 formatter.write_str("piece data")
911 }
912
913 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
914 where
915 A: MapAccess<'de>,
916 {
917 let mut piece = Piece {
918 extent: None,
919 number_of_points: 0,
920 number_of_cells: 0,
921 number_of_lines: 0,
922 number_of_strips: 0,
923 number_of_polys: 0,
924 number_of_verts: 0,
925 point_data: AttributeData::default(),
926 cell_data: AttributeData::default(),
927 polys: None,
928 points: None,
929 cells: None,
930 verts: None,
931 lines: None,
932 strips: None,
933 coordinates: None,
934 };
935
936 while let Some(key) = map.next_key::<Field>()? {
937 match key {
938 Field::Extent => {
939 piece.extent = map.next_value::<Option<Extent>>()?;
940 }
941 Field::NumberOfPoints => {
942 piece.number_of_points = map.next_value::<u32>()?;
943 }
944 Field::NumberOfCells => {
945 piece.number_of_cells = map.next_value::<u32>()?;
946 }
947 Field::NumberOfLines => {
948 piece.number_of_lines = map.next_value::<u32>()?;
949 }
950 Field::NumberOfStrips => {
951 piece.number_of_strips = map.next_value::<u32>()?;
952 }
953 Field::NumberOfPolys => {
954 piece.number_of_polys = map.next_value::<u32>()?;
955 }
956 Field::NumberOfVerts => {
957 piece.number_of_verts = map.next_value::<u32>()?;
958 }
959 Field::PointData => {
960 piece.point_data = map.next_value::<AttributeData>()?;
961 }
962 Field::CellData => {
963 piece.cell_data = map.next_value::<AttributeData>()?;
964 }
965 Field::Polys => {
966 piece.polys = map.next_value::<Option<Topo>>()?;
967 }
968 Field::Points => {
969 piece.points = map.next_value::<Option<Points>>()?;
970 }
971 Field::Cells => {
972 piece.cells = map.next_value::<Option<Cells>>()?;
973 }
974 Field::Verts => {
975 piece.verts = map.next_value::<Option<Topo>>()?;
976 }
977 Field::Lines => {
978 piece.lines = map.next_value::<Option<Topo>>()?;
979 }
980 Field::Strips => {
981 piece.strips = map.next_value::<Option<Topo>>()?;
982 }
983 Field::Coordinates => {
984 piece.coordinates = map.next_value::<Option<Coordinates>>()?;
985 }
986 }
987 }
988
989 Ok(piece)
990 }
991 }
992
993 impl<'de> Deserialize<'de> for Piece {
994 fn deserialize<D>(d: D) -> Result<Self, D::Error>
995 where
996 D: Deserializer<'de>,
997 {
998 Ok(d.deserialize_struct(
999 "Piece",
1000 &[
1001 "Extent",
1002 "NumberOfPoints",
1003 "NumberOfCells",
1004 "NumberOfLines",
1005 "NumberOfStrips",
1006 "NumberOfPolys",
1007 "NumberOfVerts",
1008 "PointData",
1009 "CellData",
1010 "Polys",
1011 "Points",
1012 "Cells",
1013 "Verts",
1014 "Lines",
1015 "Strips",
1016 "Coordinates",
1017 ],
1018 PieceVisitor,
1019 )?)
1020 }
1021 }
1022}
1023
1024mod vtkfile {
1025 use super::{
1026 model, AppendedData, Compressor, DataSet, DataSetType, ScalarType, Unstructured, VTKFile,
1027 };
1028 use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
1029 use serde::ser::{Serialize, Serializer};
1030 use std::fmt;
1031
1032 impl Serialize for VTKFile {
1033 fn serialize<S>(&self, s: S) -> std::result::Result<S::Ok, S::Error>
1034 where
1035 S: Serializer,
1036 {
1037 use serde::ser::SerializeStruct;
1038 let mut ss = s.serialize_struct("VTKFile", 7)?;
1039 ss.serialize_field("type", &self.data_set_type)?;
1040 ss.serialize_field("version", &self.version)?;
1041 ss.serialize_field("byte_order", &self.byte_order)?;
1042 ss.serialize_field("header_type", &self.header_type)?;
1043 ss.serialize_field("compressor", &self.compressor)?;
1044 ss.serialize_field("AppendedData", &self.appended_data)?;
1045 match &self.data_set {
1046 DataSet::ImageData(image_data) => ss.serialize_field("ImageData", image_data)?,
1047 DataSet::PolyData(unstructured) => ss.serialize_field("PolyData", unstructured)?,
1048 DataSet::RectilinearGrid(grid) => ss.serialize_field("RectilinearGrid", grid)?,
1049 DataSet::StructuredGrid(grid) => ss.serialize_field("StructuredGrid", grid)?,
1050 DataSet::UnstructuredGrid(grid) => ss.serialize_field("UnstructuredGrid", grid)?,
1051 DataSet::PImageData(image_data) => ss.serialize_field("PImageData", image_data)?,
1052 DataSet::PPolyData(unstructured) => {
1053 ss.serialize_field("PPolyData", unstructured)?
1054 }
1055 DataSet::PRectilinearGrid(grid) => ss.serialize_field("PRectilinearGrid", grid)?,
1056 DataSet::PStructuredGrid(grid) => ss.serialize_field("PStructuredGrid", grid)?,
1057 DataSet::PUnstructuredGrid(grid) => {
1058 ss.serialize_field("PUnstructuredGrid", grid)?
1059 }
1060 }
1061
1062 ss.end()
1063 }
1064 }
1065
1066 #[derive(Debug, serde::Deserialize)]
1067 #[serde(field_identifier)]
1068 enum Field {
1069 #[serde(rename = "type")]
1070 Type,
1071 #[serde(rename = "version")]
1072 Version,
1073 #[serde(rename = "byte_order")]
1074 ByteOrder,
1075 #[serde(rename = "header_type")]
1076 HeaderType,
1077 #[serde(rename = "compressor")]
1078 Compressor,
1079 AppendedData,
1080 ImageData,
1081 PolyData,
1082 RectilinearGrid,
1083 StructuredGrid,
1084 UnstructuredGrid,
1085 PImageData,
1086 PPolyData,
1087 PRectilinearGrid,
1088 PStructuredGrid,
1089 PUnstructuredGrid,
1090 }
1091
1092 struct VTKFileVisitor;
1093
1094 impl<'de> Visitor<'de> for VTKFileVisitor {
1095 type Value = VTKFile;
1096
1097 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1098 formatter.write_str("vtk xml file data")
1099 }
1100
1101 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
1102 where
1103 A: MapAccess<'de>,
1104 {
1105 let mut vtk = VTKFile {
1106 data_set_type: DataSetType::UnstructuredGrid,
1107 version: model::Version::new((1, 0)),
1108 byte_order: model::ByteOrder::BigEndian,
1109 header_type: None,
1110 compressor: Compressor::None,
1111 appended_data: None,
1112 data_set: DataSet::UnstructuredGrid(Unstructured { pieces: Vec::new() }),
1113 };
1114
1115 while let Some(key) = map.next_key::<Field>()? {
1116 match key {
1117 Field::Type => {
1118 vtk.data_set_type = map.next_value::<DataSetType>()?;
1119 }
1120 Field::Version => {
1121 vtk.version = map.next_value::<model::Version>()?;
1122 }
1123 Field::ByteOrder => {
1124 vtk.byte_order = map.next_value::<model::ByteOrder>()?;
1125 }
1126 Field::HeaderType => {
1127 vtk.header_type = map.next_value::<Option<ScalarType>>()?;
1128 }
1129 Field::Compressor => {
1130 vtk.compressor = map.next_value::<Compressor>()?;
1131 }
1132 Field::AppendedData => {
1133 vtk.appended_data = map.next_value::<Option<AppendedData>>()?;
1134 }
1135 Field::ImageData
1136 | Field::PolyData
1137 | Field::RectilinearGrid
1138 | Field::StructuredGrid
1139 | Field::UnstructuredGrid
1140 | Field::PImageData
1141 | Field::PPolyData
1142 | Field::PRectilinearGrid
1143 | Field::PStructuredGrid
1144 | Field::PUnstructuredGrid => {
1145 vtk.data_set = map.next_value::<DataSet>()?;
1146 }
1147 }
1148 }
1149
1150 Ok(vtk)
1151 }
1152 }
1153
1154 impl<'de> Deserialize<'de> for VTKFile {
1155 fn deserialize<D>(d: D) -> Result<Self, D::Error>
1156 where
1157 D: Deserializer<'de>,
1158 {
1159 Ok(d.deserialize_struct(
1160 "VTKFile",
1161 &[
1162 "type",
1163 "version",
1164 "byte_order",
1165 "header_type",
1166 "compressor",
1167 "AppendedData",
1168 "ImageData",
1169 "PolyData",
1170 "RectilinearGrid",
1171 "StructuredGrid",
1172 "UnstructuredGrid",
1173 "PImageData",
1174 "PPolyData",
1175 "PRectilinearGrid",
1176 "PStructuredGrid",
1177 "PUnstructuredGrid",
1178 ],
1179 VTKFileVisitor,
1180 )?)
1181 }
1182 }
1183}
1184
1185#[derive(Clone, Debug, PartialEq)]
1194pub struct VTKFile {
1195 pub data_set_type: DataSetType,
1196 pub version: model::Version,
1197 pub byte_order: model::ByteOrder,
1198 pub header_type: Option<ScalarType>, pub compressor: Compressor,
1200 pub appended_data: Option<AppendedData>,
1201 pub data_set: DataSet,
1202}
1203
1204impl Default for VTKFile {
1205 fn default() -> VTKFile {
1206 VTKFile {
1207 data_set_type: DataSetType::ImageData,
1208 version: model::Version::new((0, 1)),
1209 byte_order: model::ByteOrder::BigEndian,
1210 header_type: None,
1211 compressor: Compressor::None,
1212 appended_data: None,
1213 data_set: DataSet::UnstructuredGrid(Unstructured { pieces: Vec::new() }),
1214 }
1215 }
1216}
1217
1218#[derive(Copy, Clone, Debug, PartialEq)]
1219pub enum Compressor {
1220 LZ4,
1221 ZLib,
1222 LZMA,
1223 None,
1224}
1225
1226impl Default for Compressor {
1227 fn default() -> Compressor {
1228 Compressor::None
1229 }
1230}
1231
1232#[derive(Clone, Debug, PartialEq, Deserialize)]
1233pub enum DataSet {
1234 ImageData(ImageData),
1235 PolyData(Unstructured),
1236 RectilinearGrid(Grid),
1237 StructuredGrid(Grid),
1238 UnstructuredGrid(Unstructured),
1239 PImageData(PImageData),
1240 PPolyData(PUnstructured),
1241 PRectilinearGrid(PRectilinearGrid),
1242 PStructuredGrid(PStructuredGrid),
1243 PUnstructuredGrid(PUnstructured),
1244}
1245
1246#[derive(Clone, Debug, PartialEq, Deserialize)]
1247pub struct ImageData {
1248 #[serde(rename = "WholeExtent")]
1249 whole_extent: Extent,
1250 #[serde(rename = "Origin", deserialize_with = "vector3::deserialize")]
1251 origin: [f32; 3],
1252 #[serde(rename = "Spacing", deserialize_with = "vector3::deserialize")]
1253 spacing: [f32; 3],
1254 #[serde(rename = "Piece")]
1255 pieces: Vec<Piece>,
1256}
1257
1258#[derive(Clone, Debug, PartialEq, Deserialize)]
1259pub struct Grid {
1260 #[serde(rename = "WholeExtent")]
1261 whole_extent: Extent,
1262 #[serde(rename = "Piece")]
1263 pieces: Vec<Piece>,
1264}
1265
1266#[derive(Clone, Debug, PartialEq, Deserialize)]
1267pub struct Unstructured {
1268 #[serde(rename = "Piece")]
1269 pieces: Vec<Piece>,
1270}
1271
1272#[derive(Clone, Debug, PartialEq, Deserialize)]
1273pub struct PImageData {
1274 #[serde(rename = "GhostLevel")]
1275 ghost_level: u32,
1276 #[serde(rename = "WholeExtent")]
1277 whole_extent: Extent,
1278 #[serde(rename = "Origin", deserialize_with = "vector3::deserialize")]
1279 origin: [f32; 3],
1280 #[serde(rename = "Spacing", deserialize_with = "vector3::deserialize")]
1281 spacing: [f32; 3],
1282 #[serde(rename = "PPointData")]
1283 point_data: Option<PAttributeData>,
1284 #[serde(rename = "PCellData")]
1285 cell_data: Option<PAttributeData>,
1286 #[serde(rename = "Piece")]
1287 pieces: Vec<PieceSource>,
1288}
1289
1290#[derive(Clone, Debug, PartialEq, Deserialize)]
1291pub struct PRectilinearGrid {
1292 #[serde(rename = "GhostLevel")]
1293 ghost_level: u32,
1294 #[serde(rename = "WholeExtent")]
1295 whole_extent: Extent,
1296 #[serde(rename = "PPointData")]
1297 point_data: Option<PAttributeData>,
1298 #[serde(rename = "PCellData")]
1299 cell_data: Option<PAttributeData>,
1300 #[serde(rename = "PCoordinates")]
1301 coords: PCoordinates,
1302 #[serde(rename = "Piece")]
1303 pieces: Vec<PieceSource>,
1304}
1305
1306#[derive(Clone, Debug, PartialEq, Deserialize)]
1307pub struct PStructuredGrid {
1308 #[serde(rename = "GhostLevel")]
1309 ghost_level: u32,
1310 #[serde(rename = "WholeExtent")]
1311 whole_extent: Extent,
1312 #[serde(rename = "PPointData")]
1313 point_data: Option<PAttributeData>,
1314 #[serde(rename = "PCellData")]
1315 cell_data: Option<PAttributeData>,
1316 #[serde(rename = "PPoints")]
1317 points: PPoints,
1318 #[serde(rename = "Piece")]
1319 pieces: Vec<PieceSource>,
1320}
1321
1322#[derive(Clone, Debug, PartialEq, Deserialize)]
1323pub struct PUnstructured {
1324 #[serde(rename = "GhostLevel")]
1325 ghost_level: u32,
1326 #[serde(rename = "PPointData")]
1327 point_data: Option<PAttributeData>,
1328 #[serde(rename = "PCellData")]
1329 cell_data: Option<PAttributeData>,
1330 #[serde(rename = "PPoints")]
1331 points: PPoints,
1332 #[serde(rename = "Piece")]
1333 pieces: Vec<PieceSource>,
1334}
1335
1336#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
1337#[serde(rename_all = "PascalCase")]
1338pub struct PieceSource {
1339 extent: Option<Extent>,
1340 source: String,
1341}
1342
1343#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
1345pub struct PAttributeData {
1346 #[serde(rename = "Scalars")]
1347 scalars: Option<String>,
1348 #[serde(rename = "Vectors")]
1349 vectors: Option<String>,
1350 #[serde(rename = "Normals")]
1351 normals: Option<String>,
1352 #[serde(rename = "Tensors")]
1353 tensors: Option<String>,
1354 #[serde(rename = "TCoords")]
1355 tcoords: Option<String>,
1356 #[serde(rename = "$value", default)]
1357 data_array: Vec<PDataArray>,
1358}
1359
1360impl PAttributeData {
1361 pub fn into_model_attributes_meta_data(self) -> Vec<model::ArrayMetaData> {
1362 let PAttributeData {
1363 scalars,
1364 vectors,
1365 normals,
1366 tensors,
1367 tcoords,
1368 data_array,
1369 } = self;
1370
1371 let info = AttributeInfo {
1372 scalars,
1373 vectors,
1374 normals,
1375 tensors,
1376 tcoords,
1377 };
1378
1379 data_array
1380 .into_iter()
1381 .filter_map(|x| x.into_model_array_meta_data(&info).ok())
1382 .collect()
1383 }
1384}
1385
1386#[derive(Clone, Debug, PartialEq)]
1387pub struct PCoordinates([PDataArray; 3]);
1388
1389impl Default for PCoordinates {
1390 fn default() -> PCoordinates {
1391 let coord = PDataArray {
1392 scalar_type: ScalarType::Float32,
1393 name: String::new(),
1394 num_comp: 1,
1395 };
1396 PCoordinates([coord.clone(), coord.clone(), coord])
1397 }
1398}
1399
1400#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1401pub struct PPoints {
1402 #[serde(rename = "PDataArray")]
1403 data: PDataArray,
1404}
1405
1406impl Default for PPoints {
1407 fn default() -> PPoints {
1408 PPoints {
1409 data: PDataArray {
1410 scalar_type: ScalarType::Float32,
1411 name: String::new(),
1412 num_comp: 3,
1413 },
1414 }
1415 }
1416}
1417
1418#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
1420pub enum DataSetType {
1421 ImageData,
1422 PolyData,
1423 RectilinearGrid,
1424 StructuredGrid,
1425 UnstructuredGrid,
1426 PImageData,
1427 PPolyData,
1428 PRectilinearGrid,
1429 PStructuredGrid,
1430 PUnstructuredGrid,
1431}
1432
1433#[derive(Copy, Clone, Debug, PartialEq, Default)]
1434pub struct Extent([i32; 6]);
1435
1436impl From<model::Extent> for Extent {
1437 fn from(ext: model::Extent) -> Extent {
1438 let [x, y, z] = ext.into_ranges();
1439 Extent([
1440 *x.start(),
1441 *x.end(),
1442 *y.start(),
1443 *y.end(),
1444 *z.start(),
1445 *z.end(),
1446 ])
1447 }
1448}
1449
1450impl From<Extent> for model::Extent {
1451 fn from(ext: Extent) -> model::Extent {
1452 let [x0, x1, y0, y1, z0, z1] = ext.0;
1453 model::Extent::Ranges([x0..=x1, y0..=y1, z0..=z1])
1454 }
1455}
1456
1457fn is_zero(n: &u32) -> bool {
1459 *n == 0
1460}
1461
1462#[derive(Clone, Debug, PartialEq, Default, Serialize)]
1463#[serde(rename_all = "PascalCase")]
1464pub struct Piece {
1465 pub extent: Option<Extent>,
1466 #[serde(default)]
1467 pub number_of_points: u32,
1468 #[serde(default, skip_serializing_if = "is_zero")]
1469 pub number_of_cells: u32,
1470 #[serde(default)]
1471 pub number_of_lines: u32,
1472 #[serde(default)]
1473 pub number_of_strips: u32,
1474 #[serde(default)]
1475 pub number_of_polys: u32,
1476 #[serde(default)]
1477 pub number_of_verts: u32,
1478 pub point_data: AttributeData,
1479 pub cell_data: AttributeData,
1480 pub points: Option<Points>,
1481 pub cells: Option<Cells>,
1482 pub verts: Option<Topo>,
1483 pub lines: Option<Topo>,
1484 pub strips: Option<Topo>,
1485 pub polys: Option<Topo>,
1486 pub coordinates: Option<Coordinates>,
1487}
1488
1489#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1490pub struct Points {
1491 #[serde(rename = "DataArray")]
1492 data: DataArray,
1493}
1494
1495impl Points {
1496 pub fn from_io_buffer(buf: model::IOBuffer, ei: EncodingInfo) -> Points {
1497 Points {
1498 data: DataArray::from_io_buffer(buf, ei).with_num_comp(3),
1499 }
1500 }
1501}
1502
1503#[derive(Clone, Debug, PartialEq, Serialize)]
1504pub struct Cells {
1505 #[serde(rename = "DataArray")]
1506 connectivity: DataArray,
1507 #[serde(rename = "DataArray")]
1508 offsets: DataArray,
1509 #[serde(rename = "DataArray")]
1510 types: DataArray,
1511}
1512
1513impl Cells {
1514 fn from_model_cells(cells: model::Cells, ei: EncodingInfo) -> Cells {
1515 let model::Cells { cell_verts, types } = cells;
1516 let (connectivity, offsets) = cell_verts.into_xml();
1517 Cells {
1518 connectivity: DataArray::from_io_buffer(connectivity.into(), ei)
1519 .with_name("connectivity"),
1520 offsets: DataArray::from_io_buffer(offsets.into(), ei).with_name("offsets"),
1521 types: DataArray::from_io_buffer(
1522 types
1523 .into_iter()
1524 .map(|x| x as u8)
1525 .collect::<model::IOBuffer>(),
1526 ei,
1527 )
1528 .with_name("types"),
1529 }
1530 }
1531
1532 pub fn into_model_cells(
1535 self,
1536 l: usize,
1537 appended: Option<&AppendedData>,
1538 ei: EncodingInfo,
1539 ) -> std::result::Result<model::Cells, ValidationError> {
1540 use num_traits::FromPrimitive;
1541
1542 let type_codes: Option<Vec<u8>> = self.types.into_io_buffer(l, appended, ei)?.into();
1543 let type_codes = type_codes.ok_or_else(|| ValidationError::InvalidDataFormat)?;
1544 let types: std::result::Result<Vec<model::CellType>, ValidationError> = type_codes
1545 .into_iter()
1546 .map(|x| model::CellType::from_u8(x).ok_or_else(|| ValidationError::InvalidCellType(x)))
1547 .collect();
1548 let types = types?;
1549
1550 let offsets: Option<Vec<u64>> = self.offsets.into_io_buffer(l, appended, ei)?.cast_into();
1551 let offsets = offsets.ok_or_else(|| ValidationError::InvalidDataFormat)?;
1552
1553 let num_vertices: usize = offsets.last().map(|&x| x as usize).unwrap_or(0);
1555
1556 let connectivity: Option<Vec<u64>> = self
1557 .connectivity
1558 .into_io_buffer(num_vertices, appended, ei)?
1559 .cast_into();
1560 let connectivity = connectivity.ok_or_else(|| ValidationError::InvalidDataFormat)?;
1561 Ok(model::Cells {
1562 cell_verts: model::VertexNumbers::XML {
1563 connectivity,
1564 offsets,
1565 },
1566 types,
1567 })
1568 }
1569}
1570
1571#[derive(Clone, Debug, PartialEq, Serialize)]
1572pub struct Topo {
1573 #[serde(rename = "DataArray")]
1574 connectivity: DataArray,
1575 #[serde(rename = "DataArray")]
1576 offsets: DataArray,
1577}
1578
1579impl Topo {
1580 fn from_model_topo(topo: model::VertexNumbers, ei: EncodingInfo) -> Topo {
1582 let (connectivity, offsets) = topo.into_xml();
1583 Topo {
1584 connectivity: DataArray::from_io_buffer(connectivity.into(), ei)
1585 .with_name("connectivity"),
1586 offsets: DataArray::from_io_buffer(offsets.into(), ei).with_name("offsets"),
1587 }
1588 }
1589
1590 pub fn into_vertex_numbers(
1593 self,
1594 num_elements: usize,
1595 appended: Option<&AppendedData>,
1596 ei: EncodingInfo,
1597 ) -> std::result::Result<model::VertexNumbers, ValidationError> {
1598 let offsets: Option<Vec<u64>> = self
1599 .offsets
1600 .into_io_buffer(num_elements, appended, ei)?
1601 .cast_into();
1602 let offsets = offsets.ok_or_else(|| ValidationError::InvalidDataFormat)?;
1603
1604 let num_values = usize::try_from(*offsets.last().unwrap_or(&0))
1606 .map_err(|_| ValidationError::MissingTopologyOffsets)?;
1607 let connectivity: Option<Vec<u64>> = self
1608 .connectivity
1609 .into_io_buffer(num_values, appended, ei)?
1610 .cast_into();
1611 Ok(model::VertexNumbers::XML {
1612 connectivity: connectivity.ok_or_else(|| ValidationError::InvalidDataFormat)?,
1613 offsets,
1614 })
1615 }
1616}
1617
1618#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
1620pub struct AttributeData {
1621 #[serde(rename = "Scalars")]
1622 pub scalars: Option<String>,
1623 #[serde(rename = "Vectors")]
1624 pub vectors: Option<String>,
1625 #[serde(rename = "Normals")]
1626 pub normals: Option<String>,
1627 #[serde(rename = "Tensors")]
1628 pub tensors: Option<String>,
1629 #[serde(rename = "TCoords")]
1630 pub tcoords: Option<String>,
1631 #[serde(rename = "$value", default)]
1633 pub data_array: Vec<DataArray>,
1634}
1635
1636#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
1637pub struct AttributeInfo {
1638 #[serde(rename = "Scalars")]
1639 pub scalars: Option<String>,
1640 #[serde(rename = "Vectors")]
1641 pub vectors: Option<String>,
1642 #[serde(rename = "Normals")]
1643 pub normals: Option<String>,
1644 #[serde(rename = "Tensors")]
1645 pub tensors: Option<String>,
1646 #[serde(rename = "TCoords")]
1647 pub tcoords: Option<String>,
1648}
1649
1650impl AttributeInfo {
1651 pub fn element_type(&self, name: &str, num_comp: u32) -> model::ElementType {
1653 let AttributeInfo {
1654 scalars,
1655 vectors,
1656 normals,
1657 tensors,
1658 tcoords,
1659 } = self;
1660
1661 if let Some(scalars) = scalars {
1663 if scalars.as_str() == name {
1664 return model::ElementType::Scalars {
1665 num_comp,
1666 lookup_table: None,
1667 };
1668 }
1669 }
1670 if let Some(vectors) = vectors {
1671 if vectors.as_str() == name && num_comp == 3 {
1672 return model::ElementType::Vectors;
1673 }
1674 }
1675 if let Some(normals) = normals {
1676 if normals.as_str() == name && num_comp == 3 {
1677 return model::ElementType::Normals;
1678 }
1679 }
1680 if let Some(tensors) = tensors {
1681 if tensors.as_str() == name && num_comp == 9 {
1682 return model::ElementType::Tensors;
1683 }
1684 }
1685 if let Some(tcoords) = tcoords {
1686 if tcoords.as_str() == name && num_comp < 4 {
1687 return model::ElementType::TCoords(num_comp);
1688 }
1689 }
1690
1691 model::ElementType::Generic(num_comp)
1692 }
1693}
1694
1695impl AttributeData {
1696 pub fn from_model_attributes(attribs: Vec<model::Attribute>, ei: EncodingInfo) -> Self {
1697 let mut attribute_data = AttributeData::default();
1698 for attrib in attribs {
1699 match attrib {
1700 model::Attribute::DataArray(data) => {
1701 match data.elem {
1703 model::ElementType::Scalars { .. } => {
1704 if attribute_data.scalars.is_none() {
1705 attribute_data.scalars = Some(data.name.to_string());
1706 }
1707 }
1708 model::ElementType::Vectors => {
1709 if attribute_data.vectors.is_none() {
1710 attribute_data.vectors = Some(data.name.to_string());
1711 }
1712 }
1713 model::ElementType::Normals => {
1714 if attribute_data.normals.is_none() {
1715 attribute_data.normals = Some(data.name.to_string());
1716 }
1717 }
1718 model::ElementType::TCoords(_) => {
1719 if attribute_data.tcoords.is_none() {
1720 attribute_data.tcoords = Some(data.name.to_string());
1721 }
1722 }
1723 model::ElementType::Tensors => {
1724 if attribute_data.tensors.is_none() {
1725 attribute_data.tensors = Some(data.name.to_string());
1726 }
1727 }
1728 _ => {}
1729 }
1730 attribute_data
1731 .data_array
1732 .push(DataArray::from_model_data_array(data, ei));
1733 }
1734 _ => {}
1736 }
1737 }
1738 attribute_data
1739 }
1740 pub fn into_model_attributes(
1741 self,
1742 n: usize,
1743 appended_data: Option<&AppendedData>,
1744 ei: EncodingInfo,
1745 ) -> Vec<model::Attribute> {
1746 let AttributeData {
1747 scalars,
1748 vectors,
1749 normals,
1750 tensors,
1751 tcoords,
1752 data_array,
1753 } = self;
1754
1755 let info = AttributeInfo {
1756 scalars,
1757 vectors,
1758 normals,
1759 tensors,
1760 tcoords,
1761 };
1762
1763 data_array
1764 .into_iter()
1765 .filter_map(|x| x.into_attribute(n, appended_data, &info, ei).ok())
1766 .collect()
1767 }
1768}
1769
1770#[derive(Clone, Debug, PartialEq)]
1771pub struct Coordinates([DataArray; 3]);
1772
1773impl Coordinates {
1774 pub fn from_model_coords(coords: model::Coordinates, ei: EncodingInfo) -> Self {
1776 Coordinates([
1777 DataArray::from_io_buffer(coords.x, ei),
1778 DataArray::from_io_buffer(coords.y, ei),
1779 DataArray::from_io_buffer(coords.z, ei),
1780 ])
1781 }
1782
1783 pub fn into_model_coordinates(
1786 self,
1787 [nx, ny, nz]: [usize; 3],
1788 appended: Option<&AppendedData>,
1789 ei: EncodingInfo,
1790 ) -> std::result::Result<model::Coordinates, ValidationError> {
1791 let Coordinates([x, y, z]) = self;
1792 let x = x.into_io_buffer(nx, appended, ei)?;
1793 let y = y.into_io_buffer(ny, appended, ei)?;
1794 let z = z.into_io_buffer(nz, appended, ei)?;
1795 Ok(model::Coordinates { x, y, z })
1796 }
1797}
1798
1799#[derive(Copy, Clone, Debug, PartialEq)]
1801pub struct EncodingInfo {
1802 byte_order: model::ByteOrder,
1803 header_type: ScalarType,
1804 compressor: Compressor,
1805 compression_level: u32,
1807}
1808
1809#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1810pub struct PDataArray {
1811 #[serde(rename = "type")]
1812 pub scalar_type: ScalarType,
1813 #[serde(rename = "Name", default)]
1814 pub name: String,
1815 #[serde(rename = "NumberOfComponents", default = "default_num_comp")]
1816 pub num_comp: u32,
1817}
1818
1819impl PDataArray {
1820 pub fn into_model_array_meta_data(
1822 self,
1823 info: &AttributeInfo,
1824 ) -> std::result::Result<model::ArrayMetaData, ValidationError> {
1825 let elem = info.element_type(&self.name, self.num_comp);
1826 Ok(model::ArrayMetaData {
1827 name: self.name,
1828 elem,
1829 scalar_type: self.scalar_type.into(),
1830 })
1831 }
1832}
1833
1834#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1835pub struct DataArray {
1836 #[serde(rename = "type")]
1837 pub scalar_type: ScalarType,
1838 #[serde(rename = "Name", default)]
1839 pub name: String,
1840 pub format: DataArrayFormat,
1841 pub offset: Option<u32>,
1842 #[serde(rename = "NumberOfComponents", default = "default_num_comp")]
1843 pub num_comp: u32,
1844 #[serde(rename = "RangeMin")]
1845 pub range_min: Option<f64>,
1846 #[serde(rename = "RangeMax")]
1847 pub range_max: Option<f64>,
1848 #[serde(rename = "$value", default)]
1849 pub data: Vec<Data>,
1850}
1851
1852impl Default for DataArray {
1854 fn default() -> DataArray {
1855 DataArray {
1856 scalar_type: ScalarType::UInt32,
1857 name: String::new(),
1858 format: DataArrayFormat::Binary,
1859 offset: None,
1860 num_comp: 1,
1861 range_min: None,
1862 range_max: None,
1863 data: vec![Data::default()],
1864 }
1865 }
1866}
1867
1868impl DataArray {
1869 pub fn from_model_data_array(data: model::DataArray, ei: EncodingInfo) -> Self {
1871 let num_comp = u32::try_from(data.num_comp()).unwrap();
1872 DataArray {
1873 name: data.name,
1874 num_comp,
1875 ..DataArray::from_io_buffer(data.data, ei)
1876 }
1877 }
1878 pub fn from_field_array(field: model::FieldArray, ei: EncodingInfo) -> Self {
1880 DataArray {
1881 name: field.name,
1882 num_comp: field.elem,
1883 ..DataArray::from_io_buffer(field.data, ei)
1884 }
1885 }
1886 pub fn from_io_buffer(buf: model::IOBuffer, ei: EncodingInfo) -> Self {
1888 DataArray {
1889 scalar_type: buf.scalar_type().into(),
1890 data: vec![Data::Data(base64::encode(
1891 if ei.header_type == ScalarType::UInt64 {
1892 buf.into_bytes_with_size(ei.byte_order, ei.compressor, ei.compression_level)
1893 } else {
1894 buf.into_bytes_with_size32(ei.byte_order, ei.compressor, ei.compression_level)
1895 },
1897 ))],
1898 ..Default::default()
1899 }
1900 }
1901
1902 pub fn with_name(self, name: impl Into<String>) -> Self {
1904 DataArray {
1905 name: name.into(),
1906 ..self
1907 }
1908 }
1909
1910 pub fn with_num_comp(self, num_comp: u32) -> Self {
1912 DataArray { num_comp, ..self }
1913 }
1914
1915 pub fn into_field_array(
1920 self,
1921 l: usize,
1922 appended: Option<&AppendedData>,
1923 ei: EncodingInfo,
1924 ) -> std::result::Result<model::FieldArray, ValidationError> {
1925 use model::IOBuffer;
1926
1927 let DataArray {
1928 name,
1929 scalar_type,
1930 format,
1931 offset,
1932 num_comp,
1933 data,
1934 ..
1935 } = self;
1936
1937 let num_elements = usize::try_from(num_comp).unwrap() * l;
1940 let header_bytes = ei.header_type.size();
1941
1942 let data = match format {
1943 DataArrayFormat::Appended => {
1944 if let Some(appended) = appended {
1945 let start: usize = offset.unwrap_or(0).try_into().unwrap();
1946 let buf = appended.extract_data(start, num_elements, scalar_type, ei)?;
1947 if buf.len() != num_elements {
1948 return Err(ValidationError::DataArraySizeMismatch {
1949 name,
1950 expected: num_elements,
1951 actual: buf.len(),
1952 });
1953 }
1954 buf
1955 } else {
1956 return Err(ValidationError::InvalidDataFormat);
1957 }
1958 }
1959 DataArrayFormat::Binary => {
1960 let bytes = base64::decode(data[0].clone().into_string())?;
1962 let buf = IOBuffer::from_bytes(
1964 &bytes[header_bytes..],
1965 scalar_type.into(),
1966 ei.byte_order,
1967 )?;
1968 if buf.len() != num_elements {
1969 return Err(ValidationError::DataArraySizeMismatch {
1970 name,
1971 expected: num_elements,
1972 actual: buf.len(),
1973 });
1974 }
1975 buf
1976 }
1977 DataArrayFormat::Ascii => {
1978 let string = data[0].clone().into_string();
1979 let slice = string.as_str();
1980 fn parse_num_seq<E, T>(s: &str) -> std::result::Result<Vec<T>, ValidationError>
1981 where
1982 T: std::str::FromStr<Err = E>,
1983 E: Into<ValidationError>,
1984 {
1985 s.split_ascii_whitespace()
1986 .map(|x| x.parse::<T>().map_err(Into::into))
1987 .collect()
1988 }
1989 let buf = match scalar_type {
1990 ScalarType::Int8 => IOBuffer::I8(parse_num_seq(slice)?),
1991 ScalarType::UInt8 => IOBuffer::U8(parse_num_seq(slice)?),
1992 ScalarType::Int16 => IOBuffer::I16(parse_num_seq(slice)?),
1993 ScalarType::UInt16 => IOBuffer::U16(parse_num_seq(slice)?),
1994 ScalarType::Int32 => IOBuffer::I32(parse_num_seq(slice)?),
1995 ScalarType::UInt32 => IOBuffer::U32(parse_num_seq(slice)?),
1996 ScalarType::Int64 => IOBuffer::I64(parse_num_seq(slice)?),
1997 ScalarType::UInt64 => IOBuffer::U64(parse_num_seq(slice)?),
1998 ScalarType::Float32 => IOBuffer::F32(parse_num_seq(slice)?),
1999 ScalarType::Float64 => IOBuffer::F64(parse_num_seq(slice)?),
2000 };
2001 if buf.len() != num_elements {
2002 return Err(ValidationError::DataArraySizeMismatch {
2003 name,
2004 expected: num_elements,
2005 actual: buf.len(),
2006 });
2007 }
2008 buf
2009 }
2010 };
2011
2012 Ok(model::FieldArray {
2013 name,
2014 data,
2015 elem: num_comp,
2016 })
2017 }
2018
2019 pub fn into_model_data_array(
2024 self,
2025 l: usize,
2026 appended: Option<&AppendedData>,
2027 info: &AttributeInfo,
2028 ei: EncodingInfo,
2029 ) -> std::result::Result<model::DataArray, ValidationError> {
2030 let model::FieldArray { name, data, elem } = self.into_field_array(l, appended, ei)?;
2032
2033 let elem = info.element_type(&name, elem);
2035
2036 Ok(model::DataArray { name, data, elem })
2037 }
2038
2039 pub fn into_io_buffer(
2043 self,
2044 num_elements: usize,
2045 appended: Option<&AppendedData>,
2046 ei: EncodingInfo,
2047 ) -> std::result::Result<model::IOBuffer, ValidationError> {
2048 self.into_field_array(num_elements, appended, ei)
2049 .map(|model::FieldArray { data, .. }| data)
2050 }
2051
2052 pub fn into_attribute(
2053 self,
2054 num_elements: usize,
2055 appended: Option<&AppendedData>,
2056 info: &AttributeInfo,
2057 ei: EncodingInfo,
2058 ) -> std::result::Result<model::Attribute, ValidationError> {
2059 let data_array = self.into_model_data_array(num_elements, appended, info, ei)?;
2060 Ok(model::Attribute::DataArray(data_array))
2061 }
2062}
2063
2064fn default_num_comp() -> u32 {
2065 1
2066}
2067
2068#[derive(Clone, Debug, PartialEq, Serialize)]
2074#[serde(untagged)]
2075pub enum Data {
2076 Meta {
2077 #[serde(rename = "InformationKey")]
2078 information_key: (),
2079 },
2080 Data(String),
2081}
2082
2083impl Data {
2084 fn into_string(self) -> String {
2085 match self {
2086 Data::Meta { .. } => String::new(),
2087 Data::Data(r) => r,
2088 }
2089 }
2090}
2091
2092impl Default for Data {
2093 fn default() -> Data {
2094 Data::Data(String::default())
2095 }
2096}
2097
2098#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
2099pub enum ScalarType {
2100 Int8,
2101 UInt8,
2102 Int16,
2103 UInt16,
2104 Int32,
2105 UInt32,
2106 Int64,
2107 UInt64,
2108 Float32,
2109 Float64,
2110}
2111
2112impl ScalarType {
2113 pub fn size(self) -> usize {
2115 use std::mem::size_of;
2116 match self {
2117 ScalarType::Int8 => size_of::<i8>(),
2118 ScalarType::UInt8 => size_of::<u8>(),
2119 ScalarType::Int16 => size_of::<i16>(),
2120 ScalarType::UInt16 => size_of::<u16>(),
2121 ScalarType::Int32 => size_of::<i32>(),
2122 ScalarType::UInt32 => size_of::<u32>(),
2123 ScalarType::Int64 => size_of::<i64>(),
2124 ScalarType::UInt64 => size_of::<u64>(),
2125 ScalarType::Float32 => size_of::<f32>(),
2126 ScalarType::Float64 => size_of::<f64>(),
2127 }
2128 }
2129}
2130
2131impl From<model::ScalarType> for ScalarType {
2132 fn from(s: model::ScalarType) -> ScalarType {
2133 match s {
2134 model::ScalarType::Bit => ScalarType::UInt8,
2135 model::ScalarType::I8 => ScalarType::Int8,
2136 model::ScalarType::U8 => ScalarType::UInt8,
2137 model::ScalarType::I16 => ScalarType::Int16,
2138 model::ScalarType::U16 => ScalarType::UInt16,
2139 model::ScalarType::I32 => ScalarType::Int32,
2140 model::ScalarType::U32 => ScalarType::UInt32,
2141 model::ScalarType::I64 => ScalarType::Int64,
2142 model::ScalarType::U64 => ScalarType::UInt64,
2143 model::ScalarType::F32 => ScalarType::Float32,
2144 model::ScalarType::F64 => ScalarType::Float64,
2145 }
2146 }
2147}
2148
2149impl From<ScalarType> for model::ScalarType {
2150 fn from(s: ScalarType) -> model::ScalarType {
2151 match s {
2152 ScalarType::Int8 => model::ScalarType::I8,
2153 ScalarType::UInt8 => model::ScalarType::U8,
2154 ScalarType::Int16 => model::ScalarType::I16,
2155 ScalarType::UInt16 => model::ScalarType::U16,
2156 ScalarType::Int32 => model::ScalarType::I32,
2157 ScalarType::UInt32 => model::ScalarType::U32,
2158 ScalarType::Int64 => model::ScalarType::I64,
2159 ScalarType::UInt64 => model::ScalarType::U64,
2160 ScalarType::Float32 => model::ScalarType::F32,
2161 ScalarType::Float64 => model::ScalarType::F64,
2162 }
2163 }
2164}
2165
2166#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
2167#[serde(rename_all = "lowercase")]
2168pub enum DataArrayFormat {
2169 Appended,
2170 Binary,
2171 Ascii,
2172}
2173
2174#[derive(Clone, Debug, PartialEq, Serialize)]
2175pub struct AppendedData {
2176 pub encoding: Encoding,
2178 #[serde(rename = "$value")]
2183 pub data: RawData,
2184}
2185
2186#[derive(Clone, Debug, PartialEq)]
2187pub struct RawData(Vec<u8>);
2188
2189impl Default for RawData {
2190 fn default() -> RawData {
2191 RawData(Vec::new())
2192 }
2193}
2194
2195#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
2197#[serde(rename_all = "lowercase")]
2198pub enum Encoding {
2199 Base64,
2200 Raw,
2201}
2202
2203impl AppendedData {
2204 pub fn extract_data(
2211 &self,
2212 offset: usize,
2213 num_elements: usize,
2214 scalar_type: ScalarType,
2215 ei: EncodingInfo,
2216 ) -> std::result::Result<model::IOBuffer, ValidationError> {
2217 fn to_b64(bytes: usize) -> usize {
2219 4 * (bytes as f64 / 3.0).ceil() as usize
2220 }
2224
2225 let header_bytes = ei.header_type.size();
2226 let expected_num_bytes = num_elements * scalar_type.size();
2227 let mut start = offset;
2228
2229 if ei.compressor == Compressor::None {
2230 return match self.encoding {
2231 Encoding::Raw => {
2232 let given_num_bytes = read_header_num(
2236 &mut std::io::Cursor::new(&self.data.0[start..start + header_bytes]),
2237 ei,
2238 )?;
2239 if given_num_bytes != expected_num_bytes {
2240 return Err(ValidationError::UnexpectedBytesInAppendedData(
2241 expected_num_bytes as u64,
2242 given_num_bytes as u64,
2243 ));
2244 }
2245 start += header_bytes;
2246 let bytes = &self.data.0[start..start + expected_num_bytes];
2247 Ok(model::IOBuffer::from_bytes(
2248 bytes,
2249 scalar_type.into(),
2250 ei.byte_order,
2251 )?)
2252 }
2253 Encoding::Base64 => {
2254 let num_target_bytes = expected_num_bytes + header_bytes;
2256 let num_source_bytes = to_b64(num_target_bytes);
2258 let bytes = &self.data.0[start..start + num_source_bytes];
2259 let bytes = base64::decode(bytes)?;
2260 Ok(model::IOBuffer::from_bytes(
2261 &bytes[header_bytes..],
2262 scalar_type.into(),
2263 ei.byte_order,
2264 )?)
2265 }
2266 };
2267 }
2268
2269 fn read_header_num<R: AsRef<[u8]>>(
2282 header_buf: &mut std::io::Cursor<R>,
2283 ei: EncodingInfo,
2284 ) -> std::result::Result<usize, ValidationError> {
2285 use byteorder::ReadBytesExt;
2286 use byteorder::{BE, LE};
2287 Ok(match ei.byte_order {
2288 model::ByteOrder::LittleEndian => {
2289 if ei.header_type == ScalarType::UInt64 {
2290 header_buf.read_u64::<LE>()? as usize
2291 } else {
2292 header_buf.read_u32::<LE>()? as usize
2293 }
2294 }
2295 model::ByteOrder::BigEndian => {
2296 if ei.header_type == ScalarType::UInt64 {
2297 header_buf.read_u64::<BE>()? as usize
2298 } else {
2299 header_buf.read_u32::<BE>()? as usize
2300 }
2301 }
2302 })
2303 }
2304
2305 #[allow(unused_variables)]
2307 fn get_data_slice<'a, D, B>(
2308 buf: &'a mut Vec<u8>,
2309 mut decode: D,
2310 mut to_b64: B,
2311 data: &'a [u8],
2312 header_bytes: usize,
2313 ei: EncodingInfo,
2314 ) -> std::result::Result<Vec<u8>, ValidationError>
2315 where
2316 D: for<'b> FnMut(
2317 &'b [u8],
2318 &'b mut Vec<u8>,
2319 ) -> std::result::Result<&'b [u8], ValidationError>,
2320 B: FnMut(usize) -> usize,
2321 {
2322 use std::io::Cursor;
2323
2324 let num_blocks = {
2326 let encoded_header = &data[0..to_b64(header_bytes)];
2327 let decoded_header = decode(encoded_header, buf)?;
2328 read_header_num(&mut Cursor::new(decoded_header), ei)?
2329 };
2330
2331 let full_header_bytes = header_bytes * (3 + num_blocks); buf.clear();
2333
2334 let encoded_header = &data[0..to_b64(full_header_bytes)];
2335 let decoded_header = decode(encoded_header, buf)?;
2336 let mut header_cursor = Cursor::new(decoded_header);
2337 let _nb = read_header_num(&mut header_cursor, ei); let _nu = read_header_num(&mut header_cursor, ei);
2339 let _np = read_header_num(&mut header_cursor, ei);
2340 let nc_total = (0..num_blocks).fold(0, |acc, _| {
2341 acc + read_header_num(&mut header_cursor, ei).unwrap_or(0)
2342 });
2343 let num_data_bytes = to_b64(nc_total);
2344 let start = to_b64(full_header_bytes);
2345 buf.clear();
2346 let encoded_data = &data[start..start + num_data_bytes];
2347 let decoded_data = decode(encoded_data, buf)?;
2348
2349 match ei.compressor {
2351 Compressor::ZLib => {
2352 #[cfg(not(feature = "flate2"))]
2353 {
2354 return Err(ValidationError::MissingCompressionLibrary(ei.compressor));
2355 }
2356 #[cfg(feature = "flate2")]
2357 {
2358 use std::io::Read;
2359 let mut out = Vec::new();
2360 let mut decoder = flate2::read::ZlibDecoder::new(decoded_data);
2361 decoder.read_to_end(&mut out)?;
2362 Ok(out)
2363 }
2364 }
2365 Compressor::LZ4 => {
2366 #[cfg(not(feature = "lz4"))]
2367 {
2368 return Err(ValidationError::MissingCompressionLibrary(ei.compressor));
2369 }
2370 #[cfg(feature = "lz4")]
2371 {
2372 Ok(lz4::decompress(decoded_data, num_data_bytes)?)
2373 }
2374 }
2375 Compressor::LZMA => {
2376 #[cfg(not(feature = "xz2"))]
2377 {
2378 return Err(ValidationError::MissingCompressionLibrary(ei.compressor));
2379 }
2380 #[cfg(feature = "xz2")]
2381 {
2382 use std::io::Read;
2383 let mut out = Vec::new();
2384 let mut decoder = xz2::read::XzDecoder::new(decoded_data);
2385 decoder.read_to_end(&mut out)?;
2386 Ok(out)
2387 }
2388 }
2389 _ => {
2390 unreachable!()
2391 }
2392 }
2393 }
2394
2395 let out = match self.encoding {
2396 Encoding::Raw => {
2397 let mut buf = Vec::new();
2398 get_data_slice(
2399 &mut buf,
2400 |header, _| Ok(header),
2401 |x| x,
2402 &self.data.0[offset..],
2403 header_bytes,
2404 ei,
2405 )?
2406 }
2407 Encoding::Base64 => {
2408 let mut buf = Vec::new();
2409 get_data_slice(
2410 &mut buf,
2411 |header, buf| {
2412 base64::decode_config_buf(
2413 header,
2414 base64::STANDARD.decode_allow_trailing_bits(true),
2415 buf,
2416 )?;
2417 Ok(buf.as_slice())
2418 },
2419 to_b64,
2420 &self.data.0[offset..],
2421 header_bytes,
2422 ei,
2423 )?
2424 }
2425 };
2426 Ok(model::IOBuffer::from_byte_vec(
2427 out,
2428 scalar_type.into(),
2429 ei.byte_order,
2430 )?)
2431 }
2432}
2433
2434#[derive(Copy, Clone, Debug, PartialEq)]
2436pub struct FileType {
2437 storage: StorageFormat,
2438 data: DataType,
2439}
2440
2441impl FileType {
2442 pub fn try_from_ext(ext: &str) -> Option<FileType> {
2443 Some(match ext {
2444 "vti" => FileType {
2445 storage: StorageFormat::Serial,
2446 data: DataType::ImageData,
2447 },
2448 "vtp" => FileType {
2449 storage: StorageFormat::Serial,
2450 data: DataType::PolyData,
2451 },
2452 "vtr" => FileType {
2453 storage: StorageFormat::Serial,
2454 data: DataType::RectilinearGrid,
2455 },
2456 "vts" => FileType {
2457 storage: StorageFormat::Serial,
2458 data: DataType::StructuredGrid,
2459 },
2460 "vtu" => FileType {
2461 storage: StorageFormat::Serial,
2462 data: DataType::UnstructuredGrid,
2463 },
2464 "pvti" => FileType {
2465 storage: StorageFormat::Parallel,
2466 data: DataType::ImageData,
2467 },
2468 "pvtp" => FileType {
2469 storage: StorageFormat::Parallel,
2470 data: DataType::PolyData,
2471 },
2472 "pvtr" => FileType {
2473 storage: StorageFormat::Parallel,
2474 data: DataType::RectilinearGrid,
2475 },
2476 "pvts" => FileType {
2477 storage: StorageFormat::Parallel,
2478 data: DataType::StructuredGrid,
2479 },
2480 "pvtu" => FileType {
2481 storage: StorageFormat::Parallel,
2482 data: DataType::UnstructuredGrid,
2483 },
2484 _ => return None,
2485 })
2486 }
2487}
2488
2489impl From<&DataSet> for DataSetType {
2490 fn from(d: &DataSet) -> DataSetType {
2491 match d {
2492 DataSet::ImageData(_) => DataSetType::ImageData,
2493 DataSet::PolyData(_) => DataSetType::PolyData,
2494 DataSet::RectilinearGrid(_) => DataSetType::RectilinearGrid,
2495 DataSet::StructuredGrid(_) => DataSetType::StructuredGrid,
2496 DataSet::UnstructuredGrid(_) => DataSetType::UnstructuredGrid,
2497 DataSet::PImageData(_) => DataSetType::PImageData,
2498 DataSet::PPolyData(_) => DataSetType::PPolyData,
2499 DataSet::PRectilinearGrid(_) => DataSetType::PRectilinearGrid,
2500 DataSet::PStructuredGrid(_) => DataSetType::PStructuredGrid,
2501 DataSet::PUnstructuredGrid(_) => DataSetType::PUnstructuredGrid,
2502 }
2503 }
2504}
2505
2506impl From<DataSetType> for FileType {
2507 fn from(t: DataSetType) -> FileType {
2508 match t {
2509 DataSetType::ImageData => FileType {
2510 storage: StorageFormat::Serial,
2511 data: DataType::ImageData,
2512 },
2513 DataSetType::PolyData => FileType {
2514 storage: StorageFormat::Serial,
2515 data: DataType::PolyData,
2516 },
2517 DataSetType::RectilinearGrid => FileType {
2518 storage: StorageFormat::Serial,
2519 data: DataType::RectilinearGrid,
2520 },
2521 DataSetType::StructuredGrid => FileType {
2522 storage: StorageFormat::Serial,
2523 data: DataType::StructuredGrid,
2524 },
2525 DataSetType::UnstructuredGrid => FileType {
2526 storage: StorageFormat::Serial,
2527 data: DataType::UnstructuredGrid,
2528 },
2529 DataSetType::PImageData => FileType {
2530 storage: StorageFormat::Parallel,
2531 data: DataType::ImageData,
2532 },
2533 DataSetType::PPolyData => FileType {
2534 storage: StorageFormat::Parallel,
2535 data: DataType::PolyData,
2536 },
2537 DataSetType::PRectilinearGrid => FileType {
2538 storage: StorageFormat::Parallel,
2539 data: DataType::RectilinearGrid,
2540 },
2541 DataSetType::PStructuredGrid => FileType {
2542 storage: StorageFormat::Parallel,
2543 data: DataType::StructuredGrid,
2544 },
2545 DataSetType::PUnstructuredGrid => FileType {
2546 storage: StorageFormat::Parallel,
2547 data: DataType::UnstructuredGrid,
2548 },
2549 }
2550 }
2551}
2552
2553#[derive(Copy, Clone, Debug, PartialEq)]
2555pub enum StorageFormat {
2556 Parallel,
2557 Serial,
2558}
2559
2560#[derive(Copy, Clone, Debug, PartialEq)]
2564pub enum DataType {
2565 ImageData,
2566 PolyData,
2567 RectilinearGrid,
2568 StructuredGrid,
2569 UnstructuredGrid,
2570}
2571
2572impl DataType {
2573 pub fn validate(&self, fmt: &[u8]) -> Result<()> {
2574 if match self {
2575 DataType::ImageData => fmt == b"ImageData",
2576 DataType::PolyData => fmt == b"PolyData",
2577 DataType::RectilinearGrid => fmt == b"RectilinearGrid",
2578 DataType::StructuredGrid => fmt == b"StructuredGrid",
2579 DataType::UnstructuredGrid => fmt == b"UnstructuredGrid",
2580 } {
2581 Ok(())
2582 } else {
2583 Err(Error::TypeExtensionMismatch)
2584 }
2585 }
2586
2587 pub fn try_from_byte_str(ty: &[u8]) -> Option<DataType> {
2588 Some(match ty {
2589 b"ImageData" => DataType::ImageData,
2590 b"PolyData" => DataType::PolyData,
2591 b"RectilinearGrid" => DataType::RectilinearGrid,
2592 b"StructuredGrid" => DataType::StructuredGrid,
2593 b"Unstructured" => DataType::UnstructuredGrid,
2594 _ => return None,
2595 })
2596 }
2597}
2598
2599#[derive(Debug)]
2606pub enum ValidationError {
2607 MissingDataSet,
2608 DataSetMismatch,
2609 InvalidDataFormat,
2610 IO(std::io::Error),
2611 Model(model::Error),
2612 ParseFloat(std::num::ParseFloatError),
2613 ParseInt(std::num::ParseIntError),
2614 InvalidCellType(u8),
2615 TooManyElements(u32),
2616 UnexpectedBytesInAppendedData(u64, u64),
2617 MissingTopologyOffsets,
2618 MissingReferencedAppendedData,
2619 MissingCoordinates,
2620 MissingCompressionLibrary(Compressor),
2621 DataArraySizeMismatch {
2622 name: String,
2623 expected: usize,
2624 actual: usize,
2625 },
2626 Base64Decode(base64::DecodeError),
2627 Deserialize(de::DeError),
2628 #[cfg(feature = "lz4")]
2629 LZ4DecompressError(lz4::block::DecompressError),
2630 Unsupported,
2631}
2632
2633#[cfg(feature = "lz4")]
2634impl From<lz4::block::DecompressError> for ValidationError {
2635 fn from(e: lz4::block::DecompressError) -> ValidationError {
2636 ValidationError::LZ4DecompressError(e)
2637 }
2638}
2639
2640impl From<std::io::Error> for ValidationError {
2641 fn from(e: std::io::Error) -> ValidationError {
2642 ValidationError::IO(e)
2643 }
2644}
2645
2646impl From<model::Error> for ValidationError {
2647 fn from(e: model::Error) -> ValidationError {
2648 ValidationError::Model(e)
2649 }
2650}
2651
2652impl From<std::num::ParseFloatError> for ValidationError {
2653 fn from(e: std::num::ParseFloatError) -> ValidationError {
2654 ValidationError::ParseFloat(e)
2655 }
2656}
2657
2658impl From<std::num::ParseIntError> for ValidationError {
2659 fn from(e: std::num::ParseIntError) -> ValidationError {
2660 ValidationError::ParseInt(e)
2661 }
2662}
2663
2664impl From<base64::DecodeError> for ValidationError {
2665 fn from(e: base64::DecodeError) -> ValidationError {
2666 ValidationError::Base64Decode(e)
2667 }
2668}
2669
2670impl From<de::DeError> for ValidationError {
2671 fn from(e: de::DeError) -> ValidationError {
2672 ValidationError::Deserialize(e)
2673 }
2674}
2675
2676impl std::error::Error for ValidationError {
2677 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
2678 match self {
2679 ValidationError::IO(source) => Some(source),
2680 ValidationError::Model(source) => Some(source),
2681 ValidationError::Base64Decode(source) => Some(source),
2682 ValidationError::Deserialize(source) => Some(source),
2683 ValidationError::ParseFloat(source) => Some(source),
2684 ValidationError::ParseInt(source) => Some(source),
2685 #[cfg(feature = "lz4")]
2686 ValidationError::LZ4DecompressError(source) => Some(source),
2687 _ => None,
2688 }
2689 }
2690}
2691impl std::fmt::Display for ValidationError {
2692 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
2693 match self {
2694 ValidationError::MissingDataSet => write!(f, "Missing a data set definition"),
2695 ValidationError::DataSetMismatch => {
2696 write!(f, "VTKFile type doesn't match internal data set definition")
2697 }
2698 ValidationError::InvalidDataFormat => write!(f, "Invalid data format"),
2699 ValidationError::IO(e) => write!(f, "IO Error: {}", e),
2700 ValidationError::Model(e) => write!(f, "Failed to convert model to xml: {}", e),
2701 ValidationError::ParseFloat(e) => write!(f, "Failed to parse a float: {}", e),
2702 ValidationError::ParseInt(e) => write!(f, "Failed to parse an int: {}", e),
2703 ValidationError::InvalidCellType(t) => write!(f, "Invalid cell type: {}", t),
2704 ValidationError::TooManyElements(n) => write!(f, "Too many elements: {}", n),
2705 ValidationError::UnexpectedBytesInAppendedData(expected, actual) => write!(
2706 f,
2707 "Expected {} bytes in appended data array but found {} in header",
2708 expected, actual
2709 ),
2710 ValidationError::MissingTopologyOffsets => write!(f, "Missing topology offsets"),
2711 ValidationError::MissingReferencedAppendedData => {
2712 write!(f, "Appended data is referenced but missing from the file")
2713 }
2714 ValidationError::MissingCoordinates => {
2715 write!(f, "Missing coordinates in rectilinear grid definition")
2716 }
2717 ValidationError::MissingCompressionLibrary(c) => {
2718 write!(
2719 f,
2720 "Cannot compress/decompress data: {:?} compression is unsupported",
2721 c
2722 )
2723 }
2724 ValidationError::DataArraySizeMismatch {
2725 name,
2726 expected,
2727 actual,
2728 } => write!(
2729 f,
2730 "Data array \"{}\" has {} elements, but should have {}",
2731 name, actual, expected
2732 ),
2733 ValidationError::Base64Decode(source) => write!(f, "Base64 decode error: {}", source),
2734 ValidationError::Deserialize(source) => {
2735 write!(f, "Failed to deserialize data: {:?}", source)
2736 }
2737 #[cfg(feature = "lz4")]
2738 ValidationError::LZ4DecompressError(source) => {
2739 write!(f, "LZ4 deompression error: {}", source)
2740 }
2741 ValidationError::Unsupported => write!(f, "Unsupported data set format"),
2742 }
2743 }
2744}
2745
2746impl TryFrom<VTKFile> for model::Vtk {
2747 type Error = Error;
2748 fn try_from(xml: VTKFile) -> std::result::Result<model::Vtk, Self::Error> {
2749 let VTKFile {
2750 version,
2751 byte_order,
2752 compressor,
2753 header_type,
2754 data_set_type,
2755 appended_data,
2756 data_set,
2757 ..
2758 } = xml;
2759
2760 let encoding_info = EncodingInfo {
2761 byte_order,
2762 header_type: header_type.unwrap_or(ScalarType::UInt64),
2763 compressor,
2764 compression_level: 0, };
2766
2767 let appended_data = appended_data.as_ref();
2768
2769 if data_set_type != DataSetType::from(&data_set) {
2772 return Err(ValidationError::DataSetMismatch.into());
2773 }
2774
2775 let convert_num = |n: u32| -> std::result::Result<usize, ValidationError> {
2777 usize::try_from(n).map_err(|_| ValidationError::TooManyElements(n))
2778 };
2779
2780 let attributes =
2781 |npts, ncells, point_data: AttributeData, cell_data: AttributeData| model::Attributes {
2782 point: point_data.into_model_attributes(npts, appended_data, encoding_info),
2783 cell: cell_data.into_model_attributes(ncells, appended_data, encoding_info),
2784 };
2785
2786 let data = match data_set {
2787 DataSet::ImageData(ImageData {
2788 whole_extent,
2789 origin,
2790 spacing,
2791 pieces,
2792 }) => model::DataSet::ImageData {
2793 extent: whole_extent.into(),
2794 origin,
2795 spacing,
2796 meta: None,
2797 pieces: pieces
2798 .into_iter()
2799 .map(
2800 |Piece {
2801 extent,
2802 point_data,
2803 cell_data,
2804 ..
2805 }| {
2806 let extent: model::Extent = extent.unwrap_or(whole_extent).into();
2807 let number_of_points = extent.num_points().try_into().unwrap();
2808 let number_of_cells = extent.num_cells().try_into().unwrap();
2809 model::Piece::Inline(Box::new(model::ImageDataPiece {
2810 extent,
2811 data: attributes(
2812 number_of_points,
2813 number_of_cells,
2814 point_data,
2815 cell_data,
2816 ),
2817 }))
2818 },
2819 )
2820 .collect(),
2821 },
2822 DataSet::PolyData(Unstructured { pieces }) => model::DataSet::PolyData {
2823 meta: None,
2824 pieces: pieces
2825 .into_iter()
2826 .map(
2827 |Piece {
2828 number_of_points,
2829 number_of_lines,
2830 number_of_strips,
2831 number_of_polys,
2832 number_of_verts,
2833 point_data,
2834 cell_data,
2835 points,
2836 verts,
2837 lines,
2838 strips,
2839 polys,
2840 ..
2841 }| {
2842 let number_of_points = convert_num(number_of_points)?;
2843 let number_of_lines = convert_num(number_of_lines)?;
2844 let number_of_strips = convert_num(number_of_strips)?;
2845 let number_of_polys = convert_num(number_of_polys)?;
2846 let number_of_verts = convert_num(number_of_verts)?;
2847 let number_of_cells = number_of_lines
2848 + number_of_strips
2849 + number_of_polys
2850 + number_of_verts;
2851 let verts = verts
2852 .map(|verts| {
2853 verts.into_vertex_numbers(
2854 number_of_verts,
2855 appended_data,
2856 encoding_info,
2857 )
2858 })
2859 .transpose()?;
2860 let lines = lines
2861 .map(|lines| {
2862 lines.into_vertex_numbers(
2863 number_of_lines,
2864 appended_data,
2865 encoding_info,
2866 )
2867 })
2868 .transpose()?;
2869 let strips = strips
2870 .map(|strips| {
2871 strips.into_vertex_numbers(
2872 number_of_strips,
2873 appended_data,
2874 encoding_info,
2875 )
2876 })
2877 .transpose()?;
2878 let polys = polys
2879 .map(|polys| {
2880 polys.into_vertex_numbers(
2881 number_of_polys,
2882 appended_data,
2883 encoding_info,
2884 )
2885 })
2886 .transpose()?;
2887 Ok(model::Piece::Inline(Box::new(model::PolyDataPiece {
2888 points: points.unwrap().data.into_io_buffer(
2889 number_of_points,
2890 appended_data,
2891 encoding_info,
2892 )?,
2893 verts,
2894 lines,
2895 polys,
2896 strips,
2897 data: attributes(
2898 number_of_points,
2899 number_of_cells,
2900 point_data,
2901 cell_data,
2902 ),
2903 })))
2904 },
2905 )
2906 .collect::<Result<Vec<model::Piece<model::PolyDataPiece>>>>()?,
2907 },
2908 DataSet::RectilinearGrid(Grid {
2909 whole_extent,
2910 pieces,
2911 }) => model::DataSet::RectilinearGrid {
2912 extent: whole_extent.into(),
2913 meta: None,
2914 pieces: pieces
2915 .into_iter()
2916 .map(
2917 |Piece {
2918 extent,
2919 coordinates,
2920 point_data,
2921 cell_data,
2922 ..
2923 }| {
2924 let extent: model::Extent = extent.unwrap_or(whole_extent).into();
2925 let number_of_cells = extent.num_cells().try_into().unwrap();
2926 let number_of_points = extent.num_points().try_into().unwrap();
2927 let [nx, ny, nz] = extent.clone().into_dims();
2928 let coords =
2929 coordinates.ok_or_else(|| ValidationError::MissingCoordinates)?;
2930 let coords = coords.into_model_coordinates(
2931 [nx as usize, ny as usize, nz as usize],
2932 appended_data,
2933 encoding_info,
2934 )?;
2935 Ok(model::Piece::Inline(Box::new(
2936 model::RectilinearGridPiece {
2937 extent,
2938 coords,
2939 data: attributes(
2940 number_of_points,
2941 number_of_cells,
2942 point_data,
2943 cell_data,
2944 ),
2945 },
2946 )))
2947 },
2948 )
2949 .collect::<Result<Vec<model::Piece<model::RectilinearGridPiece>>>>()?,
2950 },
2951 DataSet::StructuredGrid(Grid {
2952 whole_extent,
2953 pieces,
2954 }) => model::DataSet::StructuredGrid {
2955 extent: whole_extent.into(),
2956 meta: None,
2957 pieces: pieces
2958 .into_iter()
2959 .map(
2960 |Piece {
2961 extent,
2962 points,
2963 point_data,
2964 cell_data,
2965 ..
2966 }| {
2967 let extent: model::Extent = extent.unwrap_or(whole_extent).into();
2968 let number_of_points = extent.num_points().try_into().unwrap();
2969 let number_of_cells = extent.num_cells().try_into().unwrap();
2970 Ok(model::Piece::Inline(Box::new(model::StructuredGridPiece {
2971 extent,
2972 points: points.unwrap().data.into_io_buffer(
2973 number_of_points,
2974 appended_data,
2975 encoding_info,
2976 )?,
2977 data: attributes(
2978 number_of_points,
2979 number_of_cells,
2980 point_data,
2981 cell_data,
2982 ),
2983 })))
2984 },
2985 )
2986 .collect::<Result<Vec<model::Piece<model::StructuredGridPiece>>>>()?,
2987 },
2988 DataSet::UnstructuredGrid(Unstructured { pieces }) => {
2989 model::DataSet::UnstructuredGrid {
2990 meta: None,
2991 pieces: pieces
2992 .into_iter()
2993 .map(
2994 |Piece {
2995 number_of_points,
2996 number_of_cells,
2997 point_data,
2998 cell_data,
2999 points,
3000 cells: topo,
3001 ..
3002 }| {
3003 let number_of_points = convert_num(number_of_points)?;
3004 let number_of_cells = convert_num(number_of_cells)?;
3005 let cells = topo
3006 .map(|topo| {
3007 topo.into_model_cells(
3008 number_of_cells,
3009 appended_data,
3010 encoding_info,
3011 )
3012 })
3013 .transpose()?
3014 .unwrap_or_default();
3015 Ok(model::Piece::Inline(Box::new(
3016 model::UnstructuredGridPiece {
3017 points: points.unwrap().data.into_io_buffer(
3018 number_of_points,
3019 appended_data,
3020 encoding_info,
3021 )?,
3022 cells,
3023 data: attributes(
3024 number_of_points,
3025 number_of_cells,
3026 point_data,
3027 cell_data,
3028 ),
3029 },
3030 )))
3031 },
3032 )
3033 .collect::<Result<Vec<model::Piece<model::UnstructuredGridPiece>>>>()?,
3034 }
3035 }
3036 DataSet::PImageData(PImageData {
3037 ghost_level,
3038 whole_extent,
3039 origin,
3040 spacing,
3041 point_data,
3042 cell_data,
3043 pieces,
3044 }) => model::DataSet::ImageData {
3045 extent: whole_extent.into(),
3046 origin,
3047 spacing,
3048 meta: Some(Box::new(model::MetaData::ImageData {
3049 ghost_level,
3050 attributes: model::AttributesMetaData {
3051 point_data: point_data
3052 .map(|x| x.into_model_attributes_meta_data())
3053 .unwrap_or_default(),
3054 cell_data: cell_data
3055 .map(|x| x.into_model_attributes_meta_data())
3056 .unwrap_or_default(),
3057 },
3058 })),
3059 pieces: pieces
3060 .into_iter()
3061 .map(|PieceSource { source, extent }| {
3062 Ok(model::Piece::Source(source, extent.map(From::from)))
3063 })
3064 .collect::<Result<Vec<model::Piece<model::ImageDataPiece>>>>()?,
3065 },
3066 DataSet::PPolyData(PUnstructured {
3067 ghost_level,
3068 point_data,
3069 cell_data,
3070 points,
3071 pieces,
3072 }) => model::DataSet::PolyData {
3073 meta: Some(Box::new(model::MetaData::PolyData {
3074 ghost_level,
3075 points_type: points.data.scalar_type.into(),
3076 attributes: model::AttributesMetaData {
3077 point_data: point_data
3078 .map(|x| x.into_model_attributes_meta_data())
3079 .unwrap_or_default(),
3080 cell_data: cell_data
3081 .map(|x| x.into_model_attributes_meta_data())
3082 .unwrap_or_default(),
3083 },
3084 })),
3085 pieces: pieces
3086 .into_iter()
3087 .map(|PieceSource { source, extent }| {
3088 Ok(model::Piece::Source(source, extent.map(From::from)))
3089 })
3090 .collect::<Result<Vec<model::Piece<model::PolyDataPiece>>>>()?,
3091 },
3092 DataSet::PRectilinearGrid(PRectilinearGrid {
3093 ghost_level,
3094 whole_extent,
3095 point_data,
3096 cell_data,
3097 coords,
3098 pieces,
3099 }) => model::DataSet::RectilinearGrid {
3100 extent: whole_extent.into(),
3101 meta: Some(Box::new(model::MetaData::RectilinearGrid {
3102 ghost_level,
3103 coords: [
3104 coords.0[0].scalar_type.into(),
3105 coords.0[1].scalar_type.into(),
3106 coords.0[2].scalar_type.into(),
3107 ],
3108 attributes: model::AttributesMetaData {
3109 point_data: point_data
3110 .map(|x| x.into_model_attributes_meta_data())
3111 .unwrap_or_default(),
3112 cell_data: cell_data
3113 .map(|x| x.into_model_attributes_meta_data())
3114 .unwrap_or_default(),
3115 },
3116 })),
3117 pieces: pieces
3118 .into_iter()
3119 .map(|PieceSource { source, extent }| {
3120 Ok(model::Piece::Source(source, extent.map(From::from)))
3121 })
3122 .collect::<Result<Vec<model::Piece<model::RectilinearGridPiece>>>>()?,
3123 },
3124 DataSet::PStructuredGrid(PStructuredGrid {
3125 ghost_level,
3126 whole_extent,
3127 point_data,
3128 cell_data,
3129 points,
3130 pieces,
3131 }) => model::DataSet::StructuredGrid {
3132 extent: whole_extent.into(),
3133 meta: Some(Box::new(model::MetaData::StructuredGrid {
3134 ghost_level,
3135 points_type: points.data.scalar_type.into(),
3136 attributes: model::AttributesMetaData {
3137 point_data: point_data
3138 .map(|x| x.into_model_attributes_meta_data())
3139 .unwrap_or_default(),
3140 cell_data: cell_data
3141 .map(|x| x.into_model_attributes_meta_data())
3142 .unwrap_or_default(),
3143 },
3144 })),
3145 pieces: pieces
3146 .into_iter()
3147 .map(|PieceSource { source, extent }| {
3148 Ok(model::Piece::Source(source, extent.map(From::from)))
3149 })
3150 .collect::<Result<Vec<model::Piece<model::StructuredGridPiece>>>>()?,
3151 },
3152 DataSet::PUnstructuredGrid(PUnstructured {
3153 ghost_level,
3154 point_data,
3155 cell_data,
3156 points,
3157 pieces,
3158 }) => model::DataSet::UnstructuredGrid {
3159 meta: Some(Box::new(model::MetaData::UnstructuredGrid {
3160 ghost_level,
3161 points_type: points.data.scalar_type.into(),
3162 attributes: model::AttributesMetaData {
3163 point_data: point_data
3164 .map(|x| x.into_model_attributes_meta_data())
3165 .unwrap_or_default(),
3166 cell_data: cell_data
3167 .map(|x| x.into_model_attributes_meta_data())
3168 .unwrap_or_default(),
3169 },
3170 })),
3171 pieces: pieces
3172 .into_iter()
3173 .map(|PieceSource { source, extent }| {
3174 Ok(model::Piece::Source(source, extent.map(From::from)))
3175 })
3176 .collect::<Result<Vec<model::Piece<model::UnstructuredGridPiece>>>>()?,
3177 },
3178 };
3179
3180 Ok(model::Vtk {
3181 version,
3182 byte_order,
3183 title: String::new(),
3184 data,
3185 file_path: None,
3186 })
3187 }
3188}
3189
3190impl model::Vtk {
3191 pub fn try_into_xml_format(
3203 self,
3204 compressor: Compressor,
3205 compression_level: u32,
3206 ) -> Result<VTKFile> {
3207 let model::Vtk {
3208 version,
3209 byte_order,
3210 data: data_set,
3211 file_path,
3212 ..
3213 } = self;
3214
3215 let source_path = file_path.as_ref().map(|p| p.as_ref());
3216
3217 let header_type = ScalarType::UInt64;
3218
3219 let encoding_info = EncodingInfo {
3220 byte_order,
3221 header_type,
3222 compressor,
3223 compression_level,
3224 };
3225
3226 let appended_data = Vec::new();
3227
3228 let data_set = match data_set {
3229 model::DataSet::ImageData {
3230 extent,
3231 origin,
3232 spacing,
3233 pieces,
3234 ..
3236 } => DataSet::ImageData(ImageData {
3237 whole_extent: extent.into(),
3238 origin,
3239 spacing,
3240 pieces: pieces
3241 .into_iter()
3242 .map(|piece| {
3243 let piece_data = piece.into_loaded_piece_data(source_path)?;
3244 let model::ImageDataPiece { extent, data } = piece_data;
3245 Ok(Piece {
3246 extent: Some(extent.into()),
3247 point_data: AttributeData::from_model_attributes(
3248 data.point,
3249 encoding_info,
3250 ),
3251 cell_data: AttributeData::from_model_attributes(
3252 data.cell,
3253 encoding_info,
3254 ),
3255 ..Default::default()
3256 })
3257 })
3258 .collect::<Result<Vec<Piece>>>()?,
3259 }),
3260 model::DataSet::StructuredGrid {
3261 extent,
3262 pieces,
3263 ..
3265 } => DataSet::StructuredGrid(Grid {
3266 whole_extent: extent.into(),
3267 pieces: pieces
3268 .into_iter()
3269 .map(|piece| {
3270 let piece_data = piece.into_loaded_piece_data(source_path)?;
3271 let model::StructuredGridPiece {
3272 extent,
3273 points,
3274 data,
3275 } = piece_data;
3276 Ok(Piece {
3277 extent: Some(extent.into()),
3278 points: Some(Points::from_io_buffer(points, encoding_info)),
3279 point_data: AttributeData::from_model_attributes(
3280 data.point,
3281 encoding_info,
3282 ),
3283 cell_data: AttributeData::from_model_attributes(
3284 data.cell,
3285 encoding_info,
3286 ),
3287 ..Default::default()
3288 })
3289 })
3290 .collect::<Result<Vec<Piece>>>()?,
3291 }),
3292 model::DataSet::RectilinearGrid {
3293 extent,
3294 pieces,
3295 ..
3297 } => DataSet::RectilinearGrid(Grid {
3298 whole_extent: extent.into(),
3299 pieces: pieces
3300 .into_iter()
3301 .map(|piece| {
3302 let piece_data = piece.into_loaded_piece_data(source_path)?;
3303 let model::RectilinearGridPiece {
3304 extent,
3305 coords,
3306 data,
3307 } = piece_data;
3308 Ok(Piece {
3309 extent: Some(extent.into()),
3310 coordinates: Some(Coordinates::from_model_coords(
3311 coords,
3312 encoding_info,
3313 )),
3314 point_data: AttributeData::from_model_attributes(
3315 data.point,
3316 encoding_info,
3317 ),
3318 cell_data: AttributeData::from_model_attributes(
3319 data.cell,
3320 encoding_info,
3321 ),
3322 ..Default::default()
3323 })
3324 })
3325 .collect::<Result<Vec<Piece>>>()?,
3326 }),
3327 model::DataSet::UnstructuredGrid {
3328 pieces,
3329 ..
3331 } => DataSet::UnstructuredGrid(Unstructured {
3332 pieces: pieces
3333 .into_iter()
3334 .map(|piece| {
3335 let piece_data = piece.into_loaded_piece_data(source_path)?;
3336 let num_points = piece_data.num_points();
3337 let model::UnstructuredGridPiece {
3338 points,
3339 cells,
3340 data,
3341 } = piece_data;
3342 Ok(Piece {
3343 number_of_points: u32::try_from(num_points).unwrap(),
3344 number_of_cells: u32::try_from(cells.num_cells()).unwrap(),
3345 points: Some(Points::from_io_buffer(points, encoding_info)),
3346 cells: Some(Cells::from_model_cells(cells, encoding_info)),
3347 point_data: AttributeData::from_model_attributes(
3348 data.point,
3349 encoding_info,
3350 ),
3351 cell_data: AttributeData::from_model_attributes(
3352 data.cell,
3353 encoding_info,
3354 ),
3355 ..Default::default()
3356 })
3357 })
3358 .collect::<Result<Vec<Piece>>>()?,
3359 }),
3360 model::DataSet::PolyData {
3361 pieces,
3362 ..
3364 } => DataSet::PolyData(Unstructured {
3365 pieces: pieces
3366 .into_iter()
3367 .map(|piece| {
3368 let piece_data = piece.into_loaded_piece_data(source_path)?;
3369 let num_points = piece_data.num_points();
3370 let number_of_verts = piece_data.num_verts();
3371 let number_of_lines = piece_data.num_lines();
3372 let number_of_polys = piece_data.num_polys();
3373 let number_of_strips = piece_data.num_strips();
3374 let model::PolyDataPiece {
3375 points,
3376 verts,
3377 lines,
3378 polys,
3379 strips,
3380 data,
3381 } = piece_data;
3382
3383 let verts = verts.map(|topo| Topo::from_model_topo(topo, encoding_info));
3384 let lines = lines.map(|topo| Topo::from_model_topo(topo, encoding_info));
3385 let polys = polys.map(|topo| Topo::from_model_topo(topo, encoding_info));
3386 let strips = strips.map(|topo| Topo::from_model_topo(topo, encoding_info));
3387
3388 Ok(Piece {
3389 number_of_points: u32::try_from(num_points).unwrap(),
3390 number_of_lines: u32::try_from(number_of_lines).unwrap(),
3391 number_of_verts: u32::try_from(number_of_verts).unwrap(),
3392 number_of_polys: u32::try_from(number_of_polys).unwrap(),
3393 number_of_strips: u32::try_from(number_of_strips).unwrap(),
3394 points: Some(Points::from_io_buffer(points, encoding_info)),
3395 verts,
3396 lines,
3397 polys,
3398 strips,
3399 point_data: AttributeData::from_model_attributes(
3400 data.point,
3401 encoding_info,
3402 ),
3403 cell_data: AttributeData::from_model_attributes(
3404 data.cell,
3405 encoding_info,
3406 ),
3407 ..Default::default()
3408 })
3409 })
3410 .collect::<Result<Vec<Piece>>>()?,
3411 }),
3412 model::DataSet::Field { data_array, .. } => {
3413 let max_count = data_array.iter().map(|v| v.len()).max().unwrap_or(0) as i32;
3418 DataSet::ImageData(ImageData {
3419 whole_extent: Extent([0, max_count, 0, 0, 0, 0]),
3420 origin: [0.0; 3],
3421 spacing: [1.0; 3],
3422 pieces: data_array
3423 .into_iter()
3424 .map(|data| Piece {
3425 extent: Some(Extent([0, data.len() as i32, 0, 0, 0, 0])),
3426 cell_data: AttributeData {
3427 data_array: vec![DataArray::from_field_array(data, encoding_info)],
3428 ..Default::default()
3429 },
3430 ..Default::default()
3431 })
3432 .collect(),
3433 })
3434 }
3435 };
3436
3437 let data_set_type = DataSetType::from(&data_set);
3438 let appended_data = if appended_data.is_empty() {
3439 None
3440 } else {
3441 Some(AppendedData {
3442 encoding: Encoding::Raw,
3443 data: RawData(appended_data),
3444 })
3445 };
3446
3447 Ok(VTKFile {
3448 data_set_type,
3449 version,
3450 byte_order,
3451 header_type: Some(header_type),
3452 compressor,
3453 appended_data,
3454 data_set,
3455 })
3456 }
3457}
3458
3459impl TryFrom<model::Vtk> for VTKFile {
3460 type Error = Error;
3461 fn try_from(vtk: model::Vtk) -> Result<VTKFile> {
3462 vtk.try_into_xml_format(Compressor::None, 0)
3463 }
3464}
3465
3466pub(crate) fn import(file_path: impl AsRef<Path>) -> Result<VTKFile> {
3468 let f = std::fs::File::open(file_path)?;
3469 parse(std::io::BufReader::new(f))
3470}
3471
3472fn de_from_reader(reader: impl BufRead) -> Result<VTKFile> {
3473 let mut reader = quick_xml::Reader::from_reader(reader);
3474 reader
3475 .expand_empty_elements(true)
3476 .check_end_names(true)
3477 .trim_text(true)
3478 .trim_text_end(false);
3479 let mut de = de::Deserializer::new(reader);
3480 Ok(VTKFile::deserialize(&mut de)?)
3481}
3482
3483pub(crate) fn parse(reader: impl BufRead) -> Result<VTKFile> {
3485 Ok(de_from_reader(reader)?)
3486}
3487
3488#[cfg(feature = "async_blocked")]
3490pub(crate) async fn import_async(file_path: impl AsRef<Path>) -> Result<VTKFile> {
3491 let f = tokio::fs::File::open(file_path).await?;
3492 Ok(de_from_reader(std::io::BufReader::new(f))?)
3494}
3495
3496pub(crate) fn export(vtk: &VTKFile, file_path: impl AsRef<Path>) -> Result<()> {
3498 let f = std::fs::File::create(file_path)?;
3499 write(vtk, std::io::BufWriter::new(f))
3500}
3501
3502pub(crate) fn write(vtk: &VTKFile, writer: impl Write) -> Result<()> {
3504 Ok(se::to_writer(writer, &vtk)?)
3505}
3506
3507impl std::fmt::Display for VTKFile {
3508 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3509 write!(f, "{}", se::to_string(self).map_err(|_| std::fmt::Error)?)
3510 }
3511}
3512
3513#[cfg(test)]
3514mod tests {
3515 use super::*;
3516
3517 #[test]
3519 fn empty_image_data() {
3520 let image_data = r#"
3521 <VTKFile type="ImageData" version="4.2" byte_order="BigEndian">
3522 <ImageData WholeExtent="0 1 0 1 0 1" Origin="0.0 0.0 0.0" Spacing="0.1 0.1 0.1">
3523 <Piece Extent="0 1 0 1 0 1">
3524 <PointData Scalars="Temperature" Vectors="Velocity"></PointData>
3525 <CellData Tensors="Stress"></CellData>
3526 </Piece>
3527 </ImageData>
3528 </VTKFile>"#;
3529
3530 let vtk: VTKFile = de::from_str(image_data).unwrap();
3531 let as_str = se::to_string(&vtk).unwrap();
3533 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3535 assert_eq!(vtk, vtk_roundtrip);
3536 }
3537
3538 #[test]
3539 fn image_data() {
3540 let image_data = r#"
3541 <VTKFile type="ImageData" version="4.2" byte_order="BigEndian">
3542 <ImageData WholeExtent="0 1 0 1 0 1" Origin="0 0 0" Spacing="0.1 0.1 0.1">
3543 <Piece Extent="0 1 0 1 0 1">
3544 <PointData Scalars="Temperature" Vectors="Velocity">
3545 <DataArray Name="Temperature" type="Float32" format="ascii">0 1 2 3 4 5 6 7 8 9</DataArray>
3546 <DataArray Name="Velocity" type="Float32" NumberOfComponents="3" format="ascii">
3547 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
3548 </DataArray>
3549 </PointData>
3550 <CellData></CellData>
3551 </Piece>
3552 </ImageData>
3553 </VTKFile>"#;
3554
3555 let vtk: VTKFile = de::from_str(image_data).unwrap();
3556 let as_str = se::to_string(&vtk).unwrap();
3558 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3560 assert_eq!(vtk, vtk_roundtrip);
3561 }
3562
3563 #[test]
3564 fn polys() -> Result<()> {
3565 let polys = r#"<Polys>
3566 <DataArray type="Int32" Name="connectivity" format="ascii">
3567 0 1 2 3 4 5 6 7 0 1 5 4 2 3 7 6 0 4 7 3 1 2 6 5
3568 </DataArray>
3569 <DataArray type="Int32" Name="offsets" format="ascii">
3570 4 8 12 16 20 24
3571 </DataArray>
3572 </Polys>"#;
3573
3574 let vtk: Topo = de::from_str(polys)?;
3575 let as_str = se::to_string(&vtk)?;
3577 let vtk_roundtrip = de::from_str(&as_str)?;
3579 assert_eq!(vtk, vtk_roundtrip);
3580 Ok(())
3581 }
3582
3583 #[test]
3584 fn points() -> Result<()> {
3585 let points = r#"
3586 <Points>
3587 <DataArray type="Float32" NumberOfComponents="3" format="ascii">
3588 0 0 0 1 0 0 1 1 0 0 1 0 0 0 1 1 0 1 1 1 1 0 1 1
3589 </DataArray>
3590 </Points>"#;
3591
3592 let vtk: Points = de::from_str(points)?;
3593 let as_str = se::to_string(&vtk)?;
3594 let vtk_roundtrip = de::from_str(&as_str)?;
3595 assert_eq!(vtk, vtk_roundtrip);
3596 Ok(())
3597 }
3598
3599 #[test]
3600 fn piece() -> Result<()> {
3601 let piece = r#"
3602 <Piece NumberOfPoints="8" NumberOfVerts="0" NumberOfLines="0"
3603 NumberOfStrips="0" NumberOfPolys="6">
3604 <Points>
3605 <DataArray type="Float32" NumberOfComponents="3" format="ascii">
3606 0 0 0 1 0 0 1 1 0 0 1 0 0 0 1 1 0 1 1 1 1 0 1 1
3607 </DataArray>
3608 </Points>
3609 <PointData Scalars="my_scalars">
3610 <DataArray type="Float32" Name="my_scalars" format="ascii">
3611 0 1 2 3 4 5 6 7
3612 </DataArray>
3613 </PointData>
3614 <CellData Scalars="cell_scalars" Normals="cell_normals">
3615 <DataArray type="Int32" Name="cell_scalars" format="ascii">
3616 0 1 2 3 4 5
3617 </DataArray>
3618 <DataArray type="Float32" Name="cell_normals"
3619 NumberOfComponents="3" format="ascii">
3620 0 0 -1 0 0 1 0 -1 0 0 1 0 -1 0 0 1 0 0
3621 </DataArray>
3622 </CellData>
3623 <Polys>
3624 <DataArray type="Int32" Name="connectivity" format="ascii">
3625 0 1 2 3 4 5 6 7 0 1 5 4 2 3 7 6 0 4 7 3 1 2 6 5
3626 </DataArray>
3627 <DataArray type="Int32" Name="offsets" format="ascii">
3628 4 8 12 16 20 24
3629 </DataArray>
3630 </Polys>
3631 </Piece>"#;
3632
3633 let vtk: Piece = de::from_str(piece)?;
3634 let as_str = se::to_string(&vtk)?;
3636 let vtk_roundtrip = de::from_str(&as_str)?;
3638 assert_eq!(vtk, vtk_roundtrip);
3639 Ok(())
3640 }
3641
3642 #[test]
3643 fn rectilinear_grid_ascii() -> Result<()> {
3644 let vtk = import("assets/RectilinearGrid_ascii.vtr")?;
3645 let as_str = se::to_string(&vtk).unwrap();
3647 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3649 assert_eq!(vtk, vtk_roundtrip);
3650 Ok(())
3651 }
3652
3653 #[test]
3654 fn rectilinear_grid_compressed() -> Result<()> {
3655 let vtk = import("assets/RectilinearGridCompressed.vtr")?;
3656 let as_str = se::to_string(&vtk).unwrap();
3658 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3660 assert_eq!(vtk, vtk_roundtrip);
3661 Ok(())
3662 }
3663
3664 #[test]
3665 fn rectilinear_grid_appended_base64() -> Result<()> {
3666 let vtk = import("assets/RectilinearGridAppendedBase64.vtr")?;
3667 let as_bytes = se::to_bytes(&vtk)?;
3669 let vtk_roundtrip = de_from_reader(as_bytes.as_slice()).unwrap();
3671 assert_eq!(vtk, vtk_roundtrip);
3672 Ok(())
3673 }
3674
3675 #[test]
3676 fn rectilinear_grid_appended_raw_binary() -> Result<()> {
3677 let vtk = import("assets/RectilinearGridRawBinary.vtr")?;
3678 let as_bytes = se::to_bytes(&vtk)?;
3680 let vtk_roundtrip = de_from_reader(as_bytes.as_slice()).unwrap();
3682 assert_eq!(vtk, vtk_roundtrip);
3683 Ok(())
3684 }
3685
3686 #[test]
3687 fn rectilinear_grid_inline_binary() -> Result<()> {
3688 let vtk = import("assets/RectilinearGridInlineBinary.vtr")?;
3689 let as_bytes = se::to_bytes(&vtk)?;
3691 let vtk_roundtrip = de_from_reader(as_bytes.as_slice()).unwrap();
3693 assert_eq!(vtk, vtk_roundtrip);
3694 Ok(())
3695 }
3696
3697 #[test]
3698 fn single_point() -> Result<()> {
3699 let inline_raw = import("assets/point.vtp")?;
3700 let vtk_inline_raw: model::Vtk = inline_raw.try_into()?;
3701 let vtk_ascii: model::Vtk = import("assets/point_ascii.vtp")?.try_into()?;
3702 assert_eq!(&vtk_inline_raw, &vtk_ascii);
3703 Ok(())
3704 }
3705
3706 #[test]
3708 fn rectilinear_grid_binary_all() -> Result<()> {
3709 let inline_raw = import("assets/RectilinearGridInlineBinary.vtr")?;
3710 let vtk_inline_raw: model::Vtk = inline_raw.try_into()?;
3711 let vtk_app_raw: model::Vtk = import("assets/RectilinearGridRawBinary.vtr")?.try_into()?;
3712 let vtk_app_base64: model::Vtk =
3713 import("assets/RectilinearGridAppendedBase64.vtr")?.try_into()?;
3714 assert_eq!(&vtk_inline_raw, &vtk_app_raw);
3717 assert_eq!(&vtk_inline_raw, &vtk_app_base64);
3718 Ok(())
3719 }
3720
3721 #[test]
3722 fn parallel_rectilinear_grid() -> Result<()> {
3723 let vtk = import("assets/RectilinearGrid.pvtr")?;
3724 let as_str = se::to_string(&vtk).unwrap();
3726 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3728 assert_eq!(vtk, vtk_roundtrip);
3729 Ok(())
3730 }
3731
3732 #[test]
3733 fn poly_cube() -> Result<()> {
3734 let vtk = import("assets/polyEx0.vtp")?;
3735 let as_str = se::to_string(&vtk).unwrap();
3737 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3739 assert_eq!(vtk, vtk_roundtrip);
3740 Ok(())
3741 }
3742
3743 #[test]
3744 fn parallel_cube() -> Result<()> {
3745 let vtk = import("assets/cube.pvtp")?;
3746 let as_str = se::to_string(&vtk).unwrap();
3748 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3750 assert_eq!(vtk, vtk_roundtrip);
3751 Ok(())
3752 }
3753
3754 #[test]
3755 fn hexahedron_appended() -> Result<()> {
3756 let vtk = import("assets/hexahedron.vtu")?;
3757 let as_str = se::to_string(&vtk).unwrap();
3759 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3761 assert_eq!(vtk, vtk_roundtrip);
3762 Ok(())
3763 }
3764
3765 #[test]
3766 fn hexahedron_ascii() -> Result<()> {
3767 let vtk = import("assets/hexahedron_ascii.vtu")?;
3768 let as_str = se::to_string(&vtk).unwrap();
3770 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3772 assert_eq!(vtk, vtk_roundtrip);
3773 Ok(())
3774 }
3775
3776 #[test]
3777 fn hexahedron_inline_binary() -> Result<()> {
3778 let vtk = import("assets/hexahedron_inline_binary.vtu")?;
3779 let as_str = se::to_string(&vtk).unwrap();
3781 let vtk_roundtrip = de::from_str(&as_str).unwrap();
3783 assert_eq!(vtk, vtk_roundtrip);
3784 let vtk_ascii = import("assets/hexahedron_ascii.vtu")?;
3785 let vtk_ascii = model::Vtk::try_from(vtk_ascii.clone())?;
3788 let vtk_binary = model::Vtk::try_from(vtk.clone())?;
3789 assert_eq!(&vtk_ascii, &vtk_binary);
3790 Ok(())
3791 }
3792
3793 #[test]
3794 fn coordinates() -> Result<()> {
3795 let xml = r#"<Coordinates>
3796 <DataArray type="Float32" format="ascii">1 2 3</DataArray>
3797 <DataArray type="Float32" format="ascii">1 2 3</DataArray>
3798 <DataArray type="Float32" format="ascii">1 2 3</DataArray>
3799 </Coordinates>"#;
3800 let coords: Coordinates = de::from_str(xml)?;
3801 let xml_round_trip = se::to_string(&coords)?;
3802 let round_trip: Coordinates = de::from_str(&xml_round_trip)?;
3803 assert_eq!(round_trip, coords);
3804 Ok(())
3805 }
3806
3807 #[test]
3808 fn data_array_appended() -> Result<()> {
3809 let appended_xml = "<DataArray type=\"Float32\" Name=\"vectors\" \
3810 NumberOfComponents=\"3\" format=\"appended\" offset=\"0\"/>";
3811 let appended: DataArray = de::from_str(appended_xml)?;
3812 let appended_xml_round_trip = se::to_string(&appended)?;
3813 let appended_round_trip: DataArray = de::from_str(&appended_xml_round_trip)?;
3814 assert_eq!(appended_round_trip, appended);
3815 Ok(())
3816 }
3817
3818 #[test]
3819 fn data_array_binary() -> Result<()> {
3820 let binary_xml = "<DataArray type=\"Float32\" Name=\"scalars\" format=\"binary\"> \
3821 _bAAAAAAAAAAAAIA/AAAAQAAAQEAAAIBA </DataArray>";
3822
3823 let binary: DataArray = de::from_str(binary_xml)?;
3824 let binary_xml_round_trip = se::to_string(&binary)?;
3826 let binary_round_trip: DataArray = de::from_str(&binary_xml_round_trip)?;
3827 assert_eq!(binary_round_trip, binary);
3828 Ok(())
3829 }
3830
3831 #[test]
3832 fn data_array_ascii() -> Result<()> {
3833 let ascii_xml =
3834 "<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\"> 10 20 30 </DataArray>";
3835
3836 let ascii: DataArray = de::from_str(ascii_xml)?;
3837 let ascii_xml_round_trip = se::to_string(&ascii)?;
3838 let ascii_round_trip: DataArray = de::from_str(&ascii_xml_round_trip)?;
3839 assert_eq!(ascii_round_trip, ascii);
3840 Ok(())
3841 }
3842
3843 #[test]
3846 fn data_array_paraview() -> Result<()> {
3847 let xml = r#"
3848 <DataArray type="Float32" Name="Points" NumberOfComponents="3" format="appended" RangeMin="0" RangeMax="1.7320508076" offset="0" >
3849 <InformationKey name="L2_NORM_FINITE_RANGE" location="vtkDataArray" length="2">
3850 <Value index="0">
3851 0
3852 </Value>
3853 <Value index="1">
3854 1.7320508076
3855 </Value>
3856 </InformationKey>
3857 <InformationKey name="L2_NORM_RANGE" location="vtkDataArray" length="2">
3858 <Value index="0">
3859 0
3860 </Value>
3861 <Value index="1">
3862 1.7320508076
3863 </Value>
3864 </InformationKey>
3865 </DataArray>"#;
3866
3867 let arr: DataArray = de::from_str(xml)?;
3868 let xml_round_trip = se::to_string(&arr)?;
3869 let round_trip: DataArray = de::from_str(&xml_round_trip)?;
3870 assert_eq!(round_trip, arr);
3871 Ok(())
3872 }
3873
3874 #[test]
3879 fn xml_to_vtk_conversion() -> Result<()> {
3880 use model::*;
3881 let xml = import("assets/RectilinearGrid_ascii.vtr")?;
3882 let vtk: Vtk = xml.clone().try_into()?;
3883 assert_eq!(
3884 vtk,
3885 Vtk {
3886 version: Version::new((1, 0)),
3887 byte_order: ByteOrder::LittleEndian,
3888 title: String::new(),
3889 data: DataSet::inline(RectilinearGridPiece {
3890 extent: Extent::Ranges([0..=3, 0..=1, 0..=1]),
3891 coords: Coordinates {
3892 x: vec![-3.0, -1.0, 1.0, 3.0].into(),
3893 y: vec![0.0, 1.0].into(),
3894 z: vec![-1.0, 1.0].into(),
3895 },
3896 data: Attributes {
3897 point: Vec::new(),
3898 cell: vec![
3899 Attribute::scalars("Pressure", 1).with_data(vec![0.0f32, 0.0, 0.0]),
3900 Attribute::generic("Void Volume Fraction", 1)
3901 .with_data(vec![1.0f32, 0.5, 1.0]),
3902 Attribute::generic("X Velocity", 1).with_data(vec![0.0f32, 0.0, 1.4]),
3903 Attribute::generic("Y Velocity", 1).with_data(vec![0.0f32, 0.0, 1.0]),
3904 Attribute::generic("Z Velocity", 1).with_data(vec![0.0f32, 0.5, 0.0]),
3905 ]
3906 }
3907 }),
3908 file_path: None,
3909 }
3910 );
3911 Ok(())
3912 }
3913
3914 #[test]
3915 fn vtk_xml_conversion_round_trip() -> Result<()> {
3916 use model::*;
3917 let xml = import("assets/RectilinearGrid_ascii.vtr")?;
3918 let vtk: Vtk = xml.clone().try_into()?;
3919 let xml_round_trip: VTKFile = vtk.clone().try_into()?;
3920 let vtk_round_trip: Vtk = xml_round_trip.clone().try_into()?;
3921 assert_eq!(vtk.clone(), vtk_round_trip,);
3922 assert_eq!(xml_round_trip.clone(), vtk_round_trip.try_into()?);
3923 Ok(())
3924 }
3925}