Coverage Report

Created: 2025-07-12 07:18

/rust/registry/src/index.crates.io-6f17d22bba15001f/exr-1.73.0/src/meta/attribute.rs
Line
Count
Source (jump to first uncovered line)
1
2
//! Contains all meta data attributes.
3
//! Each layer can have any number of [`Attribute`]s, including custom attributes.
4
5
use smallvec::SmallVec;
6
7
8
/// Contains one of all possible attributes.
9
/// Includes a variant for custom attributes.
10
#[derive(Debug, Clone, PartialEq)]
11
pub enum AttributeValue {
12
13
    /// Channel meta data.
14
    ChannelList(ChannelList),
15
16
    /// Color space definition.
17
    Chromaticities(Chromaticities),
18
19
    /// Compression method of this layer.
20
    Compression(Compression),
21
22
    /// This image is an environment map.
23
    EnvironmentMap(EnvironmentMap),
24
25
    /// Film roll information.
26
    KeyCode(KeyCode),
27
28
    /// Order of the bocks in the file.
29
    LineOrder(LineOrder),
30
31
    /// A 3x3 matrix of floats.
32
    Matrix3x3(Matrix3x3),
33
34
    /// A 4x4 matrix of floats.
35
    Matrix4x4(Matrix4x4),
36
37
    /// 8-bit rgba Preview of the image.
38
    Preview(Preview),
39
40
    /// An integer dividend and divisor.
41
    Rational(Rational),
42
43
    /// Deep or flat and tiled or scan line.
44
    BlockType(BlockType),
45
46
    /// List of texts.
47
    TextVector(Vec<Text>),
48
49
    /// How to tile up the image.
50
    TileDescription(TileDescription),
51
52
    /// Timepoint and more.
53
    TimeCode(TimeCode),
54
55
    /// A string of byte-chars.
56
    Text(Text),
57
58
    /// 64-bit float
59
    F64(f64),
60
61
    /// 32-bit float
62
    F32(f32),
63
64
    /// 32-bit signed integer
65
    I32(i32),
66
67
    /// 2D integer rectangle.
68
    IntegerBounds(IntegerBounds),
69
70
    /// 2D float rectangle.
71
    FloatRect(FloatRect),
72
73
    /// 2D integer vector.
74
    IntVec2(Vec2<i32>),
75
76
    /// 2D float vector.
77
    FloatVec2(Vec2<f32>),
78
79
    /// 3D integer vector.
80
    IntVec3((i32, i32, i32)),
81
82
    /// 3D float vector.
83
    FloatVec3((f32, f32, f32)),
84
85
    /// A custom attribute.
86
    /// Contains the type name of this value.
87
    Custom {
88
89
        /// The name of the type this attribute is an instance of.
90
        kind: Text,
91
92
        /// The value, stored in little-endian byte order, of the value.
93
        /// Use the `exr::io::Data` trait to extract binary values from this vector.
94
        bytes: Vec<u8>
95
    },
96
}
97
98
/// A byte array with each byte being a char.
99
/// This is not UTF an must be constructed from a standard string.
100
// TODO is this ascii? use a rust ascii crate?
101
#[derive(Clone, PartialEq, Ord, PartialOrd, Default)] // hash implemented manually
102
pub struct Text {
103
    bytes: TextBytes,
104
}
105
106
/// Contains time information for this frame within a sequence.
107
/// Also defined methods to compile this information into a
108
/// `TV60`, `TV50` or `Film24` bit sequence, packed into `u32`.
109
///
110
/// Satisfies the [SMPTE standard 12M-1999](https://en.wikipedia.org/wiki/SMPTE_timecode).
111
/// For more in-depth information, see [philrees.co.uk/timecode](http://www.philrees.co.uk/articles/timecode.htm).
112
#[derive(Copy, Debug, Clone, Eq, PartialEq, Hash, Default)]
113
pub struct TimeCode {
114
115
    /// Hours 0 - 23 are valid.
116
    pub hours: u8,
117
118
    /// Minutes 0 - 59 are valid.
119
    pub minutes: u8,
120
121
    /// Seconds 0 - 59 are valid.
122
    pub seconds: u8,
123
124
    /// Frame Indices 0 - 29 are valid.
125
    pub frame: u8,
126
127
    /// Whether this is a drop frame.
128
    pub drop_frame: bool,
129
130
    /// Whether this is a color frame.
131
    pub color_frame: bool,
132
133
    /// Field Phase.
134
    pub field_phase: bool,
135
136
    /// Flags for `TimeCode.binary_groups`.
137
    pub binary_group_flags: [bool; 3],
138
139
    /// The user-defined control codes.
140
    /// Every entry in this array can use at most 3 bits.
141
    /// This results in a maximum value of 15, including 0, for each `u8`.
142
    pub binary_groups: [u8; 8]
143
}
144
145
/// layer type, specifies block type and deepness.
146
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
147
pub enum BlockType {
148
149
    /// Corresponds to the string value `scanlineimage`.
150
    ScanLine,
151
152
    /// Corresponds to the string value `tiledimage`.
153
    Tile,
154
155
    /// Corresponds to the string value `deepscanline`.
156
    DeepScanLine,
157
158
    /// Corresponds to the string value `deeptile`.
159
    DeepTile,
160
}
161
162
/// The string literals used to represent a `BlockType` in a file.
163
pub mod block_type_strings {
164
165
    /// Type attribute text value of flat scan lines
166
    pub const SCAN_LINE: &'static [u8] = b"scanlineimage";
167
168
    /// Type attribute text value of flat tiles
169
    pub const TILE: &'static [u8] = b"tiledimage";
170
171
    /// Type attribute text value of deep scan lines
172
    pub const DEEP_SCAN_LINE: &'static [u8] = b"deepscanline";
173
174
    /// Type attribute text value of deep tiles
175
    pub const DEEP_TILE: &'static [u8] = b"deeptile";
176
}
177
178
179
pub use crate::compression::Compression;
180
181
/// The integer rectangle describing where an layer is placed on the infinite 2D global space.
182
pub type DataWindow = IntegerBounds;
183
184
/// The integer rectangle limiting which part of the infinite 2D global space should be displayed.
185
pub type DisplayWindow = IntegerBounds;
186
187
/// An integer dividend and divisor, together forming a ratio.
188
pub type Rational = (i32, u32);
189
190
/// A float matrix with four rows and four columns.
191
pub type Matrix4x4 = [f32; 4*4];
192
193
/// A float matrix with three rows and three columns.
194
pub type Matrix3x3 = [f32; 3*3];
195
196
/// A rectangular section anywhere in 2D integer space.
197
/// Valid from minimum coordinate (including) `-1,073,741,822`
198
/// to maximum coordinate (including) `1,073,741,822`, the value of (`i32::MAX/2 -1`).
199
#[derive(Clone, Copy, Debug, Eq, PartialEq, Default, Hash)]
200
pub struct IntegerBounds {
201
202
    /// The top left corner of this rectangle.
203
    /// The `Box2I32` includes this pixel if the size is not zero.
204
    pub position: Vec2<i32>,
205
206
    /// How many pixels to include in this `Box2I32`.
207
    /// Extends to the right and downwards.
208
    /// Does not include the actual boundary, just like `Vec::len()`.
209
    pub size: Vec2<usize>,
210
}
211
212
/// A rectangular section anywhere in 2D float space.
213
#[derive(Clone, Copy, Debug, PartialEq)]
214
pub struct FloatRect {
215
216
    /// The top left corner location of the rectangle (inclusive)
217
    pub min: Vec2<f32>,
218
219
    /// The bottom right corner location of the rectangle (inclusive)
220
    pub max: Vec2<f32>
221
}
222
223
/// A List of channels. Channels must be sorted alphabetically.
224
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
225
pub struct ChannelList {
226
227
    /// The channels in this list.
228
    pub list: SmallVec<[ChannelDescription; 5]>,
229
230
    /// The number of bytes that one pixel in this image needs.
231
    // FIXME this needs to account for subsampling anywhere?
232
    pub bytes_per_pixel: usize, // FIXME only makes sense for flat images!
233
234
    /// The sample type of all channels, if all channels have the same type.
235
    pub uniform_sample_type: Option<SampleType>,
236
}
237
238
/// A single channel in an layer.
239
/// Does not contain the actual pixel data,
240
/// but instead merely describes it.
241
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
242
pub struct ChannelDescription {
243
244
    /// One of "R", "G", or "B" most of the time.
245
    pub name: Text,
246
247
    /// U32, F16 or F32.
248
    pub sample_type: SampleType,
249
250
    /// This attribute only tells lossy compression methods
251
    /// whether this value should be quantized exponentially or linearly.
252
    ///
253
    /// Should be `false` for red, green, or blue channels.
254
    /// Should be `true` for hue, chroma, saturation, or alpha channels.
255
    pub quantize_linearly: bool,
256
257
    /// How many of the samples are skipped compared to the other channels in this layer.
258
    ///
259
    /// Can be used for chroma subsampling for manual lossy data compression.
260
    /// Values other than 1 are allowed only in flat, scan-line based images.
261
    /// If an image is deep or tiled, x and y sampling rates for all of its channels must be 1.
262
    pub sampling: Vec2<usize>,
263
}
264
265
/// The type of samples in this channel.
266
#[derive(Clone, Debug, Eq, PartialEq, Copy, Hash)]
267
pub enum SampleType {
268
269
    /// This channel contains 32-bit unsigned int values.
270
    U32,
271
272
    /// This channel contains 16-bit float values.
273
    F16,
274
275
    /// This channel contains 32-bit float values.
276
    F32,
277
}
278
279
/// The color space of the pixels.
280
///
281
/// If a file doesn't have a chromaticities attribute, display software
282
/// should assume that the file's primaries and the white point match `Rec. ITU-R BT.709-3`.
283
#[derive(Debug, Clone, Copy, PartialEq)]
284
pub struct Chromaticities {
285
286
    /// "Red" location on the CIE XY chromaticity diagram.
287
    pub red: Vec2<f32>,
288
289
    /// "Green" location on the CIE XY chromaticity diagram.
290
    pub green: Vec2<f32>,
291
292
    /// "Blue" location on the CIE XY chromaticity diagram.
293
    pub blue: Vec2<f32>,
294
295
    /// "White" location on the CIE XY chromaticity diagram.
296
    pub white: Vec2<f32>
297
}
298
299
/// If this attribute is present, it describes
300
/// how this texture should be projected onto an environment.
301
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
302
pub enum EnvironmentMap {
303
304
    /// This image is an environment map projected like a world map.
305
    LatitudeLongitude,
306
307
    /// This image contains the six sides of a cube.
308
    Cube,
309
}
310
311
/// Uniquely identifies a motion picture film frame.
312
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
313
pub struct KeyCode {
314
315
    /// Identifies a film manufacturer.
316
    pub film_manufacturer_code: i32,
317
318
    /// Identifies a film type.
319
    pub film_type: i32,
320
321
    /// Specifies the film roll prefix.
322
    pub film_roll_prefix: i32,
323
324
    /// Specifies the film count.
325
    pub count: i32,
326
327
    /// Specifies the perforation offset.
328
    pub perforation_offset: i32,
329
330
    /// Specifies the perforation count of each single frame.
331
    pub perforations_per_frame: i32,
332
333
    /// Specifies the perforation count of each single film.
334
    pub perforations_per_count: i32,
335
}
336
337
/// In what order the `Block`s of pixel data appear in a file.
338
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
339
pub enum LineOrder {
340
341
    /// The blocks in the file are ordered in descending rows from left to right.
342
    /// When compressing in parallel, this option requires potentially large amounts of memory.
343
    /// In that case, use `LineOrder::Unspecified` for best performance.
344
    Increasing,
345
346
    /// The blocks in the file are ordered in ascending rows from right to left.
347
    /// When compressing in parallel, this option requires potentially large amounts of memory.
348
    /// In that case, use `LineOrder::Unspecified` for best performance.
349
    Decreasing,
350
351
    /// The blocks are not ordered in a specific way inside the file.
352
    /// In multi-core file writing, this option offers the best performance.
353
    Unspecified,
354
}
355
356
/// A small `rgba` image of `i8` values that approximates the real exr image.
357
// TODO is this linear?
358
#[derive(Clone, Eq, PartialEq)]
359
pub struct Preview {
360
361
    /// The dimensions of the preview image.
362
    pub size: Vec2<usize>,
363
364
    /// An array with a length of 4 × width × height.
365
    /// The pixels are stored in `LineOrder::Increasing`.
366
    /// Each pixel consists of the four `u8` values red, green, blue, alpha.
367
    pub pixel_data: Vec<i8>,
368
}
369
370
/// Describes how the layer is divided into tiles.
371
/// Specifies the size of each tile in the image
372
/// and whether this image contains multiple resolution levels.
373
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
374
pub struct TileDescription {
375
376
    /// The size of each tile.
377
    /// Stays the same number of pixels across all levels.
378
    pub tile_size: Vec2<usize>,
379
380
    /// Whether to also store smaller versions of the image.
381
    pub level_mode: LevelMode,
382
383
    /// Whether to round up or down when calculating Mip/Rip levels.
384
    pub rounding_mode: RoundingMode,
385
}
386
387
/// Whether to also store increasingly smaller versions of the original image.
388
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
389
pub enum LevelMode {
390
391
    /// Only a single level.
392
    Singular,
393
394
    /// Levels with a similar aspect ratio.
395
    MipMap,
396
397
    /// Levels with all possible aspect ratios.
398
    RipMap,
399
}
400
401
402
/// The raw bytes that make up a string in an exr file.
403
/// Each `u8` is a single char.
404
// will mostly be "R", "G", "B" or "deepscanlineimage"
405
pub type TextBytes = SmallVec<[u8; 24]>;
406
407
/// A byte slice, interpreted as text
408
pub type TextSlice = [u8];
409
410
411
use crate::io::*;
412
use crate::meta::{sequence_end};
413
use crate::error::*;
414
use crate::math::{RoundingMode, Vec2};
415
use half::f16;
416
use std::convert::{TryFrom};
417
use std::borrow::Borrow;
418
use std::hash::{Hash, Hasher};
419
use bit_field::BitField;
420
421
422
0
fn invalid_type() -> Error {
423
0
    Error::invalid("attribute type mismatch")
424
0
}
425
426
427
impl Text {
428
429
    /// Create a `Text` from an `str` reference.
430
    /// Returns `None` if this string contains unsupported chars.
431
10.0k
    pub fn new_or_none(string: impl AsRef<str>) -> Option<Self> {
432
10.0k
        let vec : Option<TextBytes> = string.as_ref().chars()
433
10.0k
            .map(|character| u8::try_from(character as u64).ok())
434
10.0k
            .collect();
435
10.0k
436
10.0k
        vec.map(Self::from_bytes_unchecked)
437
10.0k
    }
438
439
    /// Create a `Text` from an `str` reference.
440
    /// Panics if this string contains unsupported chars.
441
10.0k
    pub fn new_or_panic(string: impl AsRef<str>) -> Self {
442
10.0k
        Self::new_or_none(string).expect("exr::Text contains unsupported characters")
443
10.0k
    }
444
445
    /// Create a `Text` from a slice of bytes,
446
    /// without checking any of the bytes.
447
0
    pub fn from_slice_unchecked(text: &TextSlice) -> Self {
448
0
        Self::from_bytes_unchecked(SmallVec::from_slice(text))
449
0
    }
450
451
    /// Create a `Text` from the specified bytes object,
452
    /// without checking any of the bytes.
453
65.2k
    pub fn from_bytes_unchecked(bytes: TextBytes) -> Self {
454
65.2k
        Text { bytes }
455
65.2k
    }
456
457
    /// The internal ASCII bytes this text is made of.
458
618k
    pub fn as_slice(&self) -> &TextSlice {
459
618k
        self.bytes.as_slice()
460
618k
    }
461
462
    /// Check whether this string is valid, adjusting `long_names` if required.
463
    /// If `long_names` is not provided, text length will be entirely unchecked.
464
15.2k
    pub fn validate(&self, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult {
465
15.2k
        Self::validate_bytes(self.as_slice(), null_terminated, long_names)
466
15.2k
    }
467
468
    /// Check whether some bytes are valid, adjusting `long_names` if required.
469
    /// If `long_names` is not provided, text length will be entirely unchecked.
470
15.2k
    pub fn validate_bytes(text: &TextSlice, null_terminated: bool, long_names: Option<&mut bool>) -> UnitResult {
471
15.2k
        if null_terminated && text.is_empty() {
472
0
            return Err(Error::invalid("text must not be empty"));
473
15.2k
        }
474
475
15.2k
        if let Some(long) = long_names {
476
10.5k
            if text.len() >= 256 { return Err(Error::invalid("text must not be longer than 255")); }
477
10.5k
            if text.len() >= 32 { *long = true; }
478
4.73k
        }
479
480
15.2k
        Ok(())
481
15.2k
    }
482
483
    /// The byte count this string would occupy if it were encoded as a null-terminated string.
484
56
    pub fn null_terminated_byte_size(&self) -> usize {
485
56
        self.bytes.len() + sequence_end::byte_size()
486
56
    }
487
488
    /// The byte count this string would occupy if it were encoded as a size-prefixed string.
489
0
    pub fn i32_sized_byte_size(&self) -> usize {
490
0
        self.bytes.len() + i32::BYTE_SIZE
491
0
    }
492
493
    /// Write the length of a string and then the contents with that length.
494
0
    pub fn write_i32_sized<W: Write>(&self, write: &mut W) -> UnitResult {
495
0
        debug_assert!(self.validate( false, None).is_ok(), "text size bug");
496
0
        i32::write(usize_to_i32(self.bytes.len()), write)?;
497
0
        Self::write_unsized_bytes(self.bytes.as_slice(), write)
498
0
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::write_i32_sized::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_i32_sized::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_i32_sized::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
499
500
    /// Without validation, write this instance to the byte stream.
501
364
    fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
502
364
        u8::write_slice(write, bytes)?;
503
364
        Ok(())
504
364
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::write_unsized_bytes::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_unsized_bytes::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::Text>::write_unsized_bytes::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
501
364
    fn write_unsized_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
502
364
        u8::write_slice(write, bytes)?;
503
364
        Ok(())
504
364
    }
505
506
    /// Read the length of a string and then the contents with that length.
507
358
    pub fn read_i32_sized<R: Read>(read: &mut R, max_size: usize) -> Result<Self> {
508
358
        let size = i32_to_usize(i32::read(read)?, "vector size")?;
509
358
        Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, Some(max_size), "text attribute length")?)))
