Skip to main content

zune_core/bytestream/
traits.rs

1/*
2 * Copyright (c) 2023.
3 *
4 * This software is free software;
5 *
6 * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license
7 */
8//! Traits for reading and writing images in zune
9//!
10//!
11//! This exposes the traits and implementations for readers
12//! and writers in the zune family of decoders and encoders.
13
14use crate::bytestream::reader::{ZByteIoError, ZSeekFrom};
15
16/// The de-facto Input trait implemented for readers.
17///
18/// This provides the basic functions needed to quick and sometimes
19/// heap free I/O for the zune image decoders with easy support for extending it
20/// to multiple implementations.
21///
22/// # Considerations
23///
24/// If you have an in memory buffer, prefer [`ZCursor`](crate::bytestream::ZCursor) over [`Cursor`](std::io::Cursor).
25/// We implement this trait for two types, `ZCursor`, and any thing that implements `BufRead`+`Seek`, `Cursor` falls in the latter
26/// and since Rust doesn't have specialization for traits, we can only implement it once. This means functions like
27/// [`read_byte_no_error`](crate::bytestream::ZByteReaderTrait::read_byte_no_error) are slower than they should be for `Cursor`.
28///
29pub trait ZByteReaderTrait {
30    /// Read a single byte from the decoder and return
31    /// `0` if we can't read the byte, e.g because of EOF
32    ///
33    /// The implementation should try to be as fast as possible as this is called
34    /// from some hot loops where it may become the bottleneck
35    fn read_byte_no_error(&mut self) -> u8;
36    /// Read exact bytes required to fill `buf` or return an error if that isn't possible
37    ///
38    /// ## Arguments
39    ///  - `buf`: Buffer to fill with bytes from the underlying reader
40    ///  ## Errors
41    /// In case of an error, the implementation should not increment the internal position
42    fn read_exact_bytes(&mut self, buf: &mut [u8]) -> Result<(), ZByteIoError>;
43
44    /// Read bytes into `buf` returning how many bytes you have read or an error if one occurred
45    ///
46    /// This doesn't guarantee that buf will be filled with bytes for such a guarantee see
47    /// [`read_exact_bytes`](Self::read_exact_bytes)
48    ///
49    /// ## Arguments
50    /// - `buf`: The buffer to fill with bytes
51    ///
52    /// ## Returns
53    ///  - `Ok(usize)` - Actual bytes read into the buffer
54    ///  - `Err()` - The error encountered when reading bytes for which we couldn't recover
55    fn read_bytes(&mut self, buf: &mut [u8]) -> Result<usize, ZByteIoError>;
56    /// Reads data into provided buffer but does not advance read position.
57    ///
58    ///
59    fn peek_bytes(&mut self, buf: &mut [u8]) -> Result<usize, ZByteIoError>;
60    fn peek_exact_bytes(&mut self, buf: &mut [u8]) -> Result<(), ZByteIoError>;
61    /// Seek into a new position from the buffer
62    ///
63    /// This is similar to the [seek](std::io::Seek::seek) function in the [Seek](std::io::Seek) trait
64    /// but implemented to work for no-std environments
65    fn z_seek(&mut self, from: ZSeekFrom) -> Result<u64, ZByteIoError>;
66    /// Report whether we are at the end of a stream.
67    ///
68    /// ## Warning
69    /// This may cause an additional syscall e.g when we are reading from a file, we must query the file
70    /// multiple times to check if we really are at the end of the file and the user didn't sneakily
71    /// add more contents to it hence use it with care
72    ///
73    /// ## Returns
74    /// - `Ok(bool)` - The answer to whether or not we are at end of file
75    /// - `Err()` - The error that occurred when we queried the underlying reader if we were at EOF
76    fn is_eof(&mut self) -> Result<bool, ZByteIoError>;
77
78    /// Return the current position of the inner cursor.
79    ///
80    /// This can be used to check the advancement of the cursor
81    fn z_position(&mut self) -> Result<u64, ZByteIoError>;
82    /// Read all bytes remaining in this input to `sink` until we hit eof
83    ///
84    /// # Returns
85    /// - `Ok(usize)` The actual number of bytes added to the sink
86    /// - `Err()` An error that occurred when reading bytes
87    fn read_remaining(&mut self, sink: &mut alloc::vec::Vec<u8>) -> Result<usize, ZByteIoError>;
88}
89
90/// The writer trait implemented for zune-image library of encoders
91///
92/// Anything that implements this trait can be used as a sink
93/// for writing encoded images
94pub trait ZByteWriterTrait {
95    /// Write some bytes into the sink returning number of bytes written or
96    /// an error if something bad happened
97    ///
98    /// An implementation is free to write less bytes that are in buf, so the bytes written
99    /// cannot be guaranteed to be fully written
100    fn write_bytes(&mut self, buf: &[u8]) -> Result<usize, ZByteIoError>;
101    /// Write all bytes to the buffer or return an error if something occurred
102    ///
103    /// This will always write all bytes, if it can't fully write all bytes, it will
104    /// error out
105    fn write_all_bytes(&mut self, buf: &[u8]) -> Result<(), ZByteIoError>;
106    /// Write a fixed number of bytes and error out if we can't write the bytes
107    ///
108    /// This is provided to allow for optimized writes where possible. (when the compiler can const fold them)
109    fn write_const_bytes<const N: usize>(&mut self, buf: &[u8; N]) -> Result<(), ZByteIoError>;
110    /// Ensure bytes are written to the sink.
111    ///
112    /// Implementations should treat this like linux `fsync`, and should implement
113    /// whatever writer's implementation of fsync should look like
114    ///
115    /// After this, the encoder should be able to guarantee that all in-core data is synced with the
116    /// storage decive
117    fn flush_bytes(&mut self) -> Result<(), ZByteIoError>;
118
119    /// A hint to tell the implementation how big of a size we expect the image to be
120    /// An implementation like in memory `Vec` can use this to reserve additional memory to
121    /// prevent reallocation when encoding
122    ///
123    /// This is just a hint, akin to calling `Vec::reserve` and should be treated as such.
124    /// If your implementation doesn't support such, e.g file or mutable slices, it's okay to return
125    /// `Ok(())`
126    fn reserve_capacity(&mut self, size: usize) -> Result<(), ZByteIoError>;
127}