vtkio/
xml.rs

1//!
2//! Internal APIs for dealing with XML VTK file types.
3//!
4//! See [VTK XML Format
5//! Reference](https://lorensen.github.io/VTKExamples/site/VTKFileFormats/#xml-file-formats) for
6//! details on the xml format.
7//!
8
9mod 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    //MissingAttribute(AttribName),
35    //InvalidAttributeValueFor(AttribName),
36    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::InvalidAttributeValueFor(attrib) => {
56            //    write!(f, "Invalid attribute value for {}", attrib)
57            //}
58            //Error::MissingAttribute(attrib) => write!(f, "Missing attribute: {}", attrib),
59            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
119/// Module used to serialize and deserialize the compressor enum.
120mod 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
172/// Module used to serialize and deserialize whitespace separated sequences of 6 integers.
173mod 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
231/// Module used to serialize and deserialize whitespace separated sequences of 3 floats.
232mod 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
297/// Module used to serialize and deserialize version numbers like `4.1` with a major and minor
298/// parts.
299mod 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            // TODO: These should not be positional. (See VTKFile deserialization for reference)
439            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    // A helper function to detect whitespace bytes.
484    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    /*
501     * Data in a DataArray element
502     */
503
504    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            // Ignore InformationKey fields.
518            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    /* Serialization of Data is derived. */
531
532    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    /*
542     * AppendedData Element
543     */
544    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                // In base64 encoding we can trim whitespace from the end.
578                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    /* Serialization of AppendedData is derived. */
590
591    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    /*
601     * Data in an AppendedData element
602     */
603
604    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            // Skip the first byte which always corresponds to the preceeding underscore
615            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/*
1186 * The following defines the VTK XML model as Rust types, which is then serialized and deserialized
1187 * using serde.
1188 *
1189 * This model is exported in case users prefer to work with a bare bones VTK XML model without
1190 * additional handling of Legacy formats or on demand loading of "Parallel" XML files.
1191 */
1192
1193#[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>, // Assumed to be UInt32 if missing
1199    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/// Contents and attributes of the `PPointData` XML element.
1344#[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/// The attribute on VTKFile indicating the contained data set type.
1419#[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
1457// Helper for serializing number_of_cells
1458fn 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    /// Given the expected number of elements and an optional appended data,
1533    /// converts this `Topo` struct into a `mode::VertexNumbers` type.
1534    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        // Count the total number of vertices we expect in the connectivity array.
1554        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    /// Convert model topology type into `Topo`.
1581    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    /// Given the expected number of elements and an optional appended data,
1591    /// converts this `Topo` struct into a `mode::VertexNumbers` type.
1592    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        // Get the number of elements in the connectivity array from the last offset.
1605        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/// Attribute data corresponding to the `PointData` or `CellData` elements.
1619#[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    /// The (possibly empty) collection of data arrays representing individual attributes.
1632    #[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    /// Determine an appropriate `model::ElementType` for the given attribute name and number of components.
1652    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        // Pick the element type greedily.
1662        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                    // Only pick the first found attribute as the active one.
1702                    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                // Field attributes are not supported, they are simply ignored.
1735                _ => {}
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    /// Construct `Coordinates` from `model::Coordinates`.
1775    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    /// Given the expected number of elements and an optional appended data,
1784    /// converts this struct into a `mode::Coordinates` type.
1785    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/// A helper struct indicating how to read and write binary data stored in `DataArray`s.
1800#[derive(Copy, Clone, Debug, PartialEq)]
1801pub struct EncodingInfo {
1802    byte_order: model::ByteOrder,
1803    header_type: ScalarType,
1804    compressor: Compressor,
1805    // Note that compression level is meaningless during decoding.
1806    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    /// Convert this data array descriptor into a `model::ArrayMetaData` type.
1821    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
1852// For dummy arrays useful in debugging.
1853impl 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    /// Construct a binary `DataArray` from a given `model::DataArray`.
1870    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    /// Construct a binary `DataArray` from a given `model::FieldArray`.
1879    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    /// Construct a binary `DataArray` from a given [`model::IOBuffer`].
1887    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                    // Older vtk Versions
1896                },
1897            ))],
1898            ..Default::default()
1899        }
1900    }
1901
1902    /// Returns the given `DataArray` with name set to `name`.
1903    pub fn with_name(self, name: impl Into<String>) -> Self {
1904        DataArray {
1905            name: name.into(),
1906            ..self
1907        }
1908    }
1909
1910    /// Returns the given `DataArray` with the given number of components `num_comp`.
1911    pub fn with_num_comp(self, num_comp: u32) -> Self {
1912        DataArray { num_comp, ..self }
1913    }
1914
1915    /// Convert this data array into a `model::FieldArray` type.
1916    ///
1917    /// The given arguments are the number of elements (not bytes) in the expected output
1918    /// buffer and an optional appended data reference.
1919    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        //eprintln!("name = {:?}", &name);
1938
1939        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                // First byte gives the bytes
1961                let bytes = base64::decode(data[0].clone().into_string())?;
1962                //eprintln!("{:?}", &bytes[..header_bytes]);
1963                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    /// Convert this data array into a `model::DataArray` type.
2020    ///
2021    /// The given arguments are the number of elements (not bytes) in the expected output
2022    /// buffer and an optional appended data reference.
2023    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        // First convert into a field array.
2031        let model::FieldArray { name, data, elem } = self.into_field_array(l, appended, ei)?;
2032
2033        // Then determine an appropriate element type.
2034        let elem = info.element_type(&name, elem);
2035
2036        Ok(model::DataArray { name, data, elem })
2037    }
2038
2039    /// Convert this data array into an `IOBuffer`.
2040    ///
2041    /// This is the same as `into_field_array` but only keeps the `IOBuffer` part.
2042    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/// The contents of a `DataArray` element.
2069///
2070/// Some VTK tools like ParaView may produce undocumented tags inside this
2071/// element. We capture and ignore those via the `Meta` variant. Otherwise this
2072/// is treated as a data string.
2073#[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    /// Returns the number of bytes of the corresponding scalar type.
2114    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    /// Encoding used in the `data` field.
2177    pub encoding: Encoding,
2178    /// Raw data in binary or base64 format.
2179    ///
2180    /// The underscore present in the XML files is added and removed during
2181    /// serialization and deserialization respectively.
2182    #[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/// Supported binary encoding formats.
2196#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
2197#[serde(rename_all = "lowercase")]
2198pub enum Encoding {
2199    Base64,
2200    Raw,
2201}
2202
2203impl AppendedData {
2204    /// Extract the decompressed and unencoded raw bytes from appended data.
2205    ///
2206    /// The data is expected to begin at `offset` from the beginning of the stored data array.
2207    ///
2208    /// The expected number of elements is given by `num_elements`.
2209    /// The given encoding info specifies the format of the data header and how the data is compressed.
2210    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        // Convert number of target bytes to number of chars in base64 encoding.
2218        fn to_b64(bytes: usize) -> usize {
2219            4 * (bytes as f64 / 3.0).ceil() as usize
2220            //(bytes * 4 + 1) / 3 + match bytes % 3 {
2221            //    1 => 2, 2 => 1, _ => 0
2222            //}
2223        }
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                    // The first 64/32 bits gives the size of each component in bytes
2233                    // Since data here is uncompressed we can predict exactly how many bytes to expect
2234                    // We check this below.
2235                    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                    // Add one integer that specifies the size of each component in bytes.
2255                    let num_target_bytes = expected_num_bytes + header_bytes;
2256                    // Compute how many base64 chars we need to decode l elements.
2257                    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        // Compressed data has a more complex header.
2270        // The data is organized as [nb][nu][np][nc_1]...[nc_nb][Data]
2271        // Where
2272        //   [nb] = Number of blocks in the data array
2273        //   [nu] = Block size before compression
2274        //   [np] = Size of the last partial block before compression (zero if it is not needed)
2275        //   [nc_i] = Size in bytes of block i after compression
2276        // See https://vtk.org/Wiki/VTK_XML_Formats for details.
2277        // In this case we dont know how many bytes are in the data array so we must first read
2278        // this information from a header.
2279
2280        // Helper function to read a single header number, which depends on the encoding parameters.
2281        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 this warning which are fired when compression is disabled.
2306        #[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            // First we need to determine the number of blocks stored.
2325            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); // nb + nu + np + sum_i nc_i
2332            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); // We already know the number of blocks
2338            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            // Now that the data is decoded, what is left is to decompress it.
2350            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/// A file type descriptor of a XML VTK data file.
2435#[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/// The storage format of a given XML VTK file.
2554#[derive(Copy, Clone, Debug, PartialEq)]
2555pub enum StorageFormat {
2556    Parallel,
2557    Serial,
2558}
2559
2560/// A data type representing particular structured or unstructured data.
2561///
2562/// Each of these can be stored either in Parallel or Serial format.
2563#[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/*
2600 * Implement conversion from VTKFile which is almost verbatim what the XML file represents, and
2601 * Vtk, which is the unified model supporting Legacy format as well as loading of referenced
2602 * pieces.
2603 */
2604
2605#[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, // This is meaningless when decoding
2765        };
2766
2767        let appended_data = appended_data.as_ref();
2768
2769        // Validate that the expected data set type corresponds to the actual
2770        // stored data set.
2771        if data_set_type != DataSetType::from(&data_set) {
2772            return Err(ValidationError::DataSetMismatch.into());
2773        }
2774
2775        // Convenience function to convert u32 to usize without panics.
2776        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    /// Converts the given Vtk model into an XML format represented by `VTKFile`.
3192    ///
3193    /// This function allows one to specify the compression level (0-9):
3194    /// ```verbatim
3195    /// 0 -> No compression
3196    /// 1 -> Fastest write
3197    /// ...
3198    /// 5 -> Balanced performance
3199    /// ...
3200    /// 9 -> Slowest but smallest file size.
3201    /// ```
3202    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                //meta,
3235                ..
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                //meta,
3264                ..
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                //meta,
3296                ..
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                //meta,
3330                ..
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                //meta,
3363                ..
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                // Convert a legacy field data set into image data with a piece for each data_array.
3414                // If this becomes usefule we can try to group the arrays into
3415                // chunks of the same length and put those into a single piece
3416                // at different attributes.
3417                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
3466/// Import an XML VTK file from the specified path.
3467pub(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
3483/// Parse an XML VTK file from the given reader.
3484pub(crate) fn parse(reader: impl BufRead) -> Result<VTKFile> {
3485    Ok(de_from_reader(reader)?)
3486}
3487
3488/// Import an XML VTK file from the specified path.
3489#[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    // Blocked on async support from quick-xml (e.g. https://github.com/tafia/quick-xml/pull/233)
3493    Ok(de_from_reader(std::io::BufReader::new(f))?)
3494}
3495
3496/// Export an XML VTK file to the specified path.
3497pub(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
3502/// Write an XML VTK file to the specified writer.
3503pub(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    // Verify that xmls with default empty meshes files work
3518    #[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        //eprintln!("{:#?}", &vtk);
3532        let as_str = se::to_string(&vtk).unwrap();
3533        //eprintln!("{:?}", &as_str);
3534        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        //eprintln!("{:#?}", &vtk);
3557        let as_str = se::to_string(&vtk).unwrap();
3558        //eprintln!("{}", &as_str);
3559        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        //eprintln!("{:#?}", &vtk);
3576        let as_str = se::to_string(&vtk)?;
3577        //eprintln!("{}", &as_str);
3578        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        //eprintln!("{:#?}", &vtk);
3635        let as_str = se::to_string(&vtk)?;
3636        //eprintln!("{}", &as_str);
3637        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        //eprintln!("{:#?}", &vtk);
3646        let as_str = se::to_string(&vtk).unwrap();
3647        //eprintln!("{}", &as_str);
3648        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        //eprintln!("{:#?}", &vtk);
3657        let as_str = se::to_string(&vtk).unwrap();
3658        //eprintln!("{}", &as_str);
3659        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        //eprintln!("{:#?}", &vtk);
3668        let as_bytes = se::to_bytes(&vtk)?;
3669        //eprintln!("{:?}", &as_bytes);
3670        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        //eprintln!("{:#?}", &vtk);
3679        let as_bytes = se::to_bytes(&vtk)?;
3680        //eprintln!("{:?}", &as_bytes);
3681        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        //eprintln!("{:#?}", &vtk);
3690        let as_bytes = se::to_bytes(&vtk)?;
3691        //eprintln!("{:?}", &as_bytes);
3692        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    // Ensure that all binary formats produce identical (lossless) instances.
3707    #[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        //let vtk = import("assets/RectilinearGridCompressed.vtr")?;
3715        //let vtk = import("assets/RectilinearGrid.pvtr")?;
3716        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        //eprintln!("{:#?}", &vtk);
3725        let as_str = se::to_string(&vtk).unwrap();
3726        //eprintln!("{}", &as_str);
3727        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        //eprintln!("{:#?}", &vtk);
3736        let as_str = se::to_string(&vtk).unwrap();
3737        //eprintln!("{}", &as_str);
3738        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        //eprintln!("{:#?}", &vtk);
3747        let as_str = se::to_string(&vtk).unwrap();
3748        //eprintln!("{}", &as_str);
3749        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        //eprintln!("{:#?}", &vtk);
3758        let as_str = se::to_string(&vtk).unwrap();
3759        //eprintln!("{}", &as_str);
3760        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        //eprintln!("{:#?}", &vtk);
3769        let as_str = se::to_string(&vtk).unwrap();
3770        //eprintln!("{}", &as_str);
3771        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        //eprintln!("{:#?}", &vtk);
3780        let as_str = se::to_string(&vtk).unwrap();
3781        //eprintln!("{}", &as_str);
3782        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        //eprintln!("{:#?}", &vtk_ascii);
3786        // Verify that the ascii cube is the same as the inline binary cube.
3787        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        //eprintln!("bin:{:?}", binary.data);
3825        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    // An example of a data array produced by paraview.
3844    // The parser should effectively ignore unrecognized fields.
3845    #[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    /*
3875     * Test conversion facilities
3876     */
3877
3878    #[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}