510
358
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
<exr::meta::attribute::Text>::read_i32_sized::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
507
358
    pub fn read_i32_sized<R: Read>(read: &mut R, max_size: usize) -> Result<Self> {
508
358
        let size = i32_to_usize(i32::read(read)?, "vector size")?;
509
358
        Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, Some(max_size), "text attribute length")?)))
510
358
    }
511
512
    /// Read the contents with that length.
513
54.0k
    pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
514
        const SMALL_SIZE: usize  = 24;
515
516
        // for small strings, read into small vec without heap allocation
517
54.0k
        if size <= SMALL_SIZE {
518
50.6k
            let mut buffer = [0_u8; SMALL_SIZE];
519
50.6k
            let data = &mut buffer[..size];
520
50.6k
521
50.6k
            read.read_exact(data)?;
522
50.6k
            Ok(Text::from_bytes_unchecked(SmallVec::from_slice(data)))
523
        }
524
525
        // for large strings, read a dynamic vec of arbitrary size
526
        else {
527
3.39k
            Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, None, "text attribute length")?)))
528
        }
529
54.0k
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_sized::<&[u8]>
<exr::meta::attribute::Text>::read_sized::<&[u8]>
Line
Count
Source
513
46.4k
    pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
514
        const SMALL_SIZE: usize  = 24;
515
516
        // for small strings, read into small vec without heap allocation
517
46.4k
        if size <= SMALL_SIZE {
518
43.7k
            let mut buffer = [0_u8; SMALL_SIZE];
519
43.7k
            let data = &mut buffer[..size];
520
43.7k
521
43.7k
            read.read_exact(data)?;
522
43.7k
            Ok(Text::from_bytes_unchecked(SmallVec::from_slice(data)))
523
        }
524
525
        // for large strings, read a dynamic vec of arbitrary size
526
        else {
527
2.73k
            Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, None, "text attribute length")?)))
528
        }
529
46.4k
    }
<exr::meta::attribute::Text>::read_sized::<&[u8]>
Line
Count
Source
513
7.58k
    pub fn read_sized<R: Read>(read: &mut R, size: usize) -> Result<Self> {
514
        const SMALL_SIZE: usize  = 24;
515
516
        // for small strings, read into small vec without heap allocation
517
7.58k
        if size <= SMALL_SIZE {
518
6.92k
            let mut buffer = [0_u8; SMALL_SIZE];
519
6.92k
            let data = &mut buffer[..size];
520
6.92k
521
6.92k
            read.read_exact(data)?;
522
6.92k
            Ok(Text::from_bytes_unchecked(SmallVec::from_slice(data)))
523
        }
524
525
        // for large strings, read a dynamic vec of arbitrary size
526
        else {
527
660
            Ok(Text::from_bytes_unchecked(SmallVec::from_vec(u8::read_vec(read, size, 1024, None, "text attribute length")?)))
528
        }
529
7.58k
    }
530
531
    /// Write the string contents and a null-terminator.
532
56
    pub fn write_null_terminated<W: Write>(&self, write: &mut W) -> UnitResult {
533
56
        Self::write_null_terminated_bytes(self.as_slice(), write)
534
56
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::Text>::write_null_terminated::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
532
56
    pub fn write_null_terminated<W: Write>(&self, write: &mut W) -> UnitResult {
533
56
        Self::write_null_terminated_bytes(self.as_slice(), write)
534
56
    }
535
536
    /// Write the string contents and a null-terminator.
537
364
    fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
538
364
        debug_assert!(!bytes.is_empty(), "text is empty bug"); // required to avoid mixup with "sequece_end"
539
540
364
        Text::write_unsized_bytes(bytes, write)?;
541
364
        sequence_end::write(write)?;
542
364
        Ok(())
543
364
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated_bytes::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_null_terminated_bytes::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::Text>::write_null_terminated_bytes::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
537
364
    fn write_null_terminated_bytes<W: Write>(bytes: &[u8], write: &mut W) -> UnitResult {
538
364
        debug_assert!(!bytes.is_empty(), "text is empty bug"); // required to avoid mixup with "sequece_end"
539
540
364
        Text::write_unsized_bytes(bytes, write)?;
541
364
        sequence_end::write(write)?;
542
364
        Ok(())
543
364
    }
544
545
    /// Read a string until the null-terminator is found. Then skips the null-terminator.
546
1.21M
    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547
1.21M
        let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549
        loop {
550
15.6M
            match u8::read(read)? {
551
1.21M
                0 => break,
552
14.3M
                non_terminator => bytes.push(non_terminator),
553
14.3M
            }
554
14.3M
555
14.3M
            if bytes.len() > max_len {
556
15
                return Err(Error::invalid("text too long"))
557
14.3M
            }
558
        }
559
560
1.21M
        Ok(Text { bytes })
561
1.21M
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
<exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Line
Count
Source
546
1.13M
    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547
1.13M
        let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549
        loop {
550
14.6M
            match u8::read(read)? {
551
1.13M
                0 => break,
552
13.5M
                non_terminator => bytes.push(non_terminator),
553
13.5M
            }
554
13.5M
555
13.5M
            if bytes.len() > max_len {
556
14
                return Err(Error::invalid("text too long"))
557
13.5M
            }
558
        }
559
560
1.13M
        Ok(Text { bytes })
561
1.13M
    }
<exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
546
10.9k
    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547
10.9k
        let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549
        loop {
550
108k
            match u8::read(read)? {
551
10.9k
                0 => break,
552
97.3k
                non_terminator => bytes.push(non_terminator),
553
97.3k
            }
554
97.3k
555
97.3k
            if bytes.len() > max_len {
556
1
                return Err(Error::invalid("text too long"))
557
97.3k
            }
558
        }
559
560
10.9k
        Ok(Text { bytes })
561
10.9k
    }
<exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>>
Line
Count
Source
546
308
    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547
308
        let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549
        loop {
550
2.61k
            match u8::read(read)? {
551
308
                0 => break,
552
2.31k
                non_terminator => bytes.push(non_terminator),
553
2.31k
            }
554
2.31k
555
2.31k
            if bytes.len() > max_len {
556
0
                return Err(Error::invalid("text too long"))
557
2.31k
            }
558
        }
559
560
308
        Ok(Text { bytes })
561
308
    }
<exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>>
Line
Count
Source
546
68.8k
    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547
68.8k
        let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549
        loop {
550
830k
            match u8::read(read)? {
551
68.8k
                0 => break,
552
761k
                non_terminator => bytes.push(non_terminator),
553
761k
            }
554
761k
555
761k
            if bytes.len() > max_len {
556
0
                return Err(Error::invalid("text too long"))
557
761k
            }
558
        }
559
560
68.8k
        Ok(Text { bytes })
561
68.8k
    }
<exr::meta::attribute::Text>::read_null_terminated::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
546
2.61k
    pub fn read_null_terminated<R: Read>(read: &mut R, max_len: usize) -> Result<Self> {
547
2.61k
        let mut bytes = smallvec![ u8::read(read)? ]; // null-terminated strings are always at least 1 byte
548
549
        loop {
550
2.61k
            match u8::read(read)? {
551
2.61k
                0 => break,
552
0
                non_terminator => bytes.push(non_terminator),
553
0
            }
554
0
555
0
            if bytes.len() > max_len {
556
0
                return Err(Error::invalid("text too long"))
557
0
            }
558
        }
559
560
2.61k
        Ok(Text { bytes })
561
2.61k
    }
562
563
    /// Allows any text length since it is only used for attribute values,
564
    /// but not attribute names, attribute type names, or channel names.
565
358
    fn read_vec_of_i32_sized(
566
358
        read: &mut PeekRead<impl Read>,
567
358
        total_byte_size: usize
568
358
    ) -> Result<Vec<Text>>
569
358
    {
570
358
        let mut result = Vec::with_capacity(2);
571
358
572
358
        // length of the text-vector can be inferred from attribute size
573
358
        let mut processed_bytes = 0;
574
575
716
        while processed_bytes < total_byte_size {
576
358
            let text = Text::read_i32_sized(read, total_byte_size)?;
577
358
            processed_bytes += ::std::mem::size_of::<i32>(); // size i32 of the text
578
358
            processed_bytes += text.bytes.len();
579
358
            result.push(text);
580
        }
581
582
        // the expected byte size did not match the actual text byte size
583
358
        if processed_bytes != total_byte_size {
584
0
            return Err(Error::invalid("text array byte size"))
585
358
        }
586
358
587
358
        Ok(result)
588
358
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
<exr::meta::attribute::Text>::read_vec_of_i32_sized::<&[u8]>
Line
Count
Source
565
358
    fn read_vec_of_i32_sized(
566
358
        read: &mut PeekRead<impl Read>,
567
358
        total_byte_size: usize
568
358
    ) -> Result<Vec<Text>>
569
358
    {
570
358
        let mut result = Vec::with_capacity(2);
571
358
572
358
        // length of the text-vector can be inferred from attribute size
573
358
        let mut processed_bytes = 0;
574
575
716
        while processed_bytes < total_byte_size {
576
358
            let text = Text::read_i32_sized(read, total_byte_size)?;
577
358
            processed_bytes += ::std::mem::size_of::<i32>(); // size i32 of the text
578
358
            processed_bytes += text.bytes.len();
579
358
            result.push(text);
580
        }
581
582
        // the expected byte size did not match the actual text byte size
583
358
        if processed_bytes != total_byte_size {
584
0
            return Err(Error::invalid("text array byte size"))
585
358
        }
586
358
587
358
        Ok(result)
588
358
    }
589
590
    /// Allows any text length since it is only used for attribute values,
591
    /// but not attribute names, attribute type names, or channel names.
592
0
    fn write_vec_of_i32_sized_texts<W: Write>(write: &mut W, texts: &[Text]) -> UnitResult {
593
        // length of the text-vector can be inferred from attribute size
594
0
        for text in texts {
595
0
            text.write_i32_sized(write)?;
596
        }
597
598
0
        Ok(())
599
0
    }
Unexecuted instantiation: <exr::meta::attribute::Text>::write_vec_of_i32_sized_texts::<_>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_vec_of_i32_sized_texts::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::Text>::write_vec_of_i32_sized_texts::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
600
601
    /// The underlying bytes that represent this text.
602
13.9k
    pub fn bytes(&self) -> &[u8] {
603
13.9k
        self.bytes.as_slice()
604
13.9k
    }
605
606
    /// Iterate over the individual chars in this text, similar to `String::chars()`.
607
    /// Does not do any heap-allocation but borrows from this instance instead.
608
182
    pub fn chars(&self) -> impl '_ + Iterator<Item = char> {
609
182
        self.bytes.iter().map(|&byte| byte as char)
610
182
    }
611
612
    /// Compare this `exr::Text` with a plain `&str`.
613
0
    pub fn eq(&self, string: &str) -> bool {
614
0
        string.chars().eq(self.chars())
615
0
    }
616
617
    /// Compare this `exr::Text` with a plain `&str` ignoring capitalization.
618
182
    pub fn eq_case_insensitive(&self, string: &str) -> bool {
619
182
        // this is technically not working for a "turkish i", but those cannot be encoded in exr files anyways
620
182
        let self_chars = self.chars().map(|char| char.to_ascii_lowercase());
621
182
        let string_chars = string.chars().flat_map(|ch| ch.to_lowercase());
622
182
623
182
        string_chars.eq(self_chars)
624
182
    }
625
}
626
627
impl PartialEq<str> for Text {
628
0
    fn eq(&self, other: &str) -> bool {
629
0
        self.eq(other)
630
0
    }
631
}
632
633
impl PartialEq<Text> for str {
634
0
    fn eq(&self, other: &Text) -> bool {
635
0
        other.eq(self)
636
0
    }
637
}
638
639
impl Eq for Text {}
640
641
impl Borrow<TextSlice> for Text {
642
0
    fn borrow(&self) -> &TextSlice {
643
0
        self.as_slice()
644
0
    }
645
}
646
647
// forwarding implementation. guarantees `text.borrow().hash() == text.hash()` (required for Borrow)
648
impl Hash for Text {
649
639k
    fn hash<H: Hasher>(&self, state: &mut H) {
650
639k
        self.bytes.hash(state)
651
639k
    }
652
}
653
654
impl Into<String> for Text {
655
0
    fn into(self) -> String {
656
0
        self.to_string()
657
0
    }
658
}
659
660
impl<'s> From<&'s str> for Text {
661
662
    /// Panics if the string contains an unsupported character
663
10.0k
    fn from(str: &'s str) -> Self {
664
10.0k
        Self::new_or_panic(str)
665
10.0k
    }
666
}
667
668
669
/* TODO (currently conflicts with From<&str>)
670
impl<'s> TryFrom<&'s str> for Text {
671
    type Error = String;
672
673
    fn try_from(value: &'s str) -> std::result::Result<Self, Self::Error> {
674
        Text::new_or_none(value)
675
            .ok_or_else(|| format!(
676
                "exr::Text does not support all characters in the string `{}`",
677
                value
678
            ))
679
    }
680
}*/
681
682
683
impl ::std::fmt::Debug for Text {
684
0
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
685
0
        write!(f, "exr::Text(\"{}\")", self)
686
0
    }
687
}
688
689
// automatically implements to_string for us
690
impl ::std::fmt::Display for Text {
691
0
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
692
        use std::fmt::Write;
693
694
0
        for &byte in self.bytes.iter() {
695
0
            f.write_char(byte as char)?;
696
        }
697
698
0
        Ok(())
699
0
    }
