ndarray_npy/npy/elements/
primitive.rs

1//! Trait implementations for primitive element types.
2
3use super::{bytes_as_mut_slice, bytes_as_slice, check_for_extra_bytes};
4use crate::{ReadDataError, ReadableElement, ViewDataError, ViewElement, ViewMutElement};
5use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
6use py_literal::Value as PyValue;
7use std::error::Error;
8use std::fmt;
9use std::io;
10use std::mem;
11
12macro_rules! impl_readable_primitive_one_byte {
13    ($elem:ty, [$($desc:expr),*], $zero:expr, $read_into:ident) => {
14        impl ReadableElement for $elem {
15            fn read_to_end_exact_vec<R: io::Read>(
16                mut reader: R,
17                type_desc: &PyValue,
18                len: usize,
19            ) -> Result<Vec<Self>, ReadDataError> {
20                match *type_desc {
21                    PyValue::String(ref s) if $(s == $desc)||* => {
22                        let mut out = vec![$zero; len];
23                        reader.$read_into(&mut out)?;
24                        check_for_extra_bytes(&mut reader)?;
25                        Ok(out)
26                    }
27                    ref other => Err(ReadDataError::WrongDescriptor(other.clone())),
28                }
29            }
30        }
31    };
32}
33
34macro_rules! impl_view_and_view_mut_primitive_one_byte {
35    ($elem:ty, [$($desc:expr),*]) => {
36        impl ViewElement for $elem {
37            fn bytes_as_slice<'a>(
38                bytes: &'a [u8],
39                type_desc: &PyValue,
40                len: usize,
41            ) -> Result<&'a [Self], ViewDataError> {
42                match *type_desc {
43                    PyValue::String(ref s) if $(s == $desc)||* => unsafe {
44                        bytes_as_slice(bytes, len)
45                    }
46                    ref other => Err(ViewDataError::WrongDescriptor(other.clone())),
47                }
48            }
49        }
50
51        impl ViewMutElement for $elem {
52            fn bytes_as_mut_slice<'a>(
53                bytes: &'a mut [u8],
54                type_desc: &PyValue,
55                len: usize,
56            ) -> Result<&'a mut [Self], ViewDataError> {
57                match *type_desc {
58                    PyValue::String(ref s) if $(s == $desc)||* => unsafe {
59                        bytes_as_mut_slice(bytes, len)
60                    }
61                    ref other => Err(ViewDataError::WrongDescriptor(other.clone())),
62                }
63            }
64        }
65    };
66}
67
68macro_rules! impl_primitive_one_byte {
69    ($elem:ty, $write_desc:expr, [$($read_desc:expr),*], $zero:expr, $read_into:ident) => {
70        impl_writable_element_always_valid_cast!($elem, $write_desc, $write_desc);
71        impl_readable_primitive_one_byte!($elem, [$($read_desc),*], $zero, $read_into);
72        impl_view_and_view_mut_primitive_one_byte!($elem, [$($read_desc),*]);
73    };
74}
75
76impl_primitive_one_byte!(i8, "|i1", ["|i1", "i1", "b"], 0, read_i8_into);
77impl_primitive_one_byte!(u8, "|u1", ["|u1", "u1", "B"], 0, read_exact);
78
79macro_rules! impl_readable_primitive_multi_byte {
80    ($elem:ty, $little_desc:expr, $big_desc:expr, $zero:expr, $read_into:ident) => {
81        impl ReadableElement for $elem {
82            fn read_to_end_exact_vec<R: io::Read>(
83                mut reader: R,
84                type_desc: &PyValue,
85                len: usize,
86            ) -> Result<Vec<Self>, ReadDataError> {
87                let mut out = vec![$zero; len];
88                match *type_desc {
89                    PyValue::String(ref s) if s == $little_desc => {
90                        reader.$read_into::<LittleEndian>(&mut out)?;
91                    }
92                    PyValue::String(ref s) if s == $big_desc => {
93                        reader.$read_into::<BigEndian>(&mut out)?;
94                    }
95                    ref other => {
96                        return Err(ReadDataError::WrongDescriptor(other.clone()));
97                    }
98                }
99                check_for_extra_bytes(&mut reader)?;
100                Ok(out)
101            }
102        }
103    };
104}
105
106macro_rules! impl_primitive_multi_byte {
107    ($elem:ty, $little_desc:expr, $big_desc:expr, $zero:expr, $read_into:ident) => {
108        impl_writable_element_always_valid_cast!($elem, $little_desc, $big_desc);
109        impl_readable_primitive_multi_byte!($elem, $little_desc, $big_desc, $zero, $read_into);
110        #[cfg(target_endian = "little")]
111        impl_view_and_view_mut_always_valid_cast_multi_byte!($elem, $little_desc, $big_desc);
112        #[cfg(target_endian = "big")]
113        impl_view_and_view_mut_always_valid_cast_multi_byte!($elem, $big_desc, $little_desc);
114    };
115}
116
117impl_primitive_multi_byte!(i16, "<i2", ">i2", 0, read_i16_into);
118impl_primitive_multi_byte!(i32, "<i4", ">i4", 0, read_i32_into);
119impl_primitive_multi_byte!(i64, "<i8", ">i8", 0, read_i64_into);
120
121impl_primitive_multi_byte!(u16, "<u2", ">u2", 0, read_u16_into);
122impl_primitive_multi_byte!(u32, "<u4", ">u4", 0, read_u32_into);
123impl_primitive_multi_byte!(u64, "<u8", ">u8", 0, read_u64_into);
124
125impl_primitive_multi_byte!(f32, "<f4", ">f4", 0., read_f32_into);
126impl_primitive_multi_byte!(f64, "<f8", ">f8", 0., read_f64_into);
127
128/// An error parsing a `bool` from a byte.
129#[derive(Debug)]
130struct ParseBoolError {
131    bad_value: u8,
132}
133
134impl Error for ParseBoolError {
135    fn source(&self) -> Option<&(dyn Error + 'static)> {
136        None
137    }
138}
139
140impl fmt::Display for ParseBoolError {
141    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142        write!(f, "error parsing value {:#04x} as a bool", self.bad_value)
143    }
144}
145
146impl From<ParseBoolError> for ReadDataError {
147    fn from(err: ParseBoolError) -> ReadDataError {
148        ReadDataError::ParseData(Box::new(err))
149    }
150}
151
152impl From<ParseBoolError> for ViewDataError {
153    fn from(err: ParseBoolError) -> ViewDataError {
154        ViewDataError::InvalidData(Box::new(err))
155    }
156}
157
158/// Returns `Ok(_)` iff each of the bytes is a valid bitwise representation for
159/// `bool`.
160///
161/// In other words, this checks that each byte is `0x00` or `0x01`, which is
162/// important for the bytes to be reinterpreted as `bool`, since creating a
163/// `bool` with an invalid value is undefined behavior. Rust guarantees that
164/// `false` is represented as `0x00` and `true` is represented as `0x01`.
165fn check_valid_for_bool(bytes: &[u8]) -> Result<(), ParseBoolError> {
166    for &byte in bytes {
167        if byte > 1 {
168            return Err(ParseBoolError { bad_value: byte });
169        }
170    }
171    Ok(())
172}
173
174impl ReadableElement for bool {
175    fn read_to_end_exact_vec<R: io::Read>(
176        mut reader: R,
177        type_desc: &PyValue,
178        len: usize,
179    ) -> Result<Vec<Self>, ReadDataError> {
180        match *type_desc {
181            PyValue::String(ref s) if s == "|b1" => {
182                // Read the data.
183                let mut bytes: Vec<u8> = vec![0; len];
184                reader.read_exact(&mut bytes)?;
185                check_for_extra_bytes(&mut reader)?;
186
187                // Check that the data is valid for interpretation as `bool`.
188                check_valid_for_bool(&bytes)?;
189
190                // Cast the `Vec<u8>` to `Vec<bool>`.
191                {
192                    let ptr: *mut u8 = bytes.as_mut_ptr();
193                    let len: usize = bytes.len();
194                    let cap: usize = bytes.capacity();
195                    mem::forget(bytes);
196                    // This is safe because:
197                    //
198                    // * All elements are valid `bool`s. (See the call to
199                    //   `check_valid_for_bool` above.)
200                    //
201                    // * `ptr` was originally allocated by `Vec`.
202                    //
203                    // * `bool` has the same size and alignment as `u8`.
204                    //
205                    // * `len` and `cap` are copied directly from the
206                    //   `Vec<u8>`, so `len <= cap` and `cap` is the capacity
207                    //   `ptr` was allocated with.
208                    Ok(unsafe { Vec::from_raw_parts(ptr.cast::<bool>(), len, cap) })
209                }
210            }
211            ref other => Err(ReadDataError::WrongDescriptor(other.clone())),
212        }
213    }
214}
215
216// Rust guarantees that `bool` is one byte, the bitwise representation of
217// `false` is `0x00`, and the bitwise representation of `true` is `0x01`, so we
218// can just cast the data in-place.
219impl_writable_element_always_valid_cast!(bool, "|b1", "|b1");
220
221impl ViewElement for bool {
222    fn bytes_as_slice<'a>(
223        bytes: &'a [u8],
224        type_desc: &PyValue,
225        len: usize,
226    ) -> Result<&'a [Self], ViewDataError> {
227        match *type_desc {
228            PyValue::String(ref s) if s == "|b1" => {
229                check_valid_for_bool(bytes)?;
230                unsafe { bytes_as_slice(bytes, len) }
231            }
232            ref other => Err(ViewDataError::WrongDescriptor(other.clone())),
233        }
234    }
235}
236
237impl ViewMutElement for bool {
238    fn bytes_as_mut_slice<'a>(
239        bytes: &'a mut [u8],
240        type_desc: &PyValue,
241        len: usize,
242    ) -> Result<&'a mut [Self], ViewDataError> {
243        match *type_desc {
244            PyValue::String(ref s) if s == "|b1" => {
245                check_valid_for_bool(bytes)?;
246                unsafe { bytes_as_mut_slice(bytes, len) }
247            }
248            ref other => Err(ViewDataError::WrongDescriptor(other.clone())),
249        }
250    }
251}