vtkio/
basic.rs

1use std::any::Any;
2use std::str::{self, FromStr};
3
4use byteorder::ByteOrder;
5use nom::{digit, IResult, Needed};
6use num_traits::Zero;
7
8use crate::model::IOBuffer;
9
10/// This enum indicates if bulk data is saved in binary.
11/// NOTE: VTK files are saved in ASCII format with bulk data optionally saved in
12/// Binary among ASCII type keywords.  Binary data must be placed into the file
13/// immediately after the "newline" (`\n`) character from the previous ASCII
14/// keyword and parameter sequence. For example point positions and cell indices
15/// and types can be saved in Binary in VTK files.
16#[derive(Copy, Clone, PartialEq, Debug)]
17pub enum FileType {
18    Binary,
19    ASCII,
20}
21
22/// Parse floating point numbers. This macro works for differnt buffer types.
23macro_rules! impl_real_parser {
24    ($name:ident ($buf_type:ty)) => {
25        pub fn $name<T>(input: &$buf_type) -> IResult<&$buf_type, T>
26        where
27            T: FromStr,
28        {
29            flat_map!(
30                input,
31                recognize!(tuple!(
32                    opt!(alt!(tag!("+") | tag!("-"))),
33                    alt_complete!(
34                        delimited!(digit, tag!("."), opt!(digit))
35                            | delimited!(opt!(digit), tag!("."), digit)
36                            | digit
37                    ),
38                    opt!(complete!(tuple!(
39                        alt!(tag!("e") | tag!("E")),
40                        opt!(alt!(tag!("+") | tag!("-"))),
41                        digit
42                    )))
43                )),
44                parse_to!(T)
45            )
46        }
47    };
48}
49
50/*
51 * Parsing routines
52 */
53
54// Consume a spaces and tabs.
55named!(pub whitespace, eat_separator!(" \t"));
56
57/// Whitespace separator `sp`. Like `ws` but excludes new-lines.
58macro_rules! sp (
59    ($i:expr, $($args:tt)*) => ( {
60            sep!($i, whitespace, $($args)*)
61        })
62    );
63
64// Parse a floating point number from a byte array.
65// This extends `nom`'s implementation by allowing floats without a decimal point (e.g. `3e3`).
66impl_real_parser!(real([u8]));
67
68/// Parse a number in binary form from a byte array.
69pub trait FromBinary
70where
71    Self: Sized,
72{
73    fn from_binary<T: ByteOrder>(input: &[u8]) -> IResult<&[u8], Self>;
74}
75
76macro_rules! impl_from_binary {
77    ($type:ty) => {
78        impl FromBinary for $type {
79            fn from_binary<T: ByteOrder>(input: &[u8]) -> IResult<&[u8], $type> {
80                debug_assert_eq!(::std::mem::size_of::<$type>(), 1);
81                if input.len() < 1 {
82                    IResult::Incomplete(Needed::Size(1))
83                } else {
84                    IResult::Done(&input[1..], input[0] as $type)
85                }
86            }
87        }
88    };
89    ($type:ty, $read_fn:ident) => {
90        impl FromBinary for $type {
91            fn from_binary<T: ByteOrder>(input: &[u8]) -> IResult<&[u8], $type> {
92                let size = ::std::mem::size_of::<$type>();
93                if input.len() < size {
94                    IResult::Incomplete(Needed::Size(size))
95                } else {
96                    let res = T::$read_fn(input);
97                    IResult::Done(&input[size..], res)
98                }
99            }
100        }
101    };
102}
103impl_from_binary!(u8);
104impl_from_binary!(i8);
105impl_from_binary!(u16, read_u16);
106impl_from_binary!(i16, read_i16);
107impl_from_binary!(u32, read_u32);
108impl_from_binary!(i32, read_i32);
109impl_from_binary!(u64, read_u64);
110impl_from_binary!(i64, read_i64);
111impl_from_binary!(f32, read_f32);
112impl_from_binary!(f64, read_f64);
113
114pub trait FromAscii
115where
116    Self: Sized,
117{
118    fn from_ascii(input: &[u8]) -> IResult<&[u8], Self>;
119}
120
121macro_rules! impl_from_ascii {
122    ($type:ty, $fn:ident) => {
123        impl FromAscii for $type {
124            fn from_ascii(input: &[u8]) -> IResult<&[u8], $type> {
125                $fn(input)
126            }
127        }
128    };
129}
130impl_from_ascii!(u8, unsigned);
131impl_from_ascii!(i8, integer);
132impl_from_ascii!(u16, unsigned);
133impl_from_ascii!(i16, integer);
134impl_from_ascii!(u32, unsigned);
135impl_from_ascii!(i32, integer);
136impl_from_ascii!(u64, unsigned);
137impl_from_ascii!(i64, integer);
138impl_from_ascii!(f32, real);
139impl_from_ascii!(f64, real);
140
141/// Parse a formatted unsigned integer.
142pub fn unsigned<T>(input: &[u8]) -> IResult<&[u8], T>
143where
144    T: FromStr,
145{
146    map_res!(input, map_res!(digit, str::from_utf8), FromStr::from_str)
147}
148
149/// Parse a formatted signed integer.
150pub fn integer<T>(input: &[u8]) -> IResult<&[u8], T>
151where
152    T: FromStr,
153{
154    flat_map!(
155        input,
156        recognize!(tuple!(opt!(alt!(tag!("+") | tag!("-"))), digit)),
157        parse_to!(T)
158    )
159}
160
161// A trait identifying all scalar types supported by VTK.
162pub trait Scalar: FromStr + FromAscii + FromBinary {}
163macro_rules! impl_scalar {
164    ($($type:ty),* $(,)*) => {
165        $(
166            impl Scalar for $type {}
167        )*
168    }
169}
170
171impl_scalar!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
172
173/// Parse a set of typed numbers into an `IOBuffer`.
174pub fn parse_data_buffer<T, BO>(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], IOBuffer>
175where
176    T: Scalar + Any + Clone + Zero + ::std::fmt::Debug,
177    BO: ByteOrder,
178    IOBuffer: From<Vec<T>>,
179{
180    parse_data_vec::<T, BO>(input, n, ft).map(IOBuffer::from)
181}
182
183/// Parse a set of unsigned bytes into an `IOBuffer`.
184pub fn parse_data_buffer_u8(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], IOBuffer> {
185    parse_data_vec_u8(input, n, ft).map(IOBuffer::from)
186}
187
188/// Parse a set of signed bytes into an `IOBuffer`.
189pub fn parse_data_buffer_i8(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], IOBuffer> {
190    parse_data_vec_i8(input, n, ft).map(IOBuffer::from)
191}
192
193/// Parse a set of bits into an `IOBuffer`.
194pub fn parse_data_bit_buffer(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], IOBuffer> {
195    parse_data_bit_vec(input, n, ft).map(IOBuffer::from)
196}
197
198/// Parse a set of typed numbers into a `Vec`.
199pub fn parse_data_vec<T, BO>(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], Vec<T>>
200where
201    T: Scalar,
202    BO: ByteOrder,
203{
204    match ft {
205        FileType::ASCII => many_m_n!(input, n, n, ws!(T::from_ascii)),
206        FileType::Binary => many_m_n!(input, n, n, T::from_binary::<BO>),
207    }
208}
209
210/// Parse a set of unsigned bytes into a `Vec`.
211pub fn parse_data_vec_u8(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], Vec<u8>> {
212    match ft {
213        FileType::ASCII => many_m_n!(input, n, n, ws!(u8::from_ascii)),
214        FileType::Binary => {
215            // If expecting bytes, byte order doesn't matter, just return the entire block.
216            if input.len() < n {
217                IResult::Incomplete(Needed::Size(n))
218            } else {
219                IResult::Done(&input[n..], input[0..n].to_vec())
220            }
221        }
222    }
223}
224
225/// Parse a set of signed bytes into a `Vec`.
226pub fn parse_data_vec_i8(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], Vec<i8>> {
227    match ft {
228        FileType::ASCII => many_m_n!(input, n, n, ws!(i8::from_ascii)),
229        FileType::Binary => {
230            // If expecting bytes, byte order doesn't matter, just return the entire block.
231            // Unsafety is used here to avoid having to iterate.
232            if input.len() < n {
233                IResult::Incomplete(Needed::Size(n))
234            } else {
235                // SAFETY: All u8 are representable as i8 and both are 8 bits.
236                IResult::Done(
237                    &input[n..],
238                    unsafe { std::slice::from_raw_parts(input[0..n].as_ptr() as *const i8, n) }
239                        .to_vec(),
240                )
241            }
242        }
243    }
244}
245
246pub fn parse_data_bit_vec(input: &[u8], n: usize, ft: FileType) -> IResult<&[u8], Vec<u8>> {
247    match ft {
248        FileType::ASCII => many_m_n!(input, n, n, ws!(u8::from_ascii)),
249        FileType::Binary => {
250            let nbytes = n / 8 + if n % 8 == 0 { 0 } else { 1 };
251            if input.len() < nbytes {
252                IResult::Incomplete(Needed::Size(nbytes))
253            } else {
254                IResult::Done(&input[nbytes..], input[0..nbytes].to_vec())
255            }
256        }
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use super::*;
263    use byteorder::BigEndian;
264    use nom::IResult;
265
266    #[test]
267    fn can_parse_float() {
268        assert_eq!(real::<f32>(&b"-0.00005"[..]).unwrap().1, -0.00005);
269        assert_eq!(real::<f32>(&b"4."[..]).unwrap().1, 4.0);
270        assert_eq!(real::<f32>(&b"3"[..]).unwrap().1, 3.0);
271        assert_eq!(real::<f32>(&b"-.3"[..]).unwrap().1, -0.3);
272        assert_eq!(real::<f32>(&b"3e3"[..]).unwrap().1, 3000.0);
273        assert_eq!(real::<f32>(&b"-3.2e2"[..]).unwrap().1, -320.0);
274    }
275    #[test]
276    fn can_parse_int() {
277        assert_eq!(integer::<i32>(&b"-1"[..]).unwrap().1, -1);
278        assert_eq!(integer::<i32>(&b"1"[..]).unwrap().1, 1);
279        assert_eq!(integer::<i32>(&b"43242"[..]).unwrap().1, 43242);
280        assert_eq!(integer::<u8>(&b"255"[..]).unwrap().1, 255);
281    }
282    #[test]
283    fn can_parse_binary_float() {
284        assert_eq!(
285            f32::from_binary::<BigEndian>(&[0u8, 0, 0, 0]).unwrap().1,
286            0.0_f32
287        );
288        assert_eq!(
289            f32::from_binary::<BigEndian>(&[62u8, 32, 0, 0]).unwrap().1,
290            0.15625_f32
291        );
292    }
293    #[test]
294    fn data_test() {
295        let f = parse_data_buffer::<f32, BigEndian>("".as_bytes(), 0, FileType::ASCII);
296        assert_eq!(
297            f,
298            IResult::Done("".as_bytes(), IOBuffer::from(Vec::<f32>::new()))
299        );
300        let f = parse_data_buffer::<f32, BigEndian>("3".as_bytes(), 1, FileType::ASCII);
301        assert_eq!(
302            f,
303            IResult::Done("".as_bytes(), IOBuffer::from(vec![3.0f32]))
304        );
305        let f = parse_data_buffer::<f32, BigEndian>("3 32".as_bytes(), 2, FileType::ASCII);
306        assert_eq!(
307            f,
308            IResult::Done("".as_bytes(), IOBuffer::from(vec![3.0f32, 32.0]))
309        );
310        let f = parse_data_buffer::<f32, BigEndian>("3 32 32.0 4e3".as_bytes(), 4, FileType::ASCII);
311        assert_eq!(
312            f,
313            IResult::Done(
314                "".as_bytes(),
315                IOBuffer::from(vec![3.0f32, 32.0, 32.0, 4.0e3])
316            )
317        );
318        let f = parse_data_buffer::<f64, BigEndian>("3 32 32.0 4e3".as_bytes(), 4, FileType::ASCII);
319        assert_eq!(
320            f,
321            IResult::Done(
322                "".as_bytes(),
323                IOBuffer::from(vec![3.0f64, 32.0, 32.0, 4.0e3])
324            )
325        );
326    }
327}