700
}
701
702
703
impl ChannelList {
704
705
    /// Does not validate channel order.
706
7.31k
    pub fn new(channels: SmallVec<[ChannelDescription; 5]>) -> Self {
707
7.31k
        let uniform_sample_type = {
708
7.31k
            if let Some(first) = channels.first() {
709
5.81k
                let has_uniform_types = channels.iter().skip(1)
710
5.81k
                    .all(|chan| chan.sample_type == first.sample_type);
711
5.81k
712
5.81k
                if has_uniform_types { Some(first.sample_type) } else { None }
713
            }
714
1.49k
            else { None }
715
        };
716
717
7.31k
        ChannelList {
718
13.4k
            bytes_per_pixel: channels.iter().map(|channel| channel.sample_type.bytes_per_sample()).sum(),
719
7.31k
            list: channels, uniform_sample_type,
720
7.31k
        }
721
7.31k
    }
722
723
    /// Iterate over the channels, and adds to each channel the byte offset of the channels sample type.
724
    /// Assumes the internal channel list is properly sorted.
725
5.00k
    pub fn channels_with_byte_offset(&self) -> impl Iterator<Item=(usize, &ChannelDescription)> {
726
11.3k
        self.list.iter().scan(0, |byte_position, channel|{
727
11.3k
            let previous_position = *byte_position;
728
11.3k
            *byte_position += channel.sample_type.bytes_per_sample();
729
11.3k
            Some((previous_position, channel))
730
11.3k
        })
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
<exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Line
Count
Source
726
10.7k
        self.list.iter().scan(0, |byte_position, channel|{
727
10.7k
            let previous_position = *byte_position;
728
10.7k
            *byte_position += channel.sample_type.bytes_per_sample();
729
10.7k
            Some((previous_position, channel))
730
10.7k
        })
<exr::meta::attribute::ChannelList>::channels_with_byte_offset::{closure#0}
Line
Count
Source
726
520
        self.list.iter().scan(0, |byte_position, channel|{
727
520
            let previous_position = *byte_position;
728
520
            *byte_position += channel.sample_type.bytes_per_sample();
729
520
            Some((previous_position, channel))
730
520
        })
731
5.00k
    }
732
733
    /// Return the index of the channel with the exact name, case sensitive, or none.
734
    /// Potentially uses less than linear time.
735
5.07k
    pub fn find_index_of_channel(&self, exact_name: &Text) -> Option<usize> {
736
8.91k
        self.list.binary_search_by_key(&exact_name.bytes(), |chan| chan.name.bytes()).ok()
737
5.07k
    }
738
739
    // TODO use this in compression methods
740
    /*pub fn pixel_section_indices(&self, bounds: IntegerBounds) -> impl '_ + Iterator<Item=(&Channel, usize, usize)> {
741
        (bounds.position.y() .. bounds.end().y()).flat_map(|y| {
742
            self.list
743
                .filter(|channel| mod_p(y, usize_to_i32(channel.sampling.1)) == 0)
744
                .flat_map(|channel|{
745
                    (bounds.position.x() .. bounds.end().x())
746
                        .filter(|x| mod_p(*x, usize_to_i32(channel.sampling.0)) == 0)
747
                        .map(|x| (channel, x, y))
748
                })
749
        })
750
    }*/
751
}
752
753
impl BlockType {
754
755
    /// The corresponding attribute type name literal
756
    const TYPE_NAME: &'static [u8] = type_names::TEXT;
757
758
    /// Return a `BlockType` object from the specified attribute text value.
759
2.93k
    pub fn parse(text: Text) -> Result<Self> {
760
2.93k
        match text.as_slice() {
761
2.93k
            block_type_strings::SCAN_LINE => Ok(BlockType::ScanLine),
762
2.89k
            block_type_strings::TILE => Ok(BlockType::Tile),
763
764
2.62k
            block_type_strings::DEEP_SCAN_LINE => Ok(BlockType::DeepScanLine),
765
2.62k
            block_type_strings::DEEP_TILE => Ok(BlockType::DeepTile),
766
767
10
            _ => Err(Error::invalid("block type attribute value")),
768
        }
769
2.93k
    }
770
771
    /// Without validation, write this instance to the byte stream.
772
14
    pub fn write(&self, write: &mut impl Write) -> UnitResult {
773
14
        u8::write_slice(write, self.to_text_bytes())?;
774
14
        Ok(())
775
14
    }
Unexecuted instantiation: <exr::meta::attribute::BlockType>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::BlockType>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::BlockType>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
772
14
    pub fn write(&self, write: &mut impl Write) -> UnitResult {
773
14
        u8::write_slice(write, self.to_text_bytes())?;
774
14
        Ok(())
775
14
    }
776
777
    /// Returns the raw attribute text value this type is represented by in a file.
778
28
    pub fn to_text_bytes(&self) -> &[u8] {
779
28
        match self {
780
0
            BlockType::ScanLine => block_type_strings::SCAN_LINE,
781
28
            BlockType::Tile => block_type_strings::TILE,
782
0
            BlockType::DeepScanLine => block_type_strings::DEEP_SCAN_LINE,
783
0
            BlockType::DeepTile => block_type_strings::DEEP_TILE,
784
        }
785
28
    }
786
787
    /// Number of bytes this would consume in an exr file.
788
14
    pub fn byte_size(&self) -> usize {
789
14
        self.to_text_bytes().len()
790
14
    }
791
}
792
793
794
impl IntegerBounds {
795
796
    /// Create a box with no size located at (0,0).
797
4.47k
    pub fn zero() -> Self {
798
4.47k
        Self::from_dimensions(Vec2(0, 0))
799
4.47k
    }
800
801
    /// Create a box with a size starting at zero.
802
4.47k
    pub fn from_dimensions(size: impl Into<Vec2<usize>>) -> Self {
803
4.47k
        Self::new(Vec2(0,0), size)
804
4.47k
    }
805
806
    /// Create a box with a size and an origin point.
807
18.0k
    pub fn new(start: impl Into<Vec2<i32>>, size: impl Into<Vec2<usize>>) -> Self {
808
18.0k
        Self { position: start.into(), size: size.into() }
809
18.0k
    }
810
811
    /// Returns the top-right coordinate of the rectangle.
812
    /// The row and column described by this vector are not included in the rectangle,
813
    /// just like `Vec::len()`.
814
28
    pub fn end(self) -> Vec2<i32> {
815
28
        self.position + self.size.to_i32() // larger than max int32 is panic
816
28
    }
817
818
    /// Returns the maximum coordinate that a value in this rectangle may have.
819
28
    pub fn max(self) -> Vec2<i32> {
820
28
        self.end() - Vec2(1,1)
821
28
    }
822
823
    /// Validate this instance.
824
23.7k
    pub fn validate(&self, max_size: Option<Vec2<usize>>) -> UnitResult {
825
23.7k
        if let Some(max_size) = max_size {
826
18.7k
            if self.size.width() > max_size.width() || self.size.height() > max_size.height()  {
827
0
                return Err(Error::invalid("window attribute dimension value"));
828
18.7k
            }
829
5.00k
        }
830
831
23.7k
        let min_i64 = Vec2(self.position.x() as i64, self.position.y() as i64);
832
23.7k
833
23.7k
        let max_i64 = Vec2(
834
23.7k
            self.position.x() as i64 + self.size.width() as i64,
835
23.7k
            self.position.y() as i64 + self.size.height() as i64,
836
23.7k
        );
837
23.7k
838
23.7k
        Self::validate_min_max_u64(min_i64, max_i64)
839
23.7k
    }
840
841
53.8k
    fn validate_min_max_u64(min: Vec2<i64>, max: Vec2<i64>) -> UnitResult {
842
53.8k
        let max_box_size_as_i64 = (i32::MAX / 2) as i64; // as defined in the original c++ library
843
53.8k
844
53.8k
        if     max.x() >=  max_box_size_as_i64
845
53.8k
            || max.y() >=  max_box_size_as_i64
846
53.8k
            || min.x() <= -max_box_size_as_i64
847
53.8k
            || min.y() <= -max_box_size_as_i64
848
        {
849
23
            return Err(Error::invalid("window size exceeding integer maximum"));
850
53.8k
        }
851
53.8k
852
53.8k
        Ok(())
853
53.8k
    }
854
855
    /// Number of bytes this would consume in an exr file.
856
28
    pub fn byte_size() -> usize {
857
28
        4 * i32::BYTE_SIZE
858
28
    }
859
860
    /// Without validation, write this instance to the byte stream.
861
28
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
862
28
        let Vec2(x_min, y_min) = self.position;
863
28
        let Vec2(x_max, y_max) = self.max();
864
28
865
28
        x_min.write(write)?;
866
28
        y_min.write(write)?;
867
28
        x_max.write(write)?;
868
28
        y_max.write(write)?;
869
28
        Ok(())
870
28
    }
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::IntegerBounds>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
861
28
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
862
28
        let Vec2(x_min, y_min) = self.position;
863
28
        let Vec2(x_max, y_max) = self.max();
864
28
865
28
        x_min.write(write)?;
866
28
        y_min.write(write)?;
867
28
        x_max.write(write)?;
868
28
        y_max.write(write)?;
869
28
        Ok(())
870
28
    }
871
872
    /// Read the value without validating.
873
30.1k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
874
30.1k
        let x_min = i32::read(read)?;
875
30.1k
        let y_min = i32::read(read)?;
876
30.1k
        let x_max = i32::read(read)?;
877
30.1k
        let y_max = i32::read(read)?;
878
879
30.1k
        let min = Vec2(x_min.min(x_max), y_min.min(y_max));
880
30.1k
        let max  = Vec2(x_min.max(x_max), y_min.max(y_max));
881
30.1k
882
30.1k
        // prevent addition overflow
883
30.1k
        Self::validate_min_max_u64(
884
30.1k
            Vec2(min.x() as i64, min.y() as i64),
885
30.1k
            Vec2(max.x() as i64, max.y() as i64),
886
30.1k
        )?;
887
888
        // add one to max because the max inclusive, but the size is not
889
30.1k
        let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y());
890
30.1k
        let size = size.to_usize("box coordinates")?;
891
892
30.1k
        Ok(IntegerBounds { position: min, size })
893
30.1k
    }
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::IntegerBounds>::read::<&[u8]>
<exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Line
Count
Source
873
28.0k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
874
28.0k
        let x_min = i32::read(read)?;
875
28.0k
        let y_min = i32::read(read)?;
876
28.0k
        let x_max = i32::read(read)?;
877
28.0k
        let y_max = i32::read(read)?;
878
879
28.0k
        let min = Vec2(x_min.min(x_max), y_min.min(y_max));
880
28.0k
        let max  = Vec2(x_min.max(x_max), y_min.max(y_max));
881
28.0k
882
28.0k
        // prevent addition overflow
883
28.0k
        Self::validate_min_max_u64(
884
28.0k
            Vec2(min.x() as i64, min.y() as i64),
885
28.0k
            Vec2(max.x() as i64, max.y() as i64),
886
28.0k
        )?;
887
888
        // add one to max because the max inclusive, but the size is not
889
27.9k
        let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y());
890
27.9k
        let size = size.to_usize("box coordinates")?;
891
892
27.9k
        Ok(IntegerBounds { position: min, size })
893
28.0k
    }
<exr::meta::attribute::IntegerBounds>::read::<&[u8]>
Line
Count
Source
873
2.13k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
874
2.13k
        let x_min = i32::read(read)?;
875
2.13k
        let y_min = i32::read(read)?;
876
2.13k
        let x_max = i32::read(read)?;
877
2.13k
        let y_max = i32::read(read)?;
878
879
2.13k
        let min = Vec2(x_min.min(x_max), y_min.min(y_max));
880
2.13k
        let max  = Vec2(x_min.max(x_max), y_min.max(y_max));
881
2.13k
882
2.13k
        // prevent addition overflow
883
2.13k
        Self::validate_min_max_u64(
884
2.13k
            Vec2(min.x() as i64, min.y() as i64),
885
2.13k
            Vec2(max.x() as i64, max.y() as i64),
886
2.13k
        )?;
887
888
        // add one to max because the max inclusive, but the size is not
889
2.13k
        let size = Vec2(max.x() + 1 - min.x(), max.y() + 1 - min.y());
890
2.13k
        let size = size.to_usize("box coordinates")?;
891
892
2.13k
        Ok(IntegerBounds { position: min, size })
893
2.13k
    }
894
895
    /// Create a new rectangle which is offset by the specified origin.
896
0
    pub fn with_origin(self, origin: Vec2<i32>) -> Self { // TODO rename to "move" or "translate"?
897
0
        IntegerBounds { position: self.position + origin, .. self }
898
0
    }
899
900
    /// Returns whether the specified rectangle is equal to or inside this rectangle.
901
0
    pub fn contains(self, subset: Self) -> bool {
902
0
           subset.position.x() >= self.position.x()
903
0
        && subset.position.y() >= self.position.y()
904
0
        && subset.end().x() <= self.end().x()
905
0
        && subset.end().y() <= self.end().y()
906
0
    }
907
}
908
909
910
impl FloatRect {
911
912
    /// Number of bytes this would consume in an exr file.
913
0
    pub fn byte_size() -> usize {
914
0
        4 * f32::BYTE_SIZE
915
0
    }
916
917
    /// Without validation, write this instance to the byte stream.
918
0
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
919
0
        self.min.x().write(write)?;
920
0
        self.min.y().write(write)?;
921
0
        self.max.x().write(write)?;
922
0
        self.max.y().write(write)?;
923
0
        Ok(())
924
0
    }
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
925
926
    /// Read the value without validating.
927
172
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
928
172
        let x_min = f32::read(read)?;
929
171
        let y_min = f32::read(read)?;
930
170
        let x_max = f32::read(read)?;
931
169
        let y_max = f32::read(read)?;
932
933
168
        Ok(FloatRect {
934
168
            min: Vec2(x_min, y_min),
935
168
            max: Vec2(x_max, y_max)
936
168
        })
937
172
    }
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
<exr::meta::attribute::FloatRect>::read::<&[u8]>
Line
Count
Source
927
172
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
928
172
        let x_min = f32::read(read)?;
929
171
        let y_min = f32::read(read)?;
930
170
        let x_max = f32::read(read)?;
931
169
        let y_max = f32::read(read)?;
932
933
168
        Ok(FloatRect {
934
168
            min: Vec2(x_min, y_min),
935
168
            max: Vec2(x_max, y_max)
936
168
        })
937
172
    }
Unexecuted instantiation: <exr::meta::attribute::FloatRect>::read::<&[u8]>
938
}
939
940
impl SampleType {
941
942
    /// How many bytes a single sample takes up.
943
1.54M
    pub fn bytes_per_sample(&self) -> usize {
944
1.54M
        match self {
945
7.19k
            SampleType::F16 => f16::BYTE_SIZE,
946
1.53M
            SampleType::F32 => f32::BYTE_SIZE,
947
8.77k
            SampleType::U32 => u32::BYTE_SIZE,
948
        }
949
1.54M
    }
950
951
    /// Number of bytes this would consume in an exr file.
952
56
    pub fn byte_size() -> usize {
953
56
        i32::BYTE_SIZE
954
56
    }
955
956
    /// Without validation, write this instance to the byte stream.
957
56
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
958
56
        match *self {
959
0
            SampleType::U32 => 0_i32,
960
0
            SampleType::F16 => 1_i32,
961
56
            SampleType::F32 => 2_i32,
962
56
        }.write(write)?;
963
964
56
        Ok(())
965
56
    }
Unexecuted instantiation: <exr::meta::attribute::SampleType>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::SampleType>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
957
56
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
958
56
        match *self {
959
0
            SampleType::U32 => 0_i32,
960
0
            SampleType::F16 => 1_i32,
961
56
            SampleType::F32 => 2_i32,
962
56
        }.write(write)?;
963
964
56
        Ok(())
965
56
    }
966
967
    /// Read the value without validating.
968
13.5k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
969
13.5k
        // there's definitely going to be more than 255 different pixel types in the future
970
13.5k
        Ok(match i32::read(read)? {
971
5.73k
            0 => SampleType::U32,
972
3.62k
            1 => SampleType::F16,
973
4.20k
            2 => SampleType::F32,
974
19
            _ => return Err(Error::invalid("pixel type attribute value")),
975
        })
976
13.5k
    }
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
<exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
968
10.9k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
969
10.9k
        // there's definitely going to be more than 255 different pixel types in the future
970
10.9k
        Ok(match i32::read(read)? {
971
4.81k
            0 => SampleType::U32,
972
2.08k
            1 => SampleType::F16,
973
4.05k
            2 => SampleType::F32,
974
18
            _ => return Err(Error::invalid("pixel type attribute value")),
975
        })
976
10.9k
    }
<exr::meta::attribute::SampleType>::read::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
968
2.61k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
969
2.61k
        // there's definitely going to be more than 255 different pixel types in the future
970
2.61k
        Ok(match i32::read(read)? {
971
923
            0 => SampleType::U32,
972
1.54k
            1 => SampleType::F16,
973
149
            2 => SampleType::F32,
974
1
            _ => return Err(Error::invalid("pixel type attribute value")),
975
        })
976
2.61k
    }
