aboutsummaryrefslogtreecommitdiff
path: root/vendor/exr/src/io.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/exr/src/io.rs')
-rw-r--r--vendor/exr/src/io.rs447
1 files changed, 0 insertions, 447 deletions
diff --git a/vendor/exr/src/io.rs b/vendor/exr/src/io.rs
deleted file mode 100644
index 1fb863b..0000000
--- a/vendor/exr/src/io.rs
+++ /dev/null
@@ -1,447 +0,0 @@
-
-//! Specialized binary input and output.
-//! Uses the error handling for this crate.
-
-#![doc(hidden)]
-pub use ::std::io::{Read, Write};
-
-use half::slice::{HalfFloatSliceExt};
-use lebe::prelude::*;
-use ::half::f16;
-use crate::error::{Error, Result, UnitResult, IoResult};
-use std::io::{Seek, SeekFrom};
-use std::path::Path;
-use std::fs::File;
-use std::convert::TryFrom;
-
-
-/// Skip reading uninteresting bytes without allocating.
-#[inline]
-pub fn skip_bytes(read: &mut impl Read, count: usize) -> IoResult<()> {
- let count = u64::try_from(count).unwrap();
-
- let skipped = std::io::copy(
- &mut read.by_ref().take(count),
- &mut std::io::sink()
- )?;
-
- // the reader may have ended before we skipped the desired number of bytes
- if skipped < count {
- return Err(std::io::Error::new(
- std::io::ErrorKind::UnexpectedEof,
- "cannot skip more bytes than exist"
- ));
- }
-
- debug_assert_eq!(skipped, count, "skip bytes bug");
- Ok(())
-}
-
-/// If an error occurs while writing, attempts to delete the partially written file.
-/// Creates a file just before the first write operation, not when this function is called.
-#[inline]
-pub fn attempt_delete_file_on_write_error<'p>(path: &'p Path, write: impl FnOnce(LateFile<'p>) -> UnitResult) -> UnitResult {
- match write(LateFile::from(path)) {
- Err(error) => { // FIXME deletes existing file if creation of new file fails?
- let _deleted = std::fs::remove_file(path); // ignore deletion errors
- Err(error)
- },
-
- ok => ok,
- }
-}
-
-#[derive(Debug)]
-pub struct LateFile<'p> {
- path: &'p Path,
- file: Option<File>
-}
-
-impl<'p> From<&'p Path> for LateFile<'p> {
- fn from(path: &'p Path) -> Self { Self { path, file: None } }
-}
-
-impl<'p> LateFile<'p> {
- fn file(&mut self) -> std::io::Result<&mut File> {
- if self.file.is_none() { self.file = Some(File::create(self.path)?); }
- Ok(self.file.as_mut().unwrap()) // will not be reached if creation fails
- }
-}
-
-impl<'p> std::io::Write for LateFile<'p> {
- fn write(&mut self, buffer: &[u8]) -> std::io::Result<usize> {
- self.file()?.write(buffer)
- }
-
- fn flush(&mut self) -> std::io::Result<()> {
- if let Some(file) = &mut self.file { file.flush() }
- else { Ok(()) }
- }
-}
-
-impl<'p> Seek for LateFile<'p> {
- fn seek(&mut self, position: SeekFrom) -> std::io::Result<u64> {
- self.file()?.seek(position)
- }
-}
-
-
-/// Peek a single byte without consuming it.
-#[derive(Debug)]
-pub struct PeekRead<T> {
-
- /// Cannot be exposed as it will not contain peeked values anymore.
- inner: T,
-
- peeked: Option<IoResult<u8>>,
-}
-
-impl<T: Read> PeekRead<T> {
-
- /// Wrap a reader to make it peekable.
- #[inline]
- pub fn new(inner: T) -> Self {
- Self { inner, peeked: None }
- }
-
- /// Read a single byte and return that without consuming it.
- /// The next `read` call will include that byte.
- #[inline]
- pub fn peek_u8(&mut self) -> &IoResult<u8> {
- self.peeked = self.peeked.take().or_else(|| Some(u8::read_from_little_endian(&mut self.inner)));
- self.peeked.as_ref().unwrap() // unwrap cannot fail because we just set it
- }
-
- /// Skip a single byte if it equals the specified value.
- /// Returns whether the value was found.
- /// Consumes the peeked result if an error occurred.
- #[inline]
- pub fn skip_if_eq(&mut self, value: u8) -> IoResult<bool> {
- match self.peek_u8() {
- Ok(peeked) if *peeked == value => {
- self.peeked = None; // consume the byte
- Ok(true)
- },
-
- Ok(_) => Ok(false),
-
- // return the error otherwise.
- // unwrap is safe because this branch cannot be reached otherwise.
- // we need to take() from self because io errors cannot be cloned.
- Err(_) => Err(self.peeked.take().unwrap().err().unwrap())
- }
- }
-}
-
-
-impl<T: Read> Read for PeekRead<T> {
- fn read(&mut self, target_buffer: &mut [u8]) -> IoResult<usize> {
- if target_buffer.is_empty() {
- return Ok(0)
- }
-
- match self.peeked.take() {
- None => self.inner.read(target_buffer),
- Some(peeked) => {
- target_buffer[0] = peeked?;
-
- // indexing [1..] is safe because an empty buffer already returned ok
- Ok(1 + self.inner.read(&mut target_buffer[1..])?)
- }
- }
- }
-}
-
-impl<T: Read + Seek> PeekRead<Tracking<T>> {
-
- /// Seek this read to the specified byte position.
- /// Discards any previously peeked value.
- pub fn skip_to(&mut self, position: usize) -> std::io::Result<()> {
- self.inner.seek_read_to(position)?;
- self.peeked = None;
- Ok(())
- }
-}
-
-impl<T: Read> PeekRead<Tracking<T>> {
-
- /// Current number of bytes read.
- pub fn byte_position(&self) -> usize {
- self.inner.byte_position()
- }
-}
-
-/// Keep track of what byte we are at.
-/// Used to skip back to a previous place after writing some information.
-#[derive(Debug)]
-pub struct Tracking<T> {
-
- /// Do not expose to prevent seeking without updating position
- inner: T,
-
- position: usize,
-}
-
-impl<T: Read> Read for Tracking<T> {
- fn read(&mut self, buffer: &mut [u8]) -> std::io::Result<usize> {
- let count = self.inner.read(buffer)?;
- self.position += count;
- Ok(count)
- }
-}
-
-impl<T: Write> Write for Tracking<T> {
- fn write(&mut self, buffer: &[u8]) -> std::io::Result<usize> {
- let count = self.inner.write(buffer)?;
- self.position += count;
- Ok(count)
- }
-
- fn flush(&mut self) -> std::io::Result<()> {
- self.inner.flush()
- }
-}
-
-impl<T> Tracking<T> {
-
- /// If `inner` is a reference, if must never be seeked directly,
- /// but only through this `Tracking` instance.
- pub fn new(inner: T) -> Self {
- Tracking { inner, position: 0 }
- }
-
- /// Current number of bytes written or read.
- pub fn byte_position(&self) -> usize {
- self.position
- }
-}
-
-impl<T: Read + Seek> Tracking<T> {
-
- /// Set the reader to the specified byte position.
- /// If it is only a couple of bytes, no seek system call is performed.
- pub fn seek_read_to(&mut self, target_position: usize) -> std::io::Result<()> {
- let delta = target_position as i128 - self.position as i128; // FIXME panicked at 'attempt to subtract with overflow'
- debug_assert!(delta.abs() < usize::MAX as i128);
-
- if delta > 0 && delta < 16 { // TODO profile that this is indeed faster than a syscall! (should be because of bufread buffer discard)
- skip_bytes(self, delta as usize)?;
- self.position += delta as usize;
- }
- else if delta != 0 {
- self.inner.seek(SeekFrom::Start(u64::try_from(target_position).unwrap()))?;
- self.position = target_position;
- }
-
- Ok(())
- }
-}
-
-impl<T: Write + Seek> Tracking<T> {
-
- /// Move the writing cursor to the specified target byte index.
- /// If seeking forward, this will write zeroes.
- pub fn seek_write_to(&mut self, target_position: usize) -> std::io::Result<()> {
- if target_position < self.position {
- self.inner.seek(SeekFrom::Start(u64::try_from(target_position).unwrap()))?;
- }
- else if target_position > self.position {
- std::io::copy(
- &mut std::io::repeat(0).take(u64::try_from(target_position - self.position).unwrap()),
- self
- )?;
- }
-
- self.position = target_position;
- Ok(())
- }
-}
-
-
-/// Generic trait that defines common binary operations such as reading and writing for this type.
-pub trait Data: Sized + Default + Clone {
-
- /// Number of bytes this would consume in an exr file.
- const BYTE_SIZE: usize = ::std::mem::size_of::<Self>();
-
- /// Read a value of type `Self`.
- fn read(read: &mut impl Read) -> Result<Self>;
-
- /// Read as many values of type `Self` as fit into the specified slice.
- /// If the slice cannot be filled completely, returns `Error::Invalid`.
- fn read_slice(read: &mut impl Read, slice: &mut[Self]) -> UnitResult;
-
- /// Read as many values of type `Self` as specified with `data_size`.
- ///
- /// This method will not allocate more memory than `soft_max` at once.
- /// If `hard_max` is specified, it will never read any more than that.
- /// Returns `Error::Invalid` if reader does not contain the desired number of elements.
- #[inline]
- fn read_vec(read: &mut impl Read, data_size: usize, soft_max: usize, hard_max: Option<usize>, purpose: &'static str) -> Result<Vec<Self>> {
- let mut vec = Vec::with_capacity(data_size.min(soft_max));
- Self::read_into_vec(read, &mut vec, data_size, soft_max, hard_max, purpose)?;
- Ok(vec)
- }
-
- /// Write this value to the writer.
- fn write(self, write: &mut impl Write) -> UnitResult;
-
- /// Write all values of that slice to the writer.
- fn write_slice(write: &mut impl Write, slice: &[Self]) -> UnitResult;
-
-
- /// Read as many values of type `Self` as specified with `data_size` into the provided vector.
- ///
- /// This method will not allocate more memory than `soft_max` at once.
- /// If `hard_max` is specified, it will never read any more than that.
- /// Returns `Error::Invalid` if reader does not contain the desired number of elements.
- #[inline]
- fn read_into_vec(read: &mut impl Read, data: &mut Vec<Self>, data_size: usize, soft_max: usize, hard_max: Option<usize>, purpose: &'static str) -> UnitResult {
- if let Some(max) = hard_max {
- if data_size > max {
- return Err(Error::invalid(purpose))
- }
- }
-
- let soft_max = hard_max.unwrap_or(soft_max).min(soft_max);
- let end = data.len() + data_size;
-
- // do not allocate more than $chunks memory at once
- // (most of the time, this loop will run only once)
- while data.len() < end {
- let chunk_start = data.len();
- let chunk_end = (chunk_start + soft_max).min(data_size);
-
- data.resize(chunk_end, Self::default());
- Self::read_slice(read, &mut data[chunk_start .. chunk_end])?; // safe because of `min(data_size)``
- }
-
- Ok(())
- }
-
- /// Write the length of the slice and then its contents.
- #[inline]
- fn write_i32_sized_slice<W: Write>(write: &mut W, slice: &[Self]) -> UnitResult {
- i32::try_from(slice.len())?.write(write)?;
- Self::write_slice(write, slice)
- }
-
- /// Read the desired element count and then read that many items into a vector.
- ///
- /// This method will not allocate more memory than `soft_max` at once.
- /// If `hard_max` is specified, it will never read any more than that.
- /// Returns `Error::Invalid` if reader does not contain the desired number of elements.
- #[inline]
- fn read_i32_sized_vec(read: &mut impl Read, soft_max: usize, hard_max: Option<usize>, purpose: &'static str) -> Result<Vec<Self>> {
- let size = usize::try_from(i32::read(read)?)?;
- Self::read_vec(read, size, soft_max, hard_max, purpose)
- }
-
- /// Fill the slice with this value.
- #[inline]
- fn fill_slice(self, slice: &mut [Self]) where Self: Copy {
- // hopefully compiles down to a single memset call
- for value in slice {
- *value = self;
- }
- }
-}
-
-
-macro_rules! implement_data_for_primitive {
- ($kind: ident) => {
- impl Data for $kind {
- #[inline]
- fn read(read: &mut impl Read) -> Result<Self> {
- Ok(read.read_from_little_endian()?)
- }
-
- #[inline]
- fn write(self, write: &mut impl Write) -> Result<()> {
- write.write_as_little_endian(&self)?;
- Ok(())
- }
-
- #[inline]
- fn read_slice(read: &mut impl Read, slice: &mut [Self]) -> Result<()> {
- read.read_from_little_endian_into(slice)?;
- Ok(())
- }
-
- #[inline]
- fn write_slice(write: &mut impl Write, slice: &[Self]) -> Result<()> {
- write.write_as_little_endian(slice)?;
- Ok(())
- }
- }
- };
-}
-
-implement_data_for_primitive!(u8);
-implement_data_for_primitive!(i8);
-implement_data_for_primitive!(i16);
-implement_data_for_primitive!(u16);
-implement_data_for_primitive!(u32);
-implement_data_for_primitive!(i32);
-implement_data_for_primitive!(i64);
-implement_data_for_primitive!(u64);
-implement_data_for_primitive!(f32);
-implement_data_for_primitive!(f64);
-
-
-impl Data for f16 {
- #[inline]
- fn read(read: &mut impl Read) -> Result<Self> {
- u16::read(read).map(f16::from_bits)
- }
-
- #[inline]
- fn read_slice(read: &mut impl Read, slice: &mut [Self]) -> Result<()> {
- let bits = slice.reinterpret_cast_mut();
- u16::read_slice(read, bits)
- }
-
- #[inline]
- fn write(self, write: &mut impl Write) -> Result<()> {
- self.to_bits().write(write)
- }
-
- #[inline]
- fn write_slice(write: &mut impl Write, slice: &[Self]) -> Result<()> {
- let bits = slice.reinterpret_cast();
- u16::write_slice(write, bits)
- }
-}
-
-
-#[cfg(test)]
-mod test {
- use crate::io::PeekRead;
- use std::io::Read;
-
- #[test]
- fn peek(){
- use lebe::prelude::*;
- let buffer: &[u8] = &[0,1,2,3];
- let mut peek = PeekRead::new(buffer);
-
- assert_eq!(peek.peek_u8().as_ref().unwrap(), &0);
- assert_eq!(peek.peek_u8().as_ref().unwrap(), &0);
- assert_eq!(peek.peek_u8().as_ref().unwrap(), &0);
- assert_eq!(u8::read_from_little_endian(&mut peek).unwrap(), 0_u8);
-
- assert_eq!(peek.read(&mut [0,0]).unwrap(), 2);
-
- assert_eq!(peek.peek_u8().as_ref().unwrap(), &3);
- assert_eq!(u8::read_from_little_endian(&mut peek).unwrap(), 3_u8);
-
- assert!(peek.peek_u8().is_err());
- assert!(peek.peek_u8().is_err());
- assert!(peek.peek_u8().is_err());
- assert!(peek.peek_u8().is_err());
-
- assert!(u8::read_from_little_endian(&mut peek).is_err());
- }
-}
-
-