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 exact bytes required to fill `buf` or return an error if that isn't possible
45 ///
46 /// This is the same as [`read_exact_bytes`](Self::read_exact_bytes) but implemented as a separate
47 /// method to allow some implementations to optimize it to cost fewer instructions
48 ///
49 /// ## Arguments
50 /// - `buf`: Buffer to fill with bytes from the underlying reader
51 /// ## Errors
52 /// In case of an error, the implementation should not increment the internal position
53 fn read_const_bytes<const N: usize>(&mut self, buf: &mut [u8; N]) -> Result<(), ZByteIoError>;
54
55 /// Read exact bytes required to fill `buf` or ignore buf entirely if you can't fill it
56 /// due to an error like the inability to fill the buffer completely
57 /// ## Arguments
58 /// - `buf`: Buffer to fill with bytes from the underlying reader
59 /// ## Errors
60 /// In case of an error, the implementation should not increment the internal position
61 fn read_const_bytes_no_error<const N: usize>(&mut self, buf: &mut [u8; N]);
62
63 /// Read bytes into `buf` returning how many bytes you have read or an error if one occurred
64 ///
65 /// This doesn't guarantee that buf will be filled with bytes for such a guarantee see
66 /// [`read_exact_bytes`](Self::read_exact_bytes)
67 ///
68 /// ## Arguments
69 /// - `buf`: The buffer to fill with bytes
70 ///
71 /// ## Returns
72 /// - `Ok(usize)` - Actual bytes read into the buffer
73 /// - `Err()` - The error encountered when reading bytes for which we couldn't recover
74 fn read_bytes(&mut self, buf: &mut [u8]) -> Result<usize, ZByteIoError>;
75 /// Reads data into provided buffer but does not advance read position.
76 ///
77 ///
78 fn peek_bytes(&mut self, buf: &mut [u8]) -> Result<usize, ZByteIoError>;
79 fn peek_exact_bytes(&mut self, buf: &mut [u8]) -> Result<(), ZByteIoError>;
80 /// Seek into a new position from the buffer
81 ///
82 /// This is similar to the [seek](std::io::Seek::seek) function in the [Seek](std::io::Seek) trait
83 /// but implemented to work for no-std environments
84 fn z_seek(&mut self, from: ZSeekFrom) -> Result<u64, ZByteIoError>;
85 /// Report whether we are at the end of a stream.
86 ///
87 /// ## Warning
88 /// This may cause an additional syscall e.g when we are reading from a file, we must query the file
89 /// multiple times to check if we really are at the end of the file and the user didn't sneakily
90 /// add more contents to it hence use it with care
91 ///
92 /// ## Returns
93 /// - `Ok(bool)` - The answer to whether or not we are at end of file
94 /// - `Err()` - The error that occurred when we queried the underlying reader if we were at EOF
95 fn is_eof(&mut self) -> Result<bool, ZByteIoError>;
96
97 /// Return the current position of the inner cursor.
98 ///
99 /// This can be used to check the advancement of the cursor
100 fn z_position(&mut self) -> Result<u64, ZByteIoError>;
101 /// Read all bytes remaining in this input to `sink` until we hit eof
102 ///
103 /// # Returns
104 /// - `Ok(usize)` The actual number of bytes added to the sink
105 /// - `Err()` An error that occurred when reading bytes
106 fn read_remaining(&mut self, sink: &mut alloc::vec::Vec<u8>) -> Result<usize, ZByteIoError>;
107}
108
109/// The writer trait implemented for zune-image library of encoders
110///
111/// Anything that implements this trait can be used as a sink
112/// for writing encoded images
113pub trait ZByteWriterTrait {
114 /// Write some bytes into the sink returning number of bytes written or
115 /// an error if something bad happened
116 ///
117 /// An implementation is free to write less bytes that are in buf, so the bytes written
118 /// cannot be guaranteed to be fully written
119 fn write_bytes(&mut self, buf: &[u8]) -> Result<usize, ZByteIoError>;
120 /// Write all bytes to the buffer or return an error if something occurred
121 ///
122 /// This will always write all bytes, if it can't fully write all bytes, it will
123 /// error out
124 fn write_all_bytes(&mut self, buf: &[u8]) -> Result<(), ZByteIoError>;
125 /// Write a fixed number of bytes and error out if we can't write the bytes
126 ///
127 /// This is provided to allow for optimized writes where possible. (when the compiler can const fold them)
128 fn write_const_bytes<const N: usize>(&mut self, buf: &[u8; N]) -> Result<(), ZByteIoError>;
129 /// Ensure bytes are written to the sink.
130 ///
131 /// Implementations should treat this like linux `fsync`, and should implement
132 /// whatever writer's implementation of fsync should look like
133 ///
134 /// After this, the encoder should be able to guarantee that all in-core data is synced with the
135 /// storage decive
136 fn flush_bytes(&mut self) -> Result<(), ZByteIoError>;
137
138 /// A hint to tell the implementation how big of a size we expect the image to be
139 /// An implementation like in memory `Vec` can use this to reserve additional memory to
140 /// prevent reallocation when encoding
141 ///
142 /// This is just a hint, akin to calling `Vec::reserve` and should be treated as such.
143 /// If your implementation doesn't support such, e.g file or mutable slices, it's okay to return
144 /// `Ok(())`
145 fn reserve_capacity(&mut self, size: usize) -> Result<(), ZByteIoError>;
146}