977
}
978
979
impl ChannelDescription {
980
    /// Choose whether to compress samples linearly or not, based on the channel name.
981
    /// Luminance-based channels will be compressed differently than linear data such as alpha.
982
56
    pub fn guess_quantization_linearity(name: &Text) -> bool {
983
56
        !(
984
56
            name.eq_case_insensitive("R") || name.eq_case_insensitive("G") ||
985
28
                name.eq_case_insensitive("B") || name.eq_case_insensitive("L") ||
986
14
                name.eq_case_insensitive("Y") || name.eq_case_insensitive("X") ||
987
14
                name.eq_case_insensitive("Z")
988
        )
989
56
    }
990
991
    /// Create a new channel with the specified properties and a sampling rate of (1,1).
992
    /// Automatically chooses the linearity for compression based on the channel name.
993
56
    pub fn named(name: impl Into<Text>, sample_type: SampleType) -> Self {
994
56
        let name = name.into();
995
56
        let linearity = Self::guess_quantization_linearity(&name);
996
56
        Self::new(name, sample_type, linearity)
997
56
    }
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::named::<_>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::named::<&str>
<exr::meta::attribute::ChannelDescription>::named::<&str>
Line
Count
Source
993
56
    pub fn named(name: impl Into<Text>, sample_type: SampleType) -> Self {
994
56
        let name = name.into();
995
56
        let linearity = Self::guess_quantization_linearity(&name);
996
56
        Self::new(name, sample_type, linearity)
997
56
    }
998
999
    /*pub fn from_name<T: Into<Sample> + Default>(name: impl Into<Text>) -> Self {
1000
        Self::named(name, T::default().into().sample_type())
1001
    }*/
1002
1003
    /// Create a new channel with the specified properties and a sampling rate of (1,1).
1004
56
    pub fn new(name: impl Into<Text>, sample_type: SampleType, quantize_linearly: bool) -> Self {
1005
56
        Self { name: name.into(), sample_type, quantize_linearly, sampling: Vec2(1, 1) }
1006
56
    }
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::new::<_>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::new::<exr::meta::attribute::Text>
<exr::meta::attribute::ChannelDescription>::new::<exr::meta::attribute::Text>
Line
Count
Source
1004
56
    pub fn new(name: impl Into<Text>, sample_type: SampleType, quantize_linearly: bool) -> Self {
1005
56
        Self { name: name.into(), sample_type, quantize_linearly, sampling: Vec2(1, 1) }
1006
56
    }
1007
1008
    /// The count of pixels this channel contains, respecting subsampling.
1009
    // FIXME this must be used everywhere
1010
0
    pub fn subsampled_pixels(&self, dimensions: Vec2<usize>) -> usize {
1011
0
        self.subsampled_resolution(dimensions).area()
1012
0
    }
1013
1014
    /// The resolution pf this channel, respecting subsampling.
1015
39
    pub fn subsampled_resolution(&self, dimensions: Vec2<usize>) -> Vec2<usize> {
1016
39
        dimensions / self.sampling
1017
39
    }
1018
1019
    /// Number of bytes this would consume in an exr file.
1020
56
    pub fn byte_size(&self) -> usize {
1021
56
        self.name.null_terminated_byte_size()
1022
56
            + SampleType::byte_size()
1023
56
            + 1 // is_linear
1024
56
            + 3 // reserved bytes
1025
56
            + 2 * u32::BYTE_SIZE // sampling x, y
1026
56
    }
1027
1028
    /// Without validation, write this instance to the byte stream.
1029
56
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1030
56
        Text::write_null_terminated(&self.name, write)?;
1031
56
        self.sample_type.write(write)?;
1032
1033
56
        match self.quantize_linearly {
1034
42
            false => 0_u8,
1035
14
            true  => 1_u8,
1036
56
        }.write(write)?;
1037
1038
56
        i8::write_slice(write, &[0_i8, 0_i8, 0_i8])?;
1039
56
        i32::write(usize_to_i32(self.sampling.x()), write)?;
1040
56
        i32::write(usize_to_i32(self.sampling.y()), write)?;
1041
56
        Ok(())
1042
56
    }
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::ChannelDescription>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1029
56
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1030
56
        Text::write_null_terminated(&self.name, write)?;
1031
56
        self.sample_type.write(write)?;
1032
1033
56
        match self.quantize_linearly {
1034
42
            false => 0_u8,
1035
14
            true  => 1_u8,
1036
56
        }.write(write)?;
1037
1038
56
        i8::write_slice(write, &[0_i8, 0_i8, 0_i8])?;
1039
56
        i32::write(usize_to_i32(self.sampling.x()), write)?;
1040
56
        i32::write(usize_to_i32(self.sampling.y()), write)?;
1041
56
        Ok(())
1042
56
    }
1043
1044
    /// Read the value without validating.
1045
13.6k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1046
13.6k
        let name = Text::read_null_terminated(read, 256)?;
1047
13.5k
        let sample_type = SampleType::read(read)?;
1048
1049
13.5k
        let is_linear = match u8::read(read)? {
1050
572
            1 => true,
1051
12.9k
            0 => false,
1052
5
            _ => return Err(Error::invalid("channel linearity attribute value")),
1053
        };
1054
1055
13.5k
        let mut reserved = [0_i8; 3];
1056
13.5k
        i8::read_slice(read, &mut reserved)?;
1057
1058
13.5k
        let x_sampling = i32_to_usize(i32::read(read)?, "x channel sampling")?;
1059
13.5k
        let y_sampling = i32_to_usize(i32::read(read)?, "y channel sampling")?;
1060
1061
13.5k
        Ok(ChannelDescription {
1062
13.5k
            name, sample_type,
1063
13.5k
            quantize_linearly: is_linear,
1064
13.5k
            sampling: Vec2(x_sampling, y_sampling),
1065
13.5k
        })
1066
13.6k
    }
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Unexecuted instantiation: <exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
<exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
1045
10.9k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1046
10.9k
        let name = Text::read_null_terminated(read, 256)?;
1047
10.9k
        let sample_type = SampleType::read(read)?;
1048
1049
10.9k
        let is_linear = match u8::read(read)? {
1050
303
            1 => true,
1051
10.6k
            0 => false,
1052
5
            _ => return Err(Error::invalid("channel linearity attribute value")),
1053
        };
1054
1055
10.9k
        let mut reserved = [0_i8; 3];
1056
10.9k
        i8::read_slice(read, &mut reserved)?;
1057
1058
10.9k
        let x_sampling = i32_to_usize(i32::read(read)?, "x channel sampling")?;
1059
10.9k
        let y_sampling = i32_to_usize(i32::read(read)?, "y channel sampling")?;
1060
1061
10.9k
        Ok(ChannelDescription {
1062
10.9k
            name, sample_type,
1063
10.9k
            quantize_linearly: is_linear,
1064
10.9k
            sampling: Vec2(x_sampling, y_sampling),
1065
10.9k
        })
1066
10.9k
    }
<exr::meta::attribute::ChannelDescription>::read::<exr::io::PeekRead<&[u8]>>
Line
Count
Source
1045
2.61k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1046
2.61k
        let name = Text::read_null_terminated(read, 256)?;
1047
2.61k
        let sample_type = SampleType::read(read)?;
1048
1049
2.61k
        let is_linear = match u8::read(read)? {
1050
269
            1 => true,
1051
2.34k
            0 => false,
1052
0
            _ => return Err(Error::invalid("channel linearity attribute value")),
1053
        };
1054
1055
2.61k
        let mut reserved = [0_i8; 3];
1056
2.61k
        i8::read_slice(read, &mut reserved)?;
1057
1058
2.61k
        let x_sampling = i32_to_usize(i32::read(read)?, "x channel sampling")?;
1059
2.61k
        let y_sampling = i32_to_usize(i32::read(read)?, "y channel sampling")?;
1060
1061
2.61k
        Ok(ChannelDescription {
1062
2.61k
            name, sample_type,
1063
2.61k
            quantize_linearly: is_linear,
1064
2.61k
            sampling: Vec2(x_sampling, y_sampling),
1065
2.61k
        })
1066
2.61k
    }
1067
1068
    /// Validate this instance.
1069
4.73k
    pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1070
4.73k
        self.name.validate(true, None)?; // TODO spec says this does not affect `requirements.long_names` but is that true?
1071
1072
4.73k
        if self.sampling.x() == 0 || self.sampling.y() == 0 {
1073
5
            return Err(Error::invalid("zero sampling factor"));
1074
4.72k
        }
1075
4.72k
1076
4.72k
        if strict && !allow_sampling && self.sampling != Vec2(1,1) {
1077
0
            return Err(Error::invalid("subsampling is only allowed in flat scan line images"));
1078
4.72k
        }
1079
4.72k
1080
4.72k
        if data_window.position.x() % self.sampling.x() as i32 != 0 || data_window.position.y() % self.sampling.y() as i32 != 0 {
1081
36
            return Err(Error::invalid("channel sampling factor not dividing data window position"));
1082
4.69k
        }
1083
4.69k
1084
4.69k
        if data_window.size.x() % self.sampling.x() != 0 || data_window.size.y() % self.sampling.y() != 0 {
1085
6
            return Err(Error::invalid("channel sampling factor not dividing data window size"));
1086
4.68k
        }
1087
4.68k
1088
4.68k
        if self.sampling != Vec2(1,1) {
1089
            // TODO this must only be implemented in the crate::image module and child modules,
1090
            //      should not be too difficult
1091
1092
1
            return Err(Error::unsupported("channel subsampling not supported yet"));
1093
4.68k
        }
1094
4.68k
1095
4.68k
        Ok(())
1096
4.73k
    }
1097
}
1098
1099
impl ChannelList {
1100
1101
    /// Number of bytes this would consume in an exr file.
1102
14
    pub fn byte_size(&self) -> usize {
1103
14
        self.list.iter().map(ChannelDescription::byte_size).sum::<usize>() + sequence_end::byte_size()
1104
14
    }
1105
1106
    /// Without validation, write this instance to the byte stream.
1107
    /// Assumes channels are sorted alphabetically and all values are validated.
1108
14
    pub fn write(&self, write: &mut impl Write) -> UnitResult {
1109
70
        for channel in &self.list {
1110
56
            channel.write(write)?;
1111
        }
1112
1113
14
        sequence_end::write(write)?;
1114
14
        Ok(())
1115
14
    }
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::ChannelList>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1108
14
    pub fn write(&self, write: &mut impl Write) -> UnitResult {
1109
70
        for channel in &self.list {
1110
56
            channel.write(write)?;
1111
        }
1112
1113
14
        sequence_end::write(write)?;
1114
14
        Ok(())
1115
14
    }
1116
1117
    /// Read the value without validating.
1118
7.35k
    pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> {
1119
7.35k
        let mut channels = SmallVec::new();
1120
20.9k
        while !sequence_end::has_come(read)? {
1121
13.6k
            channels.push(ChannelDescription::read(read)?);
1122
        }
1123
1124
7.30k
        Ok(ChannelList::new(channels))
1125
7.35k
    }
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::ChannelList>::read::<&[u8]>
<exr::meta::attribute::ChannelList>::read::<&[u8]>
Line
Count
Source
1118
6.39k
    pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> {
1119
6.39k
        let mut channels = SmallVec::new();
1120
17.3k
        while !sequence_end::has_come(read)? {
1121
10.9k
            channels.push(ChannelDescription::read(read)?);
1122
        }
1123
1124
6.34k
        Ok(ChannelList::new(channels))
1125
6.39k
    }
<exr::meta::attribute::ChannelList>::read::<&[u8]>
Line
Count
Source
1118
959
    pub fn read(read: &mut PeekRead<impl Read>) -> Result<Self> {
1119
959
        let mut channels = SmallVec::new();
1120
3.57k
        while !sequence_end::has_come(read)? {
1121
2.61k
            channels.push(ChannelDescription::read(read)?);
1122
        }
1123
1124
958
        Ok(ChannelList::new(channels))
1125
959
    }
1126
1127
    /// Check if channels are valid and sorted.
1128
1.60k
    pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1129
4.73k
        let mut iter = self.list.iter().map(|chan| chan.validate(allow_sampling, data_window, strict).map(|_| &chan.name));
1130
1.60k
        let mut previous = iter.next().ok_or(Error::invalid("at least one channel is required"))??;
1131
1132
4.68k
        for result in iter {
1133
3.12k
            let value = result?;
1134
3.10k
            if strict && previous == value { return Err(Error::invalid("channel names are not unique")); }
1135
3.10k
            else if previous > value { return Err(Error::invalid("channel names are not sorted alphabetically")); }
1136
3.10k
            else { previous = value; }
1137
        }
1138
1139
1.55k
        Ok(())
1140
1.60k
    }
1141
}
1142
1143
0
fn u8_to_decimal32(binary: u8) -> u32 {
1144
0
    let units = binary as u32 % 10;
1145
0
    let tens = (binary as u32 / 10) % 10;
1146
0
    units | (tens << 4)
1147
0
}
1148
1149
// assumes value fits into u8
1150
0
fn u8_from_decimal32(coded: u32) -> u8 {
1151
0
    ((coded & 0x0f) + 10 * ((coded >> 4) & 0x0f)) as u8
1152
0
}
1153
1154
// https://github.com/AcademySoftwareFoundation/openexr/blob/master/src/lib/OpenEXR/ImfTimeCode.cpp
1155
impl TimeCode {
1156
1157
    /// Number of bytes this would consume in an exr file.
1158
    pub const BYTE_SIZE: usize = 2 * u32::BYTE_SIZE;
1159
1160
    /// Returns an error if this time code is considered invalid.
1161
0
    pub fn validate(&self, strict: bool) -> UnitResult {
1162
0
        if strict {
1163
0
            if self.frame > 29 { Err(Error::invalid("time code frame larger than 29")) }
1164
0
            else if self.seconds > 59 { Err(Error::invalid("time code seconds larger than 59")) }
1165
0
            else if self.minutes > 59 { Err(Error::invalid("time code minutes larger than 59")) }
1166
0
            else if self.hours > 23 { Err(Error::invalid("time code hours larger than 23")) }
1167
0
            else if self.binary_groups.iter().any(|&group| group > 15) {
1168
0
                Err(Error::invalid("time code binary group value too large for 3 bits"))
1169
            }
1170
0
            else { Ok(()) }
1171
        }
1172
0
        else { Ok(()) }
1173
0
    }
1174
1175
1176
    /// Pack the SMPTE time code into a u32 value, according to TV60 packing.
1177
    /// This is the encoding which is used within a binary exr file.
1178
0
    pub fn pack_time_as_tv60_u32(&self) -> Result<u32> {
1179
0
        // validate strictly to prevent set_bit panic! below
1180
0
        self.validate(true)?;
1181
1182
0
        Ok(*0_u32
1183
0
            .set_bits(0..6, u8_to_decimal32(self.frame))
1184
0
            .set_bit(6, self.drop_frame)
1185
0
            .set_bit(7, self.color_frame)
1186
0
            .set_bits(8..15, u8_to_decimal32(self.seconds))
1187
0
            .set_bit(15, self.field_phase)
1188
0
            .set_bits(16..23, u8_to_decimal32(self.minutes))
1189
0
            .set_bit(23, self.binary_group_flags[0])
1190
0
            .set_bits(24..30, u8_to_decimal32(self.hours))
1191
0
            .set_bit(30, self.binary_group_flags[1])
1192
0
            .set_bit(31, self.binary_group_flags[2])
1193
0
        )
1194
0
    }
1195
1196
    /// Unpack a time code from one TV60 encoded u32 value and the encoded user data.
1197
    /// This is the encoding which is used within a binary exr file.
1198
0
    pub fn from_tv60_time(tv60_time: u32, user_data: u32) -> Self {
1199
0
        Self {
1200
0
            frame: u8_from_decimal32(tv60_time.get_bits(0..6)), // cast cannot fail, as these are less than 8 bits
1201
0
            drop_frame: tv60_time.get_bit(6),
1202
0
            color_frame: tv60_time.get_bit(7),
1203
0
            seconds: u8_from_decimal32(tv60_time.get_bits(8..15)), // cast cannot fail, as these are less than 8 bits
1204
0
            field_phase: tv60_time.get_bit(15),
1205
0
            minutes: u8_from_decimal32(tv60_time.get_bits(16..23)), // cast cannot fail, as these are less than 8 bits
1206
0
            hours: u8_from_decimal32(tv60_time.get_bits(24..30)), // cast cannot fail, as these are less than 8 bits
1207
0
            binary_group_flags: [
1208
0
                tv60_time.get_bit(23),
1209
0
                tv60_time.get_bit(30),
1210
0
                tv60_time.get_bit(31),
1211
0
            ],
1212
0
1213
0
            binary_groups: Self::unpack_user_data_from_u32(user_data)
1214
0
        }
1215
0
    }
1216
1217
    /// Pack the SMPTE time code into a u32 value, according to TV50 packing.
1218
    /// This encoding does not support the `drop_frame` flag, it will be lost.
1219
0
    pub fn pack_time_as_tv50_u32(&self) -> Result<u32> {
1220
0
        Ok(*self.pack_time_as_tv60_u32()?
1221
1222
            // swap some fields by replacing some bits in the packed u32
1223
0
            .set_bit(6, false)
1224
0
            .set_bit(15, self.binary_group_flags[0])
1225
0
            .set_bit(30, self.binary_group_flags[1])
1226
0
            .set_bit(23, self.binary_group_flags[2])
1227
0
            .set_bit(31, self.field_phase)
1228
        )
1229
0
    }
1230
1231
    /// Unpack a time code from one TV50 encoded u32 value and the encoded user data.
1232
    /// This encoding does not support the `drop_frame` flag, it will always be false.
1233
0
    pub fn from_tv50_time(tv50_time: u32, user_data: u32) -> Self {
1234
0
        Self {
1235
0
            drop_frame: false, // do not use bit [6]
1236
0
1237
0
            // swap some fields:
1238
0
            field_phase: tv50_time.get_bit(31),
1239
0
            binary_group_flags: [
1240
0
                tv50_time.get_bit(15),
1241
0
                tv50_time.get_bit(30),
1242
0
                tv50_time.get_bit(23),
1243
0
            ],
1244
0
1245
0
            .. Self::from_tv60_time(tv50_time, user_data)
1246
0
        }
1247
0
    }
1248
1249
1250
    /// Pack the SMPTE time code into a u32 value, according to FILM24 packing.
1251
    /// This encoding does not support the `drop_frame` and `color_frame` flags, they will be lost.
1252
0
    pub fn pack_time_as_film24_u32(&self) -> Result<u32> {
1253
0
        Ok(*self.pack_time_as_tv60_u32()?
1254
0
            .set_bit(6, false)
1255
0
            .set_bit(7, false)
1256
        )
1257
0
    }
1258
1259
    /// Unpack a time code from one TV60 encoded u32 value and the encoded user data.
1260
    /// This encoding does not support the `drop_frame` and `color_frame` flags, they will always be `false`.
1261
0
    pub fn from_film24_time(film24_time: u32, user_data: u32) -> Self {
1262
0
        Self {
1263
0
            drop_frame: false, // bit [6]
1264
0
            color_frame: false, // bit [7]
1265
0
            .. Self::from_tv60_time(film24_time, user_data)
1266
0
        }
1267
0
    }
1268
1269
1270
    // in rust, group index starts at zero, not at one.
1271
0
    fn user_data_bit_indices(group_index: usize) -> std::ops::Range<usize> {
1272
0
        let min_bit = 4 * group_index;
1273
0
        min_bit .. min_bit + 4 // +4, not +3, as `Range` is exclusive
1274
0
    }
1275
1276
    /// Pack the user data `u8` array into one u32.
1277
    /// User data values are clamped to the valid range (maximum value is 4).
1278
0
    pub fn pack_user_data_as_u32(&self) -> u32 {
1279
0
        let packed = self.binary_groups.iter().enumerate().fold(0_u32, |mut packed, (group_index, group_value)|
1280
0
            *packed.set_bits(Self::user_data_bit_indices(group_index), *group_value.min(&15) as u32)
1281
0
        );
1282
0
1283
0
        debug_assert_eq!(Self::unpack_user_data_from_u32(packed), self.binary_groups, "round trip user data encoding");
1284
0
        packed
1285
0
    }
1286
1287
    // Unpack the encoded u32 user data to an array of bytes, each byte having a value from 0 to 4.
1288
0
    fn unpack_user_data_from_u32(user_data: u32) -> [u8; 8] {
1289
0
        (0..8).map(|group_index| user_data.get_bits(Self::user_data_bit_indices(group_index)) as u8)
1290
0
            .collect::<SmallVec<[u8;8]>>().into_inner().expect("array index bug")
1291
0
    }
1292
1293
1294
    /// Write this time code to the byte stream, encoded as TV60 integers.
1295
    /// Returns an `Error::Invalid` if the fields are out of the allowed range.
1296
0
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1297
0
        self.pack_time_as_tv60_u32()?.write(write)?; // will validate
1298
0
        self.pack_user_data_as_u32().write(write)?;
1299
0
        Ok(())
1300
0
    }
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
1301
1302
    /// Read the time code, without validating, extracting from TV60 integers.
