exr/meta/
attribute.rs

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