Coverage Report

Created: 2026-03-20 07:09

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