1303
0
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1304
0
        let time_and_flags = u32::read(read)?;
1305
0
        let user_data = u32::read(read)?;
1306
0
        Ok(Self::from_tv60_time(time_and_flags, user_data))
1307
0
    }
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TimeCode>::read::<&[u8]>
1308
}
1309
1310
impl Chromaticities {
1311
1312
    /// Number of bytes this would consume in an exr file.
1313
0
    pub fn byte_size() -> usize {
1314
0
        8 * f32::BYTE_SIZE
1315
0
    }
1316
1317
    /// Without validation, write this instance to the byte stream.
1318
0
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1319
0
        self.red.x().write(write)?;
1320
0
        self.red.y().write(write)?;
1321
1322
0
        self.green.x().write(write)?;
1323
0
        self.green.y().write(write)?;
1324
1325
0
        self.blue.x().write(write)?;
1326
0
        self.blue.y().write(write)?;
1327
1328
0
        self.white.x().write(write)?;
1329
0
        self.white.y().write(write)?;
1330
0
        Ok(())
1331
0
    }
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
1332
1333
    /// Read the value without validating.
1334
1.10k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1335
1.10k
        Ok(Chromaticities {
1336
1.10k
            red: Vec2(f32::read(read)?, f32::read(read)?),
1337
1.10k
            green: Vec2(f32::read(read)?, f32::read(read)?),
1338
1.10k
            blue: Vec2(f32::read(read)?, f32::read(read)?),
1339
1.10k
            white: Vec2(f32::read(read)?, f32::read(read)?),
1340
        })
1341
1.10k
    }
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Chromaticities>::read::<&[u8]>
<exr::meta::attribute::Chromaticities>::read::<&[u8]>
Line
Count
Source
1334
1.10k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1335
1.10k
        Ok(Chromaticities {
1336
1.10k
            red: Vec2(f32::read(read)?, f32::read(read)?),
1337
1.10k
            green: Vec2(f32::read(read)?, f32::read(read)?),
1338
1.10k
            blue: Vec2(f32::read(read)?, f32::read(read)?),
1339
1.10k
            white: Vec2(f32::read(read)?, f32::read(read)?),
1340
        })
1341
1.10k
    }
1342
}
1343
1344
impl Compression {
1345
1346
    /// Number of bytes this would consume in an exr file.
1347
14
    pub fn byte_size() -> usize { u8::BYTE_SIZE }
1348
1349
    /// Without validation, write this instance to the byte stream.
1350
14
    pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1351
        use self::Compression::*;
1352
14
        match self {
1353
0
            Uncompressed => 0_u8,
1354
14
            RLE => 1_u8,
1355
0
            ZIP1 => 2_u8,
1356
0
            ZIP16 => 3_u8,
1357
0
            PIZ => 4_u8,
1358
0
            PXR24 => 5_u8,
1359
0
            B44 => 6_u8,
1360
0
            B44A => 7_u8,
1361
0
            DWAA(_) => 8_u8,
1362
0
            DWAB(_) => 9_u8,
1363
14
        }.write(write)?;
1364
14
        Ok(())
1365
14
    }
Unexecuted instantiation: <exr::compression::Compression>::write::<_>
Unexecuted instantiation: <exr::compression::Compression>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::compression::Compression>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1350
14
    pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1351
        use self::Compression::*;
1352
14
        match self {
1353
0
            Uncompressed => 0_u8,
1354
14
            RLE => 1_u8,
1355
0
            ZIP1 => 2_u8,
1356
0
            ZIP16 => 3_u8,
1357
0
            PIZ => 4_u8,
1358
0
            PXR24 => 5_u8,
1359
0
            B44 => 6_u8,
1360
0
            B44A => 7_u8,
1361
0
            DWAA(_) => 8_u8,
1362
0
            DWAB(_) => 9_u8,
1363
14
        }.write(write)?;
1364
14
        Ok(())
1365
14
    }
1366
1367
    /// Read the value without validating.
1368
11.2k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1369
        use self::Compression::*;
1370
11.2k
        Ok(match u8::read(read)? {
1371
307
            0 => Uncompressed,
1372
25
            1 => RLE,
1373
6.85k
            2 => ZIP1,
1374
2
            3 => ZIP16,
1375
268
            4 => PIZ,
1376
1
            5 => PXR24,
1377
1
            6 => B44,
1378
2.27k
            7 => B44A,
1379
11
            8 => DWAA(None),
1380
1.52k
            9 => DWAB(None),
1381
0
            _ => return Err(Error::unsupported("unknown compression method")),
1382
        })
1383
11.2k
    }
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<_>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
Unexecuted instantiation: <exr::compression::Compression>::read::<&[u8]>
<exr::compression::Compression>::read::<&[u8]>
Line
Count
Source
1368
10.4k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1369
        use self::Compression::*;
1370
10.4k
        Ok(match u8::read(read)? {
1371
307
            0 => Uncompressed,
1372
1
            1 => RLE,
1373
6.85k
            2 => ZIP1,
1374
2
            3 => ZIP16,
1375
2
            4 => PIZ,
1376
1
            5 => PXR24,
1377
1
            6 => B44,
1378
1.75k
            7 => B44A,
1379
11
            8 => DWAA(None),
1380
1.52k
            9 => DWAB(None),
1381
0
            _ => return Err(Error::unsupported("unknown compression method")),
1382
        })
1383
10.4k
    }
<exr::compression::Compression>::read::<&[u8]>
Line
Count
Source
1368
807
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1369
        use self::Compression::*;
1370
807
        Ok(match u8::read(read)? {
1371
0
            0 => Uncompressed,
1372
24
            1 => RLE,
1373
0
            2 => ZIP1,
1374
0
            3 => ZIP16,
1375
266
            4 => PIZ,
1376
0
            5 => PXR24,
1377
0
            6 => B44,
1378
517
            7 => B44A,
1379
0
            8 => DWAA(None),
1380
0
            9 => DWAB(None),
1381
0
            _ => return Err(Error::unsupported("unknown compression method")),
1382
        })
1383
807
    }
1384
}
1385
1386
impl EnvironmentMap {
1387
1388
    /// Number of bytes this would consume in an exr file.
1389
0
    pub fn byte_size() -> usize {
1390
0
        u8::BYTE_SIZE
1391
0
    }
1392
1393
    /// Without validation, write this instance to the byte stream.
1394
0
    pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1395
        use self::EnvironmentMap::*;
1396
0
        match self {
1397
0
            LatitudeLongitude => 0_u8,
1398
0
            Cube => 1_u8
1399
0
        }.write(write)?;
1400
1401
0
        Ok(())
1402
0
    }
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
1403
1404
    /// Read the value without validating.
1405
0
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1406
        use self::EnvironmentMap::*;
1407
0
        Ok(match u8::read(read)? {
1408
0
            0 => LatitudeLongitude,
1409
0
            1 => Cube,
1410
0
            _ => return Err(Error::invalid("environment map attribute value")),
1411
        })
1412
0
    }
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::EnvironmentMap>::read::<&[u8]>
1413
}
1414
1415
impl KeyCode {
1416
1417
    /// Number of bytes this would consume in an exr file.
1418
0
    pub fn byte_size() -> usize {
1419
0
        6 * i32::BYTE_SIZE
1420
0
    }
1421
1422
    /// Without validation, write this instance to the byte stream.
1423
0
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1424
0
        self.film_manufacturer_code.write(write)?;
1425
0
        self.film_type.write(write)?;
1426
0
        self.film_roll_prefix.write(write)?;
1427
0
        self.count.write(write)?;
1428
0
        self.perforation_offset.write(write)?;
1429
0
        self.perforations_per_count.write(write)?;
1430
0
        Ok(())
1431
0
    }
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
1432
1433
    /// Read the value without validating.
1434
0
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1435
0
        Ok(KeyCode {
1436
0
            film_manufacturer_code: i32::read(read)?,
1437
0
            film_type: i32::read(read)?,
1438
0
            film_roll_prefix: i32::read(read)?,
1439
0
            count: i32::read(read)?,
1440
0
            perforation_offset: i32::read(read)?,
1441
0
            perforations_per_frame: i32::read(read)?,
1442
0
            perforations_per_count: i32::read(read)?,
1443
        })
1444
0
    }
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::KeyCode>::read::<&[u8]>
1445
}
1446
1447
impl LineOrder {
1448
1449
    /// Number of bytes this would consume in an exr file.
1450
14
    pub fn byte_size() -> usize {
1451
14
        u8::BYTE_SIZE
1452
14
    }
1453
1454
    /// Without validation, write this instance to the byte stream.
1455
14
    pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1456
        use self::LineOrder::*;
1457
14
        match self {
1458
0
            Increasing => 0_u8,
1459
0
            Decreasing => 1_u8,
1460
14
            Unspecified => 2_u8,
1461
14
        }.write(write)?;
1462
1463
14
        Ok(())
1464
14
    }
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::LineOrder>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1455
14
    pub fn write<W: Write>(self, write: &mut W) -> UnitResult {
1456
        use self::LineOrder::*;
1457
14
        match self {
1458
0
            Increasing => 0_u8,
1459
0
            Decreasing => 1_u8,
1460
14
            Unspecified => 2_u8,
1461
14
        }.write(write)?;
1462
1463
14
        Ok(())
1464
14
    }
1465
1466
    /// Read the value without validating.
1467
3.01k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1468
        use self::LineOrder::*;
1469
3.01k
        Ok(match u8::read(read)? {
1470
2.99k
            0 => Increasing,
1471
0
            1 => Decreasing,
1472
14
            2 => Unspecified,
1473
1
            _ => return Err(Error::invalid("line order attribute value")),
1474
        })
1475
3.01k
    }
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::LineOrder>::read::<&[u8]>
<exr::meta::attribute::LineOrder>::read::<&[u8]>
Line
Count
Source
1467
2.97k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1468
        use self::LineOrder::*;
1469
2.97k
        Ok(match u8::read(read)? {
1470
2.97k
            0 => Increasing,
1471
0
            1 => Decreasing,
1472
0
            2 => Unspecified,
1473
1
            _ => return Err(Error::invalid("line order attribute value")),
1474
        })
1475
2.97k
    }
<exr::meta::attribute::LineOrder>::read::<&[u8]>
Line
Count
Source
1467
38
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1468
        use self::LineOrder::*;
1469
38
        Ok(match u8::read(read)? {
1470
24
            0 => Increasing,
1471
0
            1 => Decreasing,
1472
14
            2 => Unspecified,
1473
0
            _ => return Err(Error::invalid("line order attribute value")),
1474
        })
1475
38
    }
1476
}
1477
1478
1479
1480
1481
impl Preview {
1482
1483
    /// Number of bytes this would consume in an exr file.
1484
0
    pub fn byte_size(&self) -> usize {
1485
0
        2 * u32::BYTE_SIZE + self.pixel_data.len()
1486
0
    }
1487
1488
    /// Without validation, write this instance to the byte stream.
1489
0
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1490
0
        u32::write(self.size.width() as u32, write)?;
1491
0
        u32::write(self.size.height() as u32, write)?;
1492
1493
0
        i8::write_slice(write, &self.pixel_data)?;
1494
0
        Ok(())
1495
0
    }
Unexecuted instantiation: <exr::meta::attribute::Preview>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::Preview>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Unexecuted instantiation: <exr::meta::attribute::Preview>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
1496
1497
    /// Read the value without validating.
1498
259
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1499
259
        let width = u32::read(read)? as usize;
1500
259
        let height = u32::read(read)? as usize;
1501
1502
259
        if let Some(pixel_count) = width.checked_mul(height) {
1503
            // Multiply by the number of bytes per pixel.
1504
259
            if let Some(byte_count) = pixel_count.checked_mul(4) {
1505
259
                let pixel_data = i8::read_vec(
1506
259
                    read,
1507
259
                    byte_count,
1508
259
                    1024 * 1024 * 4,
1509
259
                    None,
1510
259
                    "preview attribute pixel count",
1511
259
                )?;
1512
1513
259
                let preview = Preview {
1514
259
                    size: Vec2(width, height),
1515
259
                    pixel_data,
1516
259
                };
1517
259
1518
259
                return Ok(preview);
1519
0
            }
1520
0
        }
1521
1522
0
        return Err(Error::invalid(
1523
0
                format!("Overflow while calculating preview image Attribute size \
1524
0
                (width: {}, height: {}).",
1525
0
                width,
1526
0
                height)));
1527
259
    }
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::Preview>::read::<&[u8]>
<exr::meta::attribute::Preview>::read::<&[u8]>
Line
Count
Source
1498
259
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1499
259
        let width = u32::read(read)? as usize;
1500
259
        let height = u32::read(read)? as usize;
1501
1502
259
        if let Some(pixel_count) = width.checked_mul(height) {
1503
            // Multiply by the number of bytes per pixel.
1504
259
            if let Some(byte_count) = pixel_count.checked_mul(4) {
1505
259
                let pixel_data = i8::read_vec(
1506
259
                    read,
1507
259
                    byte_count,
1508
259
                    1024 * 1024 * 4,
1509
259
                    None,
1510
259
                    "preview attribute pixel count",
1511
259
                )?;
1512
1513
259
                let preview = Preview {
1514
259
                    size: Vec2(width, height),
1515
259
                    pixel_data,
1516
259
                };
1517
259
1518
259
                return Ok(preview);
1519
0
            }
1520
0
        }
1521
1522
0
        return Err(Error::invalid(
1523
0
                format!("Overflow while calculating preview image Attribute size \
1524
0
                (width: {}, height: {}).",
1525
0
                width,
1526
0
                height)));
1527
259
    }
1528
1529
    /// Validate this instance.
1530
87
    pub fn validate(&self, strict: bool) -> UnitResult {
1531
87
        if strict && (self.size.area() * 4 != self.pixel_data.len()) {
1532
0
            return Err(Error::invalid("preview dimensions do not match content length"))
1533
87
        }
1534
87
1535
87
        Ok(())
1536
87
    }
1537
}
1538
1539
impl ::std::fmt::Debug for Preview {
1540
0
    fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
1541
0
        write!(f, "Preview ({}x{} px)", self.size.width(), self.size.height())
1542
0
    }
