Coverage Report

Created: 2026-07-16 07:16

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