1543
}
1544
1545
impl TileDescription {
1546
1547
    /// Number of bytes this would consume in an exr file.
1548
14
    pub fn byte_size() -> usize {
1549
14
        2 * u32::BYTE_SIZE + 1 // size x,y + (level mode + rounding mode)
1550
14
    }
1551
1552
    /// Without validation, write this instance to the byte stream.
1553
14
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1554
14
        u32::write(self.tile_size.width() as u32, write)?;
1555
14
        u32::write(self.tile_size.height() as u32, write)?;
1556
1557
14
        let level_mode = match self.level_mode {
1558
14
            LevelMode::Singular => 0_u8,
1559
0
            LevelMode::MipMap => 1_u8,
1560
0
            LevelMode::RipMap => 2_u8,
1561
        };
1562
1563
14
        let rounding_mode = match self.rounding_mode {
1564
14
            RoundingMode::Down => 0_u8,
1565
0
            RoundingMode::Up => 1_u8,
1566
        };
1567
1568
14
        let mode: u8 = level_mode + (rounding_mode * 16);
1569
14
        mode.write(write)?;
1570
14
        Ok(())
1571
14
    }
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::TileDescription>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1553
14
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1554
14
        u32::write(self.tile_size.width() as u32, write)?;
1555
14
        u32::write(self.tile_size.height() as u32, write)?;
1556
1557
14
        let level_mode = match self.level_mode {
1558
14
            LevelMode::Singular => 0_u8,
1559
0
            LevelMode::MipMap => 1_u8,
1560
0
            LevelMode::RipMap => 2_u8,
1561
        };
1562
1563
14
        let rounding_mode = match self.rounding_mode {
1564
14
            RoundingMode::Down => 0_u8,
1565
0
            RoundingMode::Up => 1_u8,
1566
        };
1567
1568
14
        let mode: u8 = level_mode + (rounding_mode * 16);
1569
14
        mode.write(write)?;
1570
14
        Ok(())
1571
14
    }
1572
1573
    /// Read the value without validating.
1574
2.15k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1575
2.15k
        let x_size = u32::read(read)? as usize;
1576
2.15k
        let y_size = u32::read(read)? as usize;
1577
1578
2.15k
        let mode = u8::read(read)?;
1579
1580
        // wow you really saved that one byte here
1581
        // mode = level_mode + (rounding_mode * 16)
1582
2.15k
        let level_mode = mode & 0b00001111; // wow that works
1583
2.15k
        let rounding_mode = mode >> 4; // wow that works
1584
1585
2.15k
        let level_mode = match level_mode {
1586
1.97k
            0 => LevelMode::Singular,
1587
115
            1 => LevelMode::MipMap,
1588
65
            2 => LevelMode::RipMap,
1589
0
            _ => return Err(Error::invalid("tile description level mode")),
1590
        };
1591
1592
2.15k
        let rounding_mode = match rounding_mode {
1593
1.61k
            0 => RoundingMode::Down,
1594
533
            1 => RoundingMode::Up,
1595
0
            _ => return Err(Error::invalid("tile description rounding mode")),
1596
        };
1597
1598
2.15k
        Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, })
1599
2.15k
    }
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
Unexecuted instantiation: <exr::meta::attribute::TileDescription>::read::<&[u8]>
<exr::meta::attribute::TileDescription>::read::<&[u8]>
Line
Count
Source
1574
1.36k
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1575
1.36k
        let x_size = u32::read(read)? as usize;
1576
1.36k
        let y_size = u32::read(read)? as usize;
1577
1578
1.36k
        let mode = u8::read(read)?;
1579
1580
        // wow you really saved that one byte here
1581
        // mode = level_mode + (rounding_mode * 16)
1582
1.36k
        let level_mode = mode & 0b00001111; // wow that works
1583
1.36k
        let rounding_mode = mode >> 4; // wow that works
1584
1585
1.36k
        let level_mode = match level_mode {
1586
1.18k
            0 => LevelMode::Singular,
1587
115
            1 => LevelMode::MipMap,
1588
65
            2 => LevelMode::RipMap,
1589
0
            _ => return Err(Error::invalid("tile description level mode")),
1590
        };
1591
1592
1.36k
        let rounding_mode = match rounding_mode {
1593
832
            0 => RoundingMode::Down,
1594
533
            1 => RoundingMode::Up,
1595
0
            _ => return Err(Error::invalid("tile description rounding mode")),
1596
        };
1597
1598
1.36k
        Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, })
1599
1.36k
    }
<exr::meta::attribute::TileDescription>::read::<&[u8]>
Line
Count
Source
1574
786
    pub fn read<R: Read>(read: &mut R) -> Result<Self> {
1575
786
        let x_size = u32::read(read)? as usize;
1576
786
        let y_size = u32::read(read)? as usize;
1577
1578
786
        let mode = u8::read(read)?;
1579
1580
        // wow you really saved that one byte here
1581
        // mode = level_mode + (rounding_mode * 16)
1582
786
        let level_mode = mode & 0b00001111; // wow that works
1583
786
        let rounding_mode = mode >> 4; // wow that works
1584
1585
786
        let level_mode = match level_mode {
1586
786
            0 => LevelMode::Singular,
1587
0
            1 => LevelMode::MipMap,
1588
0
            2 => LevelMode::RipMap,
1589
0
            _ => return Err(Error::invalid("tile description level mode")),
1590
        };
1591
1592
786
        let rounding_mode = match rounding_mode {
1593
786
            0 => RoundingMode::Down,
1594
0
            1 => RoundingMode::Up,
1595
0
            _ => return Err(Error::invalid("tile description rounding mode")),
1596
        };
1597
1598
786
        Ok(TileDescription { tile_size: Vec2(x_size, y_size), level_mode, rounding_mode, })
1599
786
    }
1600
1601
    /// Validate this instance.
1602
1.52k
    pub fn validate(&self) -> UnitResult {
1603
1.52k
        let max = i32::MAX as i64 / 2;
1604
1.52k
1605
1.52k
        if self.tile_size.width() == 0 || self.tile_size.height() == 0
1606
1.52k
            || self.tile_size.width() as i64 >= max || self.tile_size.height() as i64 >= max
1607
        {
1608
3
            return Err(Error::invalid("tile size"))
1609
1.51k
        }
1610
1.51k
1611
1.51k
        Ok(())
1612
1.52k
    }
1613
}
1614
1615
1616
/// Number of bytes this attribute would consume in an exr file.
1617
// TODO instead of pre calculating byte size, write to a tmp buffer whose length is inspected before actually writing?
1618
0
pub fn byte_size(name: &Text, value: &AttributeValue) -> usize {
1619
0
    name.null_terminated_byte_size()
1620
0
        + value.kind_name().len() + sequence_end::byte_size()
1621
0
        + i32::BYTE_SIZE // serialized byte size
1622
0
        + value.byte_size()
1623
0
}
1624
1625
/// Without validation, write this attribute to the byte stream.
1626
154
pub fn write<W: Write>(name: &TextSlice, value: &AttributeValue, write: &mut W) -> UnitResult {
1627
154
    Text::write_null_terminated_bytes(name, write)?;
1628
154
    Text::write_null_terminated_bytes(value.kind_name(), write)?;
1629
154
    i32::write(value.byte_size() as i32, write)?;
1630
154
    value.write(write)
1631
154
}
Unexecuted instantiation: exr::meta::attribute::write::<_>
Unexecuted instantiation: exr::meta::attribute::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
exr::meta::attribute::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1626
154
pub fn write<W: Write>(name: &TextSlice, value: &AttributeValue, write: &mut W) -> UnitResult {
1627
154
    Text::write_null_terminated_bytes(name, write)?;
1628
154
    Text::write_null_terminated_bytes(value.kind_name(), write)?;
1629
154
    i32::write(value.byte_size() as i32, write)?;
1630
154
    value.write(write)
1631
154
}
1632
1633
/// Read the attribute without validating. The result may be `Ok` even if this single attribute is invalid.
1634
602k
pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1635
602k
    let name = Text::read_null_terminated(read, max_size)?;
1636
601k
    let kind = Text::read_null_terminated(read, max_size)?;
1637
601k
    let size = i32_to_usize(i32::read(read)?, "attribute size")?;
1638
601k
    let value = AttributeValue::read(read, kind, size)?;
1639
600k
    Ok((name, value))
1640
602k
}
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<_>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Line
Count
Source
1634
567k
pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1635
567k
    let name = Text::read_null_terminated(read, max_size)?;
1636
567k
    let kind = Text::read_null_terminated(read, max_size)?;
1637
566k
    let size = i32_to_usize(i32::read(read)?, "attribute size")?;
1638
566k
    let value = AttributeValue::read(read, kind, size)?;
1639
565k
    Ok((name, value))
1640
567k
}
exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Line
Count
Source
1634
154
pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1635
154
    let name = Text::read_null_terminated(read, max_size)?;
1636
154
    let kind = Text::read_null_terminated(read, max_size)?;
1637
154
    let size = i32_to_usize(i32::read(read)?, "attribute size")?;
1638
154
    let value = AttributeValue::read(read, kind, size)?;
1639
154
    Ok((name, value))
1640
154
}
exr::meta::attribute::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Line
Count
Source
1634
34.4k
pub fn read(read: &mut PeekRead<impl Read>, max_size: usize) -> Result<(Text, Result<AttributeValue>)> {
1635
34.4k
    let name = Text::read_null_terminated(read, max_size)?;
1636
34.4k
    let kind = Text::read_null_terminated(read, max_size)?;
1637
34.4k
    let size = i32_to_usize(i32::read(read)?, "attribute size")?;
1638
34.4k
    let value = AttributeValue::read(read, kind, size)?;
1639
34.4k
    Ok((name, value))
1640
34.4k
}
1641
1642
/// Validate this attribute.
1643
10.5k
pub fn validate(name: &Text, value: &AttributeValue, long_names: &mut bool, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1644
10.5k
    name.validate(true, Some(long_names))?; // only name text has length restriction
1645
10.5k
    value.validate(allow_sampling, data_window, strict) // attribute value text length is never restricted
1646
10.5k
}
1647
1648
1649
impl AttributeValue {
1650
1651
    /// Number of bytes this would consume in an exr file.
1652
154
    pub fn byte_size(&self) -> usize {
1653
        use self::AttributeValue::*;
1654
1655
154
        match *self {
1656
28
            IntegerBounds(_) => self::IntegerBounds::byte_size(),
1657
0
            FloatRect(_) => self::FloatRect::byte_size(),
1658
1659
14
            I32(_) => i32::BYTE_SIZE,
1660
28
            F32(_) => f32::BYTE_SIZE,
1661
0
            F64(_) => f64::BYTE_SIZE,
1662
1663
0
            Rational(_) => { i32::BYTE_SIZE + u32::BYTE_SIZE },
1664
0
            TimeCode(_) => self::TimeCode::BYTE_SIZE,
1665
1666
0
            IntVec2(_) => { 2 * i32::BYTE_SIZE },
1667
14
            FloatVec2(_) => { 2 * f32::BYTE_SIZE },
1668
0
            IntVec3(_) => { 3 * i32::BYTE_SIZE },
1669
0
            FloatVec3(_) => { 3 * f32::BYTE_SIZE },
1670
1671
14
            ChannelList(ref channels) => channels.byte_size(),
1672
0
            Chromaticities(_) => self::Chromaticities::byte_size(),
1673
14
            Compression(_) => self::Compression::byte_size(),
1674
0
            EnvironmentMap(_) => self::EnvironmentMap::byte_size(),
1675
1676
0
            KeyCode(_) => self::KeyCode::byte_size(),
1677
14
            LineOrder(_) => self::LineOrder::byte_size(),
1678
1679
0
            Matrix3x3(ref value) => value.len() * f32::BYTE_SIZE,
1680
0
            Matrix4x4(ref value) => value.len() * f32::BYTE_SIZE,
1681
1682
0
            Preview(ref value) => value.byte_size(),
1683
1684
            // attribute value texts never have limited size.
1685
            // also, don't serialize size, as it can be inferred from attribute size
1686
0
            Text(ref value) => value.bytes.len(),
1687
1688
0
            TextVector(ref value) => value.iter().map(self::Text::i32_sized_byte_size).sum(),
1689
14
            TileDescription(_) => self::TileDescription::byte_size(),
1690
0
            Custom { ref bytes, .. } => bytes.len(),
1691
14
            BlockType(ref kind) => kind.byte_size()
1692
        }
1693
154
    }
1694
1695
    /// The exr name string of the type that an attribute can have.
1696
154
    pub fn kind_name(&self) -> &TextSlice {
1697
        use self::AttributeValue::*;
1698
        use self::type_names as ty;
1699
1700
154
        match *self {
1701
28
            IntegerBounds(_) =>  ty::I32BOX2,
1702
0
            FloatRect(_) =>  ty::F32BOX2,
1703
14
            I32(_) =>  ty::I32,
1704
28
            F32(_) =>  ty::F32,
1705
0
            F64(_) =>  ty::F64,
1706
0
            Rational(_) => ty::RATIONAL,
1707
0
            TimeCode(_) => ty::TIME_CODE,
1708
0
            IntVec2(_) => ty::I32VEC2,
1709
14
            FloatVec2(_) => ty::F32VEC2,
1710
0
            IntVec3(_) => ty::I32VEC3,
1711
0
            FloatVec3(_) => ty::F32VEC3,
1712
14
            ChannelList(_) =>  ty::CHANNEL_LIST,
1713
0
            Chromaticities(_) =>  ty::CHROMATICITIES,
1714
14
            Compression(_) =>  ty::COMPRESSION,
1715
0
            EnvironmentMap(_) =>  ty::ENVIRONMENT_MAP,
1716
0
            KeyCode(_) =>  ty::KEY_CODE,
1717
14
            LineOrder(_) =>  ty::LINE_ORDER,
1718
0
            Matrix3x3(_) =>  ty::F32MATRIX3X3,
1719
0
            Matrix4x4(_) =>  ty::F32MATRIX4X4,
1720
0
            Preview(_) =>  ty::PREVIEW,
1721
0
            Text(_) =>  ty::TEXT,
1722
0
            TextVector(_) =>  ty::TEXT_VECTOR,
1723
14
            TileDescription(_) =>  ty::TILES,
1724
14
            BlockType(_) => super::BlockType::TYPE_NAME,
1725
0
            Custom { ref kind, .. } => kind.as_slice(),
1726
        }
1727
154
    }
1728
1729
    /// Without validation, write this instance to the byte stream.
1730
154
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1731
        use self::AttributeValue::*;
1732
154
        match *self {
1733
28
            IntegerBounds(value) => value.write(write)?,
1734
0
            FloatRect(value) => value.write(write)?,
1735
1736
14
            I32(value) => value.write(write)?,
1737
28
            F32(value) => value.write(write)?,
1738
0
            F64(value) => value.write(write)?,
1739
1740
0
            Rational((a, b)) => { a.write(write)?; b.write(write)?; },
1741
0
            TimeCode(codes) => { codes.write(write)?; },
1742
1743
0
            IntVec2(Vec2(x, y)) => { x.write(write)?; y.write(write)?; },
1744
14
            FloatVec2(Vec2(x, y)) => { x.write(write)?; y.write(write)?; },
1745
0
            IntVec3((x, y, z)) => { x.write(write)?; y.write(write)?; z.write(write)?; },
1746
0
            FloatVec3((x, y, z)) => { x.write(write)?; y.write(write)?; z.write(write)?; },
1747
1748
14
            ChannelList(ref channels) => channels.write(write)?,
1749
0
            Chromaticities(ref value) => value.write(write)?,
1750
14
            Compression(value) => value.write(write)?,
1751
0
            EnvironmentMap(value) => value.write(write)?,
1752
1753
0
            KeyCode(value) => value.write(write)?,
1754
14
            LineOrder(value) => value.write(write)?,
1755
1756
0
            Matrix3x3(mut value) => f32::write_slice(write, &mut value)?,
1757
0
            Matrix4x4(mut value) => f32::write_slice(write, &mut value)?,
1758
1759
0
            Preview(ref value) => { value.write(write)?; },
1760
1761
            // attribute value texts never have limited size.
1762
            // also, don't serialize size, as it can be inferred from attribute size
1763
0
            Text(ref value) => u8::write_slice(write, value.bytes.as_slice())?,
1764
1765
0
            TextVector(ref value) => self::Text::write_vec_of_i32_sized_texts(write, value)?,
1766
14
            TileDescription(ref value) => value.write(write)?,
1767
0
            Custom { ref bytes, .. } => u8::write_slice(write, &bytes)?, // write.write(&bytes).map(|_| ()),
1768
14
            BlockType(kind) => kind.write(write)?
1769
        };
1770
1771
154
        Ok(())
1772
154
    }
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::write::<_>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::write::<exr::io::Tracking<&mut &mut std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
<exr::meta::attribute::AttributeValue>::write::<exr::io::Tracking<&mut std::io::cursor::Cursor<&mut alloc::vec::Vec<u8>>>>
Line
Count
Source
1730
154
    pub fn write<W: Write>(&self, write: &mut W) -> UnitResult {
1731
        use self::AttributeValue::*;
1732
154
        match *self {
1733
28
            IntegerBounds(value) => value.write(write)?,
1734
0
            FloatRect(value) => value.write(write)?,
1735
1736
14
            I32(value) => value.write(write)?,
1737
28
            F32(value) => value.write(write)?,
1738
0
            F64(value) => value.write(write)?,
1739
1740
0
            Rational((a, b)) => { a.write(write)?; b.write(write)?; },
1741
0
            TimeCode(codes) => { codes.write(write)?; },
1742
1743
0
            IntVec2(Vec2(x, y)) => { x.write(write)?; y.write(write)?; },
1744
14
            FloatVec2(Vec2(x, y)) => { x.write(write)?; y.write(write)?; },
1745
0
            IntVec3((x, y, z)) => { x.write(write)?; y.write(write)?; z.write(write)?; },
1746
0
            FloatVec3((x, y, z)) => { x.write(write)?; y.write(write)?; z.write(write)?; },
1747
1748
14
            ChannelList(ref channels) => channels.write(write)?,
1749
0
            Chromaticities(ref value) => value.write(write)?,
1750
14
            Compression(value) => value.write(write)?,
1751
0
            EnvironmentMap(value) => value.write(write)?,
1752
1753
0
            KeyCode(value) => value.write(write)?,
1754
14
            LineOrder(value) => value.write(write)?,
1755
1756
0
            Matrix3x3(mut value) => f32::write_slice(write, &mut value)?,
1757
0
            Matrix4x4(mut value) => f32::write_slice(write, &mut value)?,
1758
1759
0
            Preview(ref value) => { value.write(write)?; },
1760
1761
            // attribute value texts never have limited size.
1762
            // also, don't serialize size, as it can be inferred from attribute size
1763
0
            Text(ref value) => u8::write_slice(write, value.bytes.as_slice())?,
1764
1765
0
            TextVector(ref value) => self::Text::write_vec_of_i32_sized_texts(write, value)?,
1766
14
            TileDescription(ref value) => value.write(write)?,
1767
0
            Custom { ref bytes, .. } => u8::write_slice(write, &bytes)?, // write.write(&bytes).map(|_| ()),
1768
14
            BlockType(kind) => kind.write(write)?
1769
        };
1770
1771
154
        Ok(())
1772
154
    }
1773
1774
    /// Read the value without validating.
1775
    /// Returns `Ok(Ok(attribute))` for valid attributes.
1776
    /// Returns `Ok(Err(Error))` for invalid attributes from a valid byte source.
1777
    /// Returns `Err(Error)` for invalid byte sources, for example for invalid files.
1778
601k
    pub fn read(read: &mut PeekRead<impl Read>, kind: Text, byte_size: usize) -> Result<Result<Self>> {
1779
        use self::AttributeValue::*;
1780
        use self::type_names as ty;
1781
1782
        // always read bytes
1783
601k
        let attribute_bytes = u8::read_vec(read, byte_size, 128, None, "attribute value size")?;
1784
        // TODO no allocation for small attributes // : SmallVec<[u8; 64]> = smallvec![0; byte_size];
1785
1786
600k
        let parse_attribute = move || {
1787
600k
            let reader = &mut attribute_bytes.as_slice();
1788
600k
1789
600k
            Ok(match kind.bytes.as_slice() {
1790
600k
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
172
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
466k
                ty::I32 => I32(i32::read(reader)?),
1794
57.6k
                ty::F32 => F32(f32::read(reader)?),
1795
373k
                ty::F64 => F64(f64::read(reader)?),
1796
1797
273k
                ty::RATIONAL => Rational({
1798
30.3k
                    let a = i32::read(reader)?;
1799
30.3k
                    let b = u32::read(reader)?;
1800
30.3k
                    (a, b)
1801
                }),
1802
1803
0
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
390
                    let a = i32::read(reader)?;
1807
390
                    let b = i32::read(reader)?;
1808
390
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
25.5k
                    let a = f32::read(reader)?;
1813
25.5k
                    let b = f32::read(reader)?;
1814
25.5k
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
126
                    let a = i32::read(reader)?;
1819
126
                    let b = i32::read(reader)?;
1820
126
                    let c = i32::read(reader)?;
1821
125
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
739
                    let a = f32::read(reader)?;
1826
739
                    let b = f32::read(reader)?;
1827
739
                    let c = f32::read(reader)?;
1828
734
                    (a, b, c)
1829
                }),
1830
1831
7.35k
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
218k
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
210k
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
0
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
175k
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
159k
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
142k
                ty::F32MATRIX3X3 => Matrix3x3({
1840
1.02k
                    let mut result = [0.0_f32; 9];
1841
1.02k
                    f32::read_slice(reader, &mut result)?;
1842
1.02k
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
8.15k
                    let mut result = [0.0_f32; 16];
1847
8.15k
                    f32::read_slice(reader, &mut result)?;
1848
8.15k
                    result
1849
                }),
1850
1851
259
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
54.0k
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
100k
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
358
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
358
                    byte_size
1858
358
                )?),
1859
1860
2.15k
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
347k
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
600k
        };
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<_>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Line
Count
Source
1786
565k
        let parse_attribute = move || {
1787
565k
            let reader = &mut attribute_bytes.as_slice();
1788
565k
1789
565k
            Ok(match kind.bytes.as_slice() {
1790
565k
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
172
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
440k
                ty::I32 => I32(i32::read(reader)?),
1794
53.9k
                ty::F32 => F32(f32::read(reader)?),
1795
348k
                ty::F64 => F64(f64::read(reader)?),
1796
1797
261k
                ty::RATIONAL => Rational({
1798
30.3k
                    let a = i32::read(reader)?;
1799
30.3k
                    let b = u32::read(reader)?;
1800
30.3k
                    (a, b)
1801
                }),
1802
1803
0
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
390
                    let a = i32::read(reader)?;
1807
390
                    let b = i32::read(reader)?;
1808
390
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
25.5k
                    let a = f32::read(reader)?;
1813
25.5k
                    let b = f32::read(reader)?;
1814
25.5k
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
126
                    let a = i32::read(reader)?;
1819
126
                    let b = i32::read(reader)?;
1820
126
                    let c = i32::read(reader)?;
1821
125
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
739
                    let a = f32::read(reader)?;
1826
739
                    let b = f32::read(reader)?;
1827
739
                    let c = f32::read(reader)?;
1828
734
                    (a, b, c)
1829
                }),
1830
1831
6.39k
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
206k
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
199k
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
0
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
165k
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
151k
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
134k
                ty::F32MATRIX3X3 => Matrix3x3({
1840
1.02k
                    let mut result = [0.0_f32; 9];
1841
1.02k
                    f32::read_slice(reader, &mut result)?;
1842
1.02k
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
6.12k
                    let mut result = [0.0_f32; 16];
1847
6.12k
                    f32::read_slice(reader, &mut result)?;
1848
6.12k
                    result
1849
                }),
1850
1851
0
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
46.4k
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
95.8k
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
0
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
0
                    byte_size
1858
0
                )?),
1859
1860
1.36k
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
332k
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
565k
        };
<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>::{closure#0}
Line
Count
Source
1786
154
        let parse_attribute = move || {
1787
154
            let reader = &mut attribute_bytes.as_slice();
1788
154
1789
154
            Ok(match kind.bytes.as_slice() {
1790
154
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
0
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
98
                ty::I32 => I32(i32::read(reader)?),
1794
28
                ty::F32 => F32(f32::read(reader)?),
1795
70
                ty::F64 => F64(f64::read(reader)?),
1796
1797
42
                ty::RATIONAL => Rational({
1798
0
                    let a = i32::read(reader)?;
1799
0
                    let b = u32::read(reader)?;
1800
0
                    (a, b)
1801
                }),
1802
1803
0
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
0
                    let a = i32::read(reader)?;
1807
0
                    let b = i32::read(reader)?;
1808
0
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
14
                    let a = f32::read(reader)?;
1813
14
                    let b = f32::read(reader)?;
1814
14
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
0
                    let a = i32::read(reader)?;
1819
0
                    let b = i32::read(reader)?;
1820
0
                    let c = i32::read(reader)?;
1821
0
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
0
                    let a = f32::read(reader)?;
1826
0
                    let b = f32::read(reader)?;
1827
0
                    let c = f32::read(reader)?;
1828
0
                    (a, b, c)
1829
                }),
1830
1831
14
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
28
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
28
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
0
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
14
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
14
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
0
                ty::F32MATRIX3X3 => Matrix3x3({
1840
0
                    let mut result = [0.0_f32; 9];
1841
0
                    f32::read_slice(reader, &mut result)?;
1842
0
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
0
                    let mut result = [0.0_f32; 16];
1847
0
                    f32::read_slice(reader, &mut result)?;
1848
0
                    result
1849
                }),
1850
1851
0
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
14
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
0
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
0
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
0
                    byte_size
1858
0
                )?),
1859
1860
14
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
0
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
154
        };
<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>::{closure#0}
Line
Count
Source
1786
34.4k
        let parse_attribute = move || {
1787
34.4k
            let reader = &mut attribute_bytes.as_slice();
1788
34.4k
1789
34.4k
            Ok(match kind.bytes.as_slice() {
1790
34.4k
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
0
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
26.4k
                ty::I32 => I32(i32::read(reader)?),
1794
3.73k
                ty::F32 => F32(f32::read(reader)?),
1795
25.3k
                ty::F64 => F64(f64::read(reader)?),
1796
1797
12.8k
                ty::RATIONAL => Rational({
1798
0
                    let a = i32::read(reader)?;
1799
0
                    let b = u32::read(reader)?;
1800
0
                    (a, b)
1801
                }),
1802
1803
0
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
0
                    let a = i32::read(reader)?;
1807
0
                    let b = i32::read(reader)?;
1808
0
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
23
                    let a = f32::read(reader)?;
1813
23
                    let b = f32::read(reader)?;
1814
23
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
0
                    let a = i32::read(reader)?;
1819
0
                    let b = i32::read(reader)?;
1820
0
                    let c = i32::read(reader)?;
1821
0
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
0
                    let a = f32::read(reader)?;
1826
0
                    let b = f32::read(reader)?;
1827
0
                    let c = f32::read(reader)?;
1828
0
                    (a, b, c)
1829
                }),
1830
1831
945
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
11.4k
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
10.0k
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
0
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
9.19k
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
8.47k
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
8.22k
                ty::F32MATRIX3X3 => Matrix3x3({
1840
0
                    let mut result = [0.0_f32; 9];
1841
0
                    f32::read_slice(reader, &mut result)?;
1842
0
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
2.03k
                    let mut result = [0.0_f32; 16];
1847
2.03k
                    f32::read_slice(reader, &mut result)?;
1848
2.03k
                    result
1849
                }),
1850
1851
259
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
7.57k
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
5.04k
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
358
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
358
                    byte_size
1858
358
                )?),
1859
1860
772
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
14.5k
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
34.4k
        };
1865
1866
600k
        Ok(parse_attribute())
1867
601k
    }
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<_>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Unexecuted instantiation: <exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Line
Count
Source
1778
566k
    pub fn read(read: &mut PeekRead<impl Read>, kind: Text, byte_size: usize) -> Result<Result<Self>> {
1779
        use self::AttributeValue::*;
1780
        use self::type_names as ty;
1781
1782
        // always read bytes
1783
566k
        let attribute_bytes = u8::read_vec(read, byte_size, 128, None, "attribute value size")?;
1784
        // TODO no allocation for small attributes // : SmallVec<[u8; 64]> = smallvec![0; byte_size];
1785
1786
565k
        let parse_attribute = move || {
1787
            let reader = &mut attribute_bytes.as_slice();
1788
1789
            Ok(match kind.bytes.as_slice() {
1790
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
                ty::I32 => I32(i32::read(reader)?),
1794
                ty::F32 => F32(f32::read(reader)?),
1795
                ty::F64 => F64(f64::read(reader)?),
1796
1797
                ty::RATIONAL => Rational({
1798
                    let a = i32::read(reader)?;
1799
                    let b = u32::read(reader)?;
1800
                    (a, b)
1801
                }),
1802
1803
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
                    let a = i32::read(reader)?;
1807
                    let b = i32::read(reader)?;
1808
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
                    let a = f32::read(reader)?;
1813
                    let b = f32::read(reader)?;
1814
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
                    let a = i32::read(reader)?;
1819
                    let b = i32::read(reader)?;
1820
                    let c = i32::read(reader)?;
1821
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
                    let a = f32::read(reader)?;
1826
                    let b = f32::read(reader)?;
1827
                    let c = f32::read(reader)?;
1828
                    (a, b, c)
1829
                }),
1830
1831
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
                ty::F32MATRIX3X3 => Matrix3x3({
1840
                    let mut result = [0.0_f32; 9];
1841
                    f32::read_slice(reader, &mut result)?;
1842
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
                    let mut result = [0.0_f32; 16];
1847
                    f32::read_slice(reader, &mut result)?;
1848
                    result
1849
                }),
1850
1851
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
                    byte_size
1858
                )?),
1859
1860
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
        };
1865
1866
565k
        Ok(parse_attribute())
1867
566k
    }
<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<alloc::vec::Vec<u8>>>>
Line
Count
Source
1778
154
    pub fn read(read: &mut PeekRead<impl Read>, kind: Text, byte_size: usize) -> Result<Result<Self>> {
1779
        use self::AttributeValue::*;
1780
        use self::type_names as ty;
1781
1782
        // always read bytes
1783
154
        let attribute_bytes = u8::read_vec(read, byte_size, 128, None, "attribute value size")?;
1784
        // TODO no allocation for small attributes // : SmallVec<[u8; 64]> = smallvec![0; byte_size];
1785
1786
154
        let parse_attribute = move || {
1787
            let reader = &mut attribute_bytes.as_slice();
1788
1789
            Ok(match kind.bytes.as_slice() {
1790
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
                ty::I32 => I32(i32::read(reader)?),
1794
                ty::F32 => F32(f32::read(reader)?),
1795
                ty::F64 => F64(f64::read(reader)?),
1796
1797
                ty::RATIONAL => Rational({
1798
                    let a = i32::read(reader)?;
1799
                    let b = u32::read(reader)?;
1800
                    (a, b)
1801
                }),
1802
1803
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
                    let a = i32::read(reader)?;
1807
                    let b = i32::read(reader)?;
1808
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
                    let a = f32::read(reader)?;
1813
                    let b = f32::read(reader)?;
1814
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
                    let a = i32::read(reader)?;
1819
                    let b = i32::read(reader)?;
1820
                    let c = i32::read(reader)?;
1821
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
                    let a = f32::read(reader)?;
1826
                    let b = f32::read(reader)?;
1827
                    let c = f32::read(reader)?;
1828
                    (a, b, c)
1829
                }),
1830
1831
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
                ty::F32MATRIX3X3 => Matrix3x3({
1840
                    let mut result = [0.0_f32; 9];
1841
                    f32::read_slice(reader, &mut result)?;
1842
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
                    let mut result = [0.0_f32; 16];
1847
                    f32::read_slice(reader, &mut result)?;
1848
                    result
1849
                }),
1850
1851
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
                    byte_size
1858
                )?),
1859
1860
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
        };
1865
1866
154
        Ok(parse_attribute())
1867
154
    }
<exr::meta::attribute::AttributeValue>::read::<exr::io::Tracking<std::io::cursor::Cursor<&[u8]>>>
Line
Count
Source
1778
34.4k
    pub fn read(read: &mut PeekRead<impl Read>, kind: Text, byte_size: usize) -> Result<Result<Self>> {
1779
        use self::AttributeValue::*;
1780
        use self::type_names as ty;
1781
1782
        // always read bytes
1783
34.4k
        let attribute_bytes = u8::read_vec(read, byte_size, 128, None, "attribute value size")?;
1784
        // TODO no allocation for small attributes // : SmallVec<[u8; 64]> = smallvec![0; byte_size];
1785
1786
34.4k
        let parse_attribute = move || {
1787
            let reader = &mut attribute_bytes.as_slice();
1788
1789
            Ok(match kind.bytes.as_slice() {
1790
                ty::I32BOX2 => IntegerBounds(self::IntegerBounds::read(reader)?),
1791
                ty::F32BOX2 => FloatRect(self::FloatRect::read(reader)?),
1792
1793
                ty::I32 => I32(i32::read(reader)?),
1794
                ty::F32 => F32(f32::read(reader)?),
1795
                ty::F64 => F64(f64::read(reader)?),
1796
1797
                ty::RATIONAL => Rational({
1798
                    let a = i32::read(reader)?;
1799
                    let b = u32::read(reader)?;
1800
                    (a, b)
1801
                }),
1802
1803
                ty::TIME_CODE => TimeCode(self::TimeCode::read(reader)?),
1804
1805
                ty::I32VEC2 => IntVec2({
1806
                    let a = i32::read(reader)?;
1807
                    let b = i32::read(reader)?;
1808
                    Vec2(a, b)
1809
                }),
1810
1811
                ty::F32VEC2 => FloatVec2({
1812
                    let a = f32::read(reader)?;
1813
                    let b = f32::read(reader)?;
1814
                    Vec2(a, b)
1815
                }),
1816
1817
                ty::I32VEC3 => IntVec3({
1818
                    let a = i32::read(reader)?;
1819
                    let b = i32::read(reader)?;
1820
                    let c = i32::read(reader)?;
1821
                    (a, b, c)
1822
                }),
1823
1824
                ty::F32VEC3 => FloatVec3({
1825
                    let a = f32::read(reader)?;
1826
                    let b = f32::read(reader)?;
1827
                    let c = f32::read(reader)?;
1828
                    (a, b, c)
1829
                }),
1830
1831
                ty::CHANNEL_LIST    => ChannelList(self::ChannelList::read(&mut PeekRead::new(attribute_bytes.as_slice()))?),
1832
                ty::CHROMATICITIES  => Chromaticities(self::Chromaticities::read(reader)?),
1833
                ty::COMPRESSION     => Compression(self::Compression::read(reader)?),
1834
                ty::ENVIRONMENT_MAP => EnvironmentMap(self::EnvironmentMap::read(reader)?),
1835
1836
                ty::KEY_CODE   => KeyCode(self::KeyCode::read(reader)?),
1837
                ty::LINE_ORDER => LineOrder(self::LineOrder::read(reader)?),
1838
1839
                ty::F32MATRIX3X3 => Matrix3x3({
1840
                    let mut result = [0.0_f32; 9];
1841
                    f32::read_slice(reader, &mut result)?;
1842
                    result
1843
                }),
1844
1845
                ty::F32MATRIX4X4 => Matrix4x4({
1846
                    let mut result = [0.0_f32; 16];
1847
                    f32::read_slice(reader, &mut result)?;
1848
                    result
1849
                }),
1850
1851
                ty::PREVIEW     => Preview(self::Preview::read(reader)?),
1852
                ty::TEXT        => Text(self::Text::read_sized(reader, byte_size)?),
1853
1854
                // the number of strings can be inferred from the total attribute size
1855
                ty::TEXT_VECTOR => TextVector(self::Text::read_vec_of_i32_sized(
1856
                    &mut PeekRead::new(attribute_bytes.as_slice()),
1857
                    byte_size
1858
                )?),
1859
1860
                ty::TILES       => TileDescription(self::TileDescription::read(reader)?),
1861
1862
                _ => Custom { kind: kind.clone(), bytes: attribute_bytes.clone() } // TODO no clone
1863
            })
1864
        };
1865
1866
34.4k
        Ok(parse_attribute())
1867
34.4k
    }
1868
1869
    /// Validate this instance.
1870
10.5k
    pub fn validate(&self, allow_sampling: bool, data_window: IntegerBounds, strict: bool) -> UnitResult {
1871
        use self::AttributeValue::*;
1872
1873
10.5k
        match *self {
1874
90
            ChannelList(ref channels) => channels.validate(allow_sampling, data_window, strict)?,
1875
151
            TileDescription(ref value) => value.validate()?,
1876
87
            Preview(ref value) => value.validate(strict)?,
1877
0
            TimeCode(ref time_code) => time_code.validate(strict)?,
1878
1879
0
            TextVector(ref vec) => if strict && vec.is_empty() {
1880
0
                return Err(Error::invalid("text vector may not be empty"))
1881
0
            },
1882
1883
10.2k
            _ => {}
1884
        };
1885
1886
10.5k
        Ok(())
1887
10.5k
    }
1888
1889
1890
    /// Return `Ok(i32)` if this attribute is an i32.
1891
0
    pub fn to_i32(&self) -> Result<i32> {
1892
0
        match *self {
1893
0
            AttributeValue::I32(value) => Ok(value),
1894
0
            _ => Err(invalid_type())
1895
        }
1896
0
    }
1897
1898
    /// Return `Ok(f32)` if this attribute is an f32.
1899
0
    pub fn to_f32(&self) -> Result<f32> {
1900
0
        match *self {
1901
0
            AttributeValue::F32(value) => Ok(value),
1902
0
            _ => Err(invalid_type())
1903
        }
1904
0
    }
1905
1906
    /// Return `Ok(Text)` if this attribute is a text.
1907
0
    pub fn into_text(self) -> Result<Text> {
1908
0
        match self {
1909
0
            AttributeValue::Text(value) => Ok(value),
1910
0
            _ => Err(invalid_type())
1911
        }
1912
0
    }
1913
1914
    /// Return `Ok(Text)` if this attribute is a text.
1915
0
    pub fn to_text(&self) -> Result<&Text> {
1916
0
        match self {
1917
0
            AttributeValue::Text(value) => Ok(value),
1918
0
            _ => Err(invalid_type())
1919
        }
1920
0
    }
1921
1922
    /// Return `Ok(Chromaticities)` if this attribute is a chromaticities attribute.
1923
0
    pub fn to_chromaticities(&self) -> Result<Chromaticities> {
1924
0
        match *self {
1925
0
            AttributeValue::Chromaticities(value) => Ok(value),
1926
0
            _ => Err(invalid_type())
1927
        }
1928
0
    }
1929
1930
    /// Return `Ok(TimeCode)` if this attribute is a time code.
1931
0
    pub fn to_time_code(&self) -> Result<TimeCode> {
1932
0
        match *self {
1933
0
            AttributeValue::TimeCode(value) => Ok(value),
1934
0
            _ => Err(invalid_type())
1935
        }
1936
0
    }
1937
}
1938
1939
1940
1941
/// Contains string literals identifying the type of an attribute.
1942
pub mod type_names {
1943
    macro_rules! define_attribute_type_names {
1944
        ( $($name: ident : $value: expr),* ) => {
1945
            $(
1946
                /// The byte-string name of this attribute type as it appears in an exr file.
1947
                pub const $name: &'static [u8] = $value;
1948
            )*
1949
        };
1950
    }
1951
1952
    define_attribute_type_names! {
1953
        I32BOX2:        b"box2i",
1954
        F32BOX2:        b"box2f",
1955
        I32:            b"int",
1956
        F32:            b"float",
1957
        F64:            b"double",
1958
        RATIONAL:       b"rational",
1959
        TIME_CODE:      b"timecode",
1960
        I32VEC2:        b"v2i",
1961
        F32VEC2:        b"v2f",
1962
        I32VEC3:        b"v3i",
1963
        F32VEC3:        b"v3f",
1964
        CHANNEL_LIST:   b"chlist",
1965
        CHROMATICITIES: b"chromaticities",
1966
        COMPRESSION:    b"compression",
1967
        ENVIRONMENT_MAP:b"envmap",
1968
        KEY_CODE:       b"keycode",
1969
        LINE_ORDER:     b"lineOrder",
1970
        F32MATRIX3X3:   b"m33f",
1971
        F32MATRIX4X4:   b"m44f",
1972
        PREVIEW:        b"preview",
1973
        TEXT:           b"string",
1974
        TEXT_VECTOR:    b"stringvector",
1975
        TILES:          b"tiledesc"
1976
    }
1977
}
1978
1979
1980
#[cfg(test)]
1981
mod test {
1982
    use super::*;
1983
    use ::std::io::Cursor;
1984
    use rand::{random, thread_rng, Rng};
1985
1986
    #[test]
1987
    fn text_ord() {
1988
        for _ in 0..1024 {
1989
            let text1 = Text::from_bytes_unchecked((0..4).map(|_| rand::random::<u8>()).collect());
1990
            let text2 = Text::from_bytes_unchecked((0..4).map(|_| rand::random::<u8>()).collect());
1991
1992
            assert_eq!(text1.to_string().cmp(&text2.to_string()), text1.cmp(&text2), "in text {:?} vs {:?}", text1, text2);
1993
        }
1994
    }
1995
1996
    #[test]
1997
    fn rounding_up(){
1998
        let round_up = RoundingMode::Up;
1999
        assert_eq!(round_up.divide(10, 10), 1, "divide equal");
2000
        assert_eq!(round_up.divide(10, 2), 5, "divide even");
2001
        assert_eq!(round_up.divide(10, 5), 2, "divide even");
2002
2003
        assert_eq!(round_up.divide(8, 5), 2, "round up");
2004
        assert_eq!(round_up.divide(10, 3), 4, "round up");
2005
        assert_eq!(round_up.divide(100, 50), 2, "divide even");
2006
        assert_eq!(round_up.divide(100, 49), 3, "round up");
2007
    }
2008
2009
    #[test]
2010
    fn rounding_down(){
2011
        let round_down = RoundingMode::Down;
2012
        assert_eq!(round_down.divide(8, 5), 1, "round down");
2013
        assert_eq!(round_down.divide(10, 3), 3, "round down");
2014
        assert_eq!(round_down.divide(100, 50), 2, "divide even");
2015
        assert_eq!(round_down.divide(100, 49), 2, "round down");
2016
        assert_eq!(round_down.divide(100, 51), 1, "round down");
2017
    }
2018
2019
    #[test]
2020
    fn tile_description_write_read_roundtrip(){
2021
        let tiles = [
2022
            TileDescription {
2023
                tile_size: Vec2(31, 7),
2024
                level_mode: LevelMode::MipMap,
2025
                rounding_mode: RoundingMode::Down,
2026
            },
2027
2028
            TileDescription {
2029
                tile_size: Vec2(0, 0),
2030
                level_mode: LevelMode::Singular,
2031
                rounding_mode: RoundingMode::Up,
2032
            },
2033
2034
            TileDescription {
2035
                tile_size: Vec2(4294967294, 4294967295),
2036
                level_mode: LevelMode::RipMap,
2037
                rounding_mode: RoundingMode::Down,
2038
            },
2039
        ];
2040
2041
        for tile in &tiles {
2042
            let mut bytes = Vec::new();
2043
            tile.write(&mut bytes).unwrap();
2044
2045
            let new_tile = TileDescription::read(&mut Cursor::new(bytes)).unwrap();
2046
            assert_eq!(*tile, new_tile, "tile round trip");
2047
        }
2048
    }
2049
2050
    #[test]
2051
    fn attribute_write_read_roundtrip_and_byte_size(){
2052
        let attributes = [
2053
            (
2054
                Text::from("greeting"),
2055
                AttributeValue::Text(Text::from("hello")),
2056
            ),
2057
            (
2058
                Text::from("age"),
2059
                AttributeValue::I32(923),
2060
            ),
2061
            (
2062
                Text::from("leg count"),
2063
                AttributeValue::F64(9.114939599234),
2064
            ),
2065
            (
2066
                Text::from("rabbit area"),
2067
                AttributeValue::FloatRect(FloatRect {
2068
                    min: Vec2(23.4234, 345.23),
2069
                    max: Vec2(68623.0, 3.12425926538),
2070
                }),
2071
            ),
2072
            (
2073
                Text::from("rabbit area int"),
2074
                AttributeValue::IntegerBounds(IntegerBounds {
2075
                    position: Vec2(23, 345),
2076
                    size: Vec2(68623, 3),
2077
                }),
2078
            ),
2079
            (
2080
                Text::from("rabbit area int"),
2081
                AttributeValue::IntegerBounds(IntegerBounds {
2082
                    position: Vec2(-(i32::MAX / 2 - 1), -(i32::MAX / 2 - 1)),
2083
                    size: Vec2(i32::MAX as usize - 2, i32::MAX as usize - 2),
2084
                }),
2085
            ),
2086
            (
2087
                Text::from("rabbit area int 2"),
2088
                AttributeValue::IntegerBounds(IntegerBounds {
2089
                    position: Vec2(0, 0),
2090
                    size: Vec2(i32::MAX as usize / 2 - 1, i32::MAX as usize / 2 - 1),
2091
                }),
2092
            ),
2093
            (
2094
                Text::from("tests are difficult"),
2095
                AttributeValue::TextVector(vec![
2096
                    Text::from("sdoifjpsdv"),
2097
                    Text::from("sdoifjpsdvxxxx"),
2098
                    Text::from("sdoifjasd"),
2099
                    Text::from("sdoifj"),
2100
                    Text::from("sdoifjddddddddasdasd"),
2101
                ]),
2102
            ),
2103
            (
2104
                Text::from("what should we eat tonight"),
2105
                AttributeValue::Preview(Preview {
2106
                    size: Vec2(10, 30),
2107
                    pixel_data: vec![31; 10 * 30 * 4],
2108
                }),
2109
            ),
2110
            (
2111
                Text::from("leg count, again"),
2112
                AttributeValue::ChannelList(ChannelList::new(smallvec![
2113
                        ChannelDescription {
2114
                            name: Text::from("Green"),
2115
                            sample_type: SampleType::F16,
2116
                            quantize_linearly: false,
2117
                            sampling: Vec2(1,2)
2118
                        },
2119
                        ChannelDescription {
2120
                            name: Text::from("Red"),
2121
                            sample_type: SampleType::F32,
2122
                            quantize_linearly: true,
2123
                            sampling: Vec2(1,2)
2124
                        },
2125
                        ChannelDescription {
2126
                            name: Text::from("Purple"),
2127
                            sample_type: SampleType::U32,
2128
                            quantize_linearly: false,
2129
                            sampling: Vec2(0,0)
2130
                        }
2131
                    ],
2132
                )),
2133
            ),
2134
        ];
2135
2136
        for (name, value) in &attributes {
2137
            let mut bytes = Vec::new();
2138
            super::write(name.as_slice(), value, &mut bytes).unwrap();
2139
            assert_eq!(super::byte_size(name, value), bytes.len(), "attribute.byte_size() for {:?}", (name, value));
2140
2141
            let new_attribute = super::read(&mut PeekRead::new(Cursor::new(bytes)), 300).unwrap();
2142
            assert_eq!((name.clone(), value.clone()), (new_attribute.0, new_attribute.1.unwrap()), "attribute round trip");
2143
        }
2144
2145
2146
        {
2147
            let (name, value) = (
2148
                Text::from("asdkaspfokpaosdkfpaokswdpoakpsfokaposdkf"),
2149
                AttributeValue::I32(0),
2150
            );
2151
2152
            let mut long_names = false;
2153
            super::validate(&name, &value, &mut long_names, false, IntegerBounds::zero(), false).unwrap();
2154
            assert!(long_names);
2155
        }
2156
2157
        {
2158
            let (name, value) = (
2159
                Text::from("sdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfposdöksadöofkaspdolkpöasolfkcöalsod,kfcöaslodkcpöasolkfpo"),
2160
                AttributeValue::I32(0),
2161
            );
2162
2163
            super::validate(&name, &value, &mut false, false, IntegerBounds::zero(), false).expect_err("name length check failed");
2164
        }
2165
    }
2166
2167
    #[test]
2168
    fn time_code_pack(){
2169
        let mut rng = thread_rng();
2170
2171
        let codes = std::iter::repeat_with(|| TimeCode {
2172
            hours: rng.gen_range(0 .. 24),
2173
            minutes: rng.gen_range(0 .. 60),
2174
            seconds: rng.gen_range(0 .. 60),
2175
            frame: rng.gen_range(0 .. 29),
2176
            drop_frame: random(),
2177
            color_frame: random(),
2178
            field_phase: random(),
2179
            binary_group_flags: [random(),random(),random()],
2180
            binary_groups: std::iter::repeat_with(|| rng.gen_range(0 .. 16)).take(8)
2181
                .collect::<SmallVec<[u8;8]>>().into_inner().unwrap()
2182
        });
2183
2184
        for code in codes.take(500) {
2185
            code.validate(true).expect("invalid timecode test input");
2186
2187
            {   // through tv60 packing, roundtrip
2188
                let packed_tv60 = code.pack_time_as_tv60_u32().expect("invalid timecode test input");
2189
                let packed_user = code.pack_user_data_as_u32();
2190
                assert_eq!(TimeCode::from_tv60_time(packed_tv60, packed_user), code);
2191
            }
2192
2193
            {   // through bytes, roundtrip
2194
                let mut bytes = Vec::<u8>::new();
2195
                code.write(&mut bytes).unwrap();
2196
                let decoded = TimeCode::read(&mut bytes.as_slice()).unwrap();
2197
                assert_eq!(code, decoded);
2198
            }
2199
2200
            {
2201
                let tv50_code = TimeCode {
2202
                    drop_frame: false, // apparently, tv50 does not support drop frame, so do not use this value
2203
                   .. code
2204
                };
2205
2206
                let packed_tv50 = code.pack_time_as_tv50_u32().expect("invalid timecode test input");
2207
                let packed_user = code.pack_user_data_as_u32();
2208
                assert_eq!(TimeCode::from_tv50_time(packed_tv50, packed_user), tv50_code);
2209
            }
2210
2211
            {
2212
                let film24_code = TimeCode {
2213
                    // apparently, film24 does not support some flags, so do not use those values
2214
                    color_frame: false,
2215
                    drop_frame: false,
2216
                   .. code
2217
                };
2218
2219
                let packed_film24 = code.pack_time_as_film24_u32().expect("invalid timecode test input");
2220
                let packed_user = code.pack_user_data_as_u32();
2221
                assert_eq!(TimeCode::from_film24_time(packed_film24, packed_user), film24_code);
2222
            }
2223
        }
2224
    }
2225
2226
}