Skip to main content

agave_fs/
buffered_reader.rs

1#![allow(clippy::arithmetic_side_effects)]
2
3//! File I/O buffered readers for AppendVec
4//! Specialized `BufRead`-like types for reading account data.
5//!
6//! Callers can use these types to iterate efficiently over append vecs. They can do so by repeatedly
7//! calling:
8//! * `fill_buf_required(account_meta_len)` to scan the account metadata parts and determine the account
9//!   data size,
10//!  * optionally extend the obtained buffer to full account data using
11//!    `fill_buf_required(account_all_bytes_len)`
12//!  * `consume(account_all_bytes_len)` to move to the next account
13//!
14//! When reading full accounts data whose sizes exceed the small stack buffer, the `BufReaderWithOverflow`
15//! should be used, which supports dynamically allocated buffer for preparing contiguous data slices.
16#[cfg(target_os = "linux")]
17pub use crate::io_uring::sequential_file_reader::{
18    SequentialFileReader, SequentialFileReaderBuilder,
19};
20use {
21    crate::{
22        FileSize,
23        file_io::{read_into_buffer, read_more_buffer},
24        io_setup::IoSetupState,
25    },
26    std::{
27        fs::File,
28        io::{self, BufRead},
29        mem::MaybeUninit,
30        ops::Range,
31        path::Path,
32        slice,
33    },
34};
35
36/// A stack-allocated buffer.
37///
38/// This is a fixed-size buffer that is allocated on the stack.
39///
40/// This should be used when the required size is known at compile time and is within reasonable stack
41/// limits.
42struct Stack<const N: usize>([MaybeUninit<u8>; N]);
43
44impl<const N: usize> Stack<N> {
45    #[inline(always)]
46    const fn new() -> Self {
47        Self([MaybeUninit::uninit(); N])
48    }
49}
50
51impl<const N: usize> Stack<N> {
52    fn capacity(&self) -> usize {
53        N
54    }
55
56    #[inline(always)]
57    unsafe fn as_slice(&self) -> &[u8] {
58        unsafe { slice::from_raw_parts(self.0.as_ptr() as *const u8, N) }
59    }
60
61    #[inline(always)]
62    unsafe fn as_mut_slice(&mut self) -> &mut [u8] {
63        unsafe { slice::from_raw_parts_mut(self.0.as_mut_ptr() as *mut u8, N) }
64    }
65}
66
67/// An extension of the `BufRead` trait for file readers that allow tracking file
68/// read position offset.
69pub trait FileBufRead<'a>: BufRead {
70    /// Activate the given `file` as source of reads of this reader.
71    ///
72    /// Resets the internal buffer to an empty state and sets the file offset to 0.
73    ///
74    /// `read_limit` provides a pre-defined limit on the number of bytes that can be read
75    /// from the file (unless EOF is reached).
76    ///
77    /// If the file was previously queued via `add_file_to_prefetch`, the reader
78    /// advances to that file (validating identity / `read_limit`) rather than
79    /// re-queueing it.
80    fn set_file(&mut self, file: &'a File, read_limit: FileSize) -> io::Result<()>;
81
82    /// Queue `file` for read-ahead (prefetch). Files are processed in FIFO order
83    /// by subsequent `set_file` calls.
84    ///
85    /// This is a hint to keep the read pipeline saturated for readers that
86    /// support concurrent read-ahead. Implementations without read-ahead may
87    /// ignore the call. Callers must still invoke `set_file` to switch the
88    /// active file.
89    fn add_file_to_prefetch(&mut self, file: &'a File, read_limit: FileSize) -> io::Result<()>;
90
91    /// Returns the current file offset corresponding to the start of the buffer
92    /// that will be returned by the next call to `fill_buf`.
93    ///
94    /// This offset represents the position within the underlying file where data
95    /// will be consumed from.
96    fn get_file_offset(&self) -> FileSize;
97
98    /// Advance the offset by `amt` bytes, potentially skipping past the current buffer
99    /// into the underlying file.
100    ///
101    /// Unlike `BufRead::consume`, `amt` is not constrained by the size of the buffer
102    /// returned by `fill_buf` — any bytes beyond what is currently buffered are skipped
103    /// by advancing the file read offset, so the next `fill_buf` starts at the correct
104    /// position.
105    fn consume_or_skip(&mut self, n: usize);
106}
107
108/// An extension of the `BufRead` trait for readers that require stronger control
109/// over returned buffer size.
110///
111/// Unlike the standard `BufRead`, which only guarantees a non-empty buffer,
112/// this trait allows callers to enforce a minimum number of contiguous bytes
113/// to be made available.
114pub trait RequiredLenBufRead: BufRead {
115    /// Ensures the internal buffer contains at least `required_len` contiguous bytes,
116    /// and returns a slice of that buffer.
117    ///
118    /// Note: subsequent calls with the same or larger `required_len` are allowed, but
119    /// before requesting smaller length all already provided bytes should be consumed
120    /// using a single `consume` call.
121    ///
122    /// Returns `Err(io::ErrorKind::UnexpectedEof)` if the end of file is reached
123    /// before the required number of bytes is available.
124    ///
125    /// Returns `Err(io::ErrorKind::QuotaExceeded)` if `required_len` exceeds supported limit.
126    fn fill_buf_required(&mut self, required_len: usize) -> io::Result<&[u8]>;
127}
128
129pub trait RequiredLenBufFileRead<'a>: RequiredLenBufRead + FileBufRead<'a> {}
130impl<'a, T: RequiredLenBufRead + FileBufRead<'a>> RequiredLenBufFileRead<'a> for T {}
131
132/// read a file a large buffer at a time and provide access to a slice in that buffer
133pub struct BufferedReader<'a, const N: usize> {
134    /// when we are next asked to read from file, start at this offset
135    file_offset_of_next_read: FileSize,
136    /// the most recently read data. `buf_valid_bytes` specifies the range of `buf` that is valid.
137    buf: Stack<N>,
138    /// specifies the range of `buf` that contains valid data that has not been used by the caller
139    buf_valid_bytes: Range<usize>,
140    /// offset in the file of the `buf_valid_bytes`.`start`
141    file_last_offset: FileSize,
142    /// how many bytes are valid in the file. The file's len may be longer.
143    file_len_valid: FileSize,
144    /// reference to file handle
145    file: Option<&'a File>,
146}
147
148impl<'a, const N: usize> BufferedReader<'a, N> {
149    pub const fn new() -> Self {
150        Self {
151            file_offset_of_next_read: 0,
152            buf: Stack::new(),
153            buf_valid_bytes: 0..0,
154            file_last_offset: 0,
155            file_len_valid: 0,
156            file: None,
157        }
158    }
159
160    pub fn with_file(mut self, file: &'a File, read_limit: FileSize) -> Self {
161        self.do_set_file(file, read_limit);
162        self
163    }
164
165    fn do_set_file(&mut self, file: &'a File, read_limit: FileSize) {
166        self.file = Some(file);
167        self.file_len_valid = read_limit;
168        self.file_last_offset = 0;
169        self.file_offset_of_next_read = 0;
170        self.buf_valid_bytes = 0..0;
171    }
172
173    /// Reset to idle state and re-type with a fresh lifetime `'b`.
174    pub fn rebind<'b>(self) -> io::Result<BufferedReader<'b, N>> {
175        Ok(BufferedReader {
176            file_offset_of_next_read: 0,
177            buf: self.buf,
178            buf_valid_bytes: 0..0,
179            file_last_offset: 0,
180            file_len_valid: 0,
181            file: None,
182        })
183    }
184}
185
186impl<'a, const N: usize> FileBufRead<'a> for BufferedReader<'a, N> {
187    fn set_file(&mut self, file: &'a File, read_limit: FileSize) -> io::Result<()> {
188        self.do_set_file(file, read_limit);
189        Ok(())
190    }
191
192    /// `BufferedReader` does not perform read-ahead — the call is a no-op and
193    /// the file becomes active only when `set_file` is later invoked.
194    fn add_file_to_prefetch(&mut self, _file: &'a File, _read_limit: FileSize) -> io::Result<()> {
195        Ok(())
196    }
197
198    #[inline(always)]
199    fn get_file_offset(&self) -> FileSize {
200        if self.buf_valid_bytes.is_empty() {
201            self.file_offset_of_next_read
202        } else {
203            self.file_last_offset + self.buf_valid_bytes.start as FileSize
204        }
205    }
206
207    fn consume_or_skip(&mut self, amt: usize) {
208        if self.buf_valid_bytes.len() >= amt {
209            self.buf_valid_bytes.start += amt;
210        } else {
211            let additional_amount_to_skip = amt - self.buf_valid_bytes.len();
212            self.buf_valid_bytes = 0..0;
213            self.file_offset_of_next_read += additional_amount_to_skip as FileSize;
214        }
215    }
216}
217
218impl<const N: usize> BufferedReader<'_, N> {
219    /// Defragment buffer and read more bytes to make sure we have filled available
220    /// space as much as possible.
221    fn read_more_bytes(&mut self) -> io::Result<()> {
222        // we haven't used all the bytes we read last time, so adjust the effective offset
223        debug_assert!(self.buf_valid_bytes.len() as FileSize <= self.file_offset_of_next_read);
224        self.file_last_offset =
225            self.file_offset_of_next_read - self.buf_valid_bytes.len() as FileSize;
226        let Some(file) = &self.file else {
227            return Err(io::Error::new(io::ErrorKind::BrokenPipe, "no open file"));
228        };
229        read_more_buffer(
230            file,
231            self.file_len_valid,
232            &mut self.file_offset_of_next_read,
233            // SAFETY: `read_more_buffer` will only _write_ to uninitialized memory and lifetime is tied to self.
234            unsafe { self.buf.as_mut_slice() },
235            &mut self.buf_valid_bytes,
236        )
237    }
238
239    fn valid_slice(&self) -> &[u8] {
240        // SAFETY: We only read from memory that has been initialized by `read_more_buffer`
241        // and lifetime is tied to self.
242        unsafe { &self.buf.as_slice()[self.buf_valid_bytes.clone()] }
243    }
244}
245
246impl<const N: usize> io::Read for BufferedReader<'_, N> {
247    fn read(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
248        let available_len = self.buf_valid_bytes.len();
249        if available_len > 0 {
250            // Copy already read data to buf.
251            let available_valid_data = self.valid_slice();
252            if available_len >= buf.len() {
253                buf.copy_from_slice(&available_valid_data[..buf.len()]);
254                self.consume(buf.len());
255                return Ok(buf.len());
256            }
257            // Only part of the buffer can be filled.
258            buf[..available_len].copy_from_slice(available_valid_data);
259            buf = &mut buf[available_len..];
260        }
261
262        // Read directly from file into space still left in the buf.
263        let Some(file) = &self.file else {
264            return Err(io::Error::new(io::ErrorKind::BrokenPipe, "no open file"));
265        };
266        let bytes_read = read_into_buffer(
267            file,
268            self.file_len_valid,
269            self.file_offset_of_next_read,
270            buf,
271        )?;
272        let filled_len = bytes_read + available_len;
273        // Buffer was successfully filled, drop buffered data and move offset.
274        self.consume_or_skip(filled_len);
275        Ok(filled_len)
276    }
277}
278
279/// `BufferedReader` implements a more permissive API compared to `BufRead`
280/// by allowing `consume` to advance beyond the end of the buffer returned by `fill_buf`.
281impl<const N: usize> BufRead for BufferedReader<'_, N> {
282    fn fill_buf(&mut self) -> io::Result<&[u8]> {
283        if self.buf_valid_bytes.is_empty() {
284            self.read_more_bytes()?;
285        }
286        Ok(self.valid_slice())
287    }
288
289    /// Advance the buffer position by `amt`, clamped to the end of the currently buffered data.
290    ///
291    /// This follows the standard `BufRead::consume` contract: `amt` must not exceed the buffer
292    /// length returned by the preceding `fill_buf`. To skip bytes beyond the current buffer,
293    /// use [`FileBufRead::consume_or_skip`] instead.
294    fn consume(&mut self, amt: usize) {
295        self.buf_valid_bytes.start = self
296            .buf_valid_bytes
297            .end
298            .min(self.buf_valid_bytes.start + amt)
299    }
300}
301
302/// Supported `required_len` is limited by backing buffer size without ability to grow.
303impl<const N: usize> RequiredLenBufRead for BufferedReader<'_, N> {
304    fn fill_buf_required(&mut self, required_len: usize) -> io::Result<&[u8]> {
305        if self.buf_valid_bytes.len() < required_len {
306            self.read_more_bytes()?;
307            if self.buf_valid_bytes.len() < required_len {
308                if required_len > self.buf.capacity() {
309                    return Err(io::Error::new(
310                        io::ErrorKind::QuotaExceeded,
311                        "requested more bytes than supported by buffer",
312                    ));
313                }
314                return Err(io::Error::new(
315                    io::ErrorKind::UnexpectedEof,
316                    "unable to read enough data",
317                ));
318            }
319        }
320        Ok(self.valid_slice())
321    }
322}
323
324/// A buffered reader that wraps `BufRead` instance and implements `RequiredLenBufRead`.
325///
326/// It uses auxiliary overflow buffer when `fill_buf` returns slice that doesn't satisfy
327/// the length requirement.
328pub struct BufReaderWithOverflow<R> {
329    reader: R,
330    overflow_buf: Vec<u8>,
331    overflow_min_capacity: usize,
332    overflow_max_capacity: usize,
333}
334
335impl<R: BufRead> BufReaderWithOverflow<R> {
336    pub fn new(reader: R, overflow_min_capacity: usize, overflow_max_capacity: usize) -> Self {
337        Self {
338            reader,
339            overflow_buf: Vec::new(),
340            overflow_min_capacity,
341            overflow_max_capacity,
342        }
343    }
344}
345
346impl<R: BufRead> io::Read for BufReaderWithOverflow<R> {
347    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
348        let available_len = self.overflow_buf.len();
349        if available_len == 0 {
350            self.reader.read(buf)
351        } else {
352            assert!(
353                buf.len() >= available_len,
354                "should read all previously required bytes"
355            );
356            buf[..available_len].copy_from_slice(&self.overflow_buf);
357            self.overflow_buf.clear();
358            if buf.len() > available_len {
359                let bytes_read = self.reader.read(&mut buf[available_len..])?;
360                Ok(available_len + bytes_read)
361            } else {
362                Ok(available_len)
363            }
364        }
365    }
366}
367
368impl<R: BufRead> BufRead for BufReaderWithOverflow<R> {
369    fn fill_buf(&mut self) -> io::Result<&[u8]> {
370        if self.overflow_buf.is_empty() {
371            self.reader.fill_buf()
372        } else {
373            Ok(self.overflow_buf.as_slice())
374        }
375    }
376
377    fn consume(&mut self, mut amt: usize) {
378        let overflow_len = self.overflow_buf.len();
379        if overflow_len > 0 {
380            amt = amt
381                .checked_sub(overflow_len)
382                .expect("should consume all previously required bytes");
383            self.overflow_buf.clear();
384        }
385        self.reader.consume(amt);
386    }
387}
388
389impl<'a, R: FileBufRead<'a>> FileBufRead<'a> for BufReaderWithOverflow<R> {
390    fn set_file(&mut self, file: &'a File, read_limit: FileSize) -> io::Result<()> {
391        self.overflow_buf.clear();
392        self.reader.set_file(file, read_limit)
393    }
394
395    fn add_file_to_prefetch(&mut self, file: &'a File, read_limit: FileSize) -> io::Result<()> {
396        self.reader.add_file_to_prefetch(file, read_limit)
397    }
398
399    fn get_file_offset(&self) -> FileSize {
400        self.reader.get_file_offset() - self.overflow_buf.len() as FileSize
401    }
402
403    fn consume_or_skip(&mut self, mut amt: usize) {
404        let overflow_len = self.overflow_buf.len();
405        if overflow_len > 0 {
406            amt = amt
407                .checked_sub(overflow_len)
408                .expect("should consume all previously required bytes");
409            self.overflow_buf.clear();
410        }
411        self.reader.consume_or_skip(amt);
412    }
413}
414
415/// Support large `required_len` (within configured limits) by using overflow buffer
416/// retained during lifetime of the reader.
417impl<R: BufRead> RequiredLenBufRead for BufReaderWithOverflow<R> {
418    fn fill_buf_required(&mut self, required_len: usize) -> io::Result<&[u8]> {
419        let available_len = self.overflow_buf.len();
420        if available_len == 0 {
421            let buf = self.reader.fill_buf()?;
422            if buf.len() >= required_len {
423                // Separate fill_buf call is needed due to borrow checker's limitation
424                // https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions
425                return self.reader.fill_buf();
426            }
427        }
428        assert!(
429            available_len <= required_len,
430            "fill_buf_required should keep or grow required_len until consume"
431        );
432        if required_len > self.overflow_buf.capacity() {
433            let target_capacity = required_len
434                .next_power_of_two()
435                .clamp(self.overflow_min_capacity, self.overflow_max_capacity);
436            if required_len > target_capacity {
437                return Err(io::Error::new(
438                    io::ErrorKind::QuotaExceeded,
439                    "requested more bytes than allowed capacity range",
440                ));
441            }
442            self.overflow_buf
443                .reserve_exact(target_capacity - available_len);
444        }
445        // Safety: we have reserved capacity and all of it will be filled by read
446        unsafe { self.overflow_buf.set_len(required_len) };
447
448        // On error overflow buffer is completely cleared to avoid access to
449        // uninitialized memory.
450        self.reader
451            .read_exact(&mut self.overflow_buf[available_len..])
452            .inspect_err(|_| self.overflow_buf.clear())?;
453        Ok(self.overflow_buf.as_slice())
454    }
455}
456
457/// Open file at `path` with buffering reader using `buf_size` memory and doing
458/// read-ahead IO reads (if `io_uring` is supported by the platform)
459pub fn large_file_buf_reader(
460    path: &Path,
461    buf_size: usize,
462    io_setup: &IoSetupState,
463) -> io::Result<impl BufRead + use<>> {
464    #[cfg(target_os = "linux")]
465    {
466        assert!(agave_io_uring::io_uring_supported());
467
468        let mut reader = SequentialFileReaderBuilder::new()
469            .shared_sqpoll(io_setup.shared_sqpoll_fd())
470            .use_direct_io(io_setup.use_direct_io)
471            .use_registered_buffers(io_setup.use_registered_io_uring_buffers)
472            .build(buf_size)?;
473        reader.set_path(path)?;
474        Ok(reader)
475    }
476    #[cfg(not(target_os = "linux"))]
477    {
478        use std::io::BufReader;
479        let file = File::open(path)?;
480        let _ = io_setup;
481        Ok(BufReader::with_capacity(buf_size, file))
482    }
483}
484
485#[cfg(test)]
486mod tests {
487    use {
488        super::*,
489        std::io::{Read as _, Write},
490        tempfile::tempfile,
491    };
492
493    #[inline(always)]
494    fn rand_bytes<const N: usize>() -> [u8; N] {
495        use rand::Rng;
496        let mut rng = rand::rng();
497        std::array::from_fn(|_| rng.random::<u8>())
498    }
499
500    #[test]
501    fn test_buffered_reader() {
502        // Setup a sample file with 32 bytes of data read using 16 bytes buffer
503        const BUFFER_SIZE: usize = 16;
504        const FILE_SIZE: usize = 32;
505        let mut sample_file = tempfile().unwrap();
506        let bytes = rand_bytes::<FILE_SIZE>();
507        sample_file.write_all(&bytes).unwrap();
508
509        // First read 16 bytes to fill buffer
510        let file_len_valid = 32;
511        let default_min_read = 8;
512        let mut reader =
513            BufferedReader::<BUFFER_SIZE>::new().with_file(&sample_file, file_len_valid);
514        let offset = reader.get_file_offset();
515        let slice = reader.fill_buf_required(default_min_read).unwrap();
516        let mut expected_offset = 0;
517        assert_eq!(offset, expected_offset);
518        assert_eq!(slice.len(), BUFFER_SIZE);
519        assert_eq!(slice, &bytes[0..BUFFER_SIZE]);
520
521        // Consume the data and attempt to read next 32 bytes, which is above supported buffer size,
522        // so file offset is moved, but call returns quota error.
523        let advance = 16;
524        let mut required_len = 32;
525        reader.consume(advance);
526        let offset = reader.get_file_offset();
527        expected_offset += advance as FileSize;
528        assert_eq!(offset, expected_offset);
529        assert_eq!(
530            reader
531                .fill_buf_required(required_len)
532                .expect_err("should fail due to required length above buffer size")
533                .kind(),
534            io::ErrorKind::QuotaExceeded
535        );
536
537        // Continue reading should yield EOF.
538        reader.consume(advance);
539        let offset = reader.get_file_offset();
540        expected_offset += advance as FileSize;
541        assert_eq!(offset, expected_offset);
542        required_len = 16;
543        assert_eq!(
544            reader
545                .fill_buf_required(required_len)
546                .expect_err("should hit EOF")
547                .kind(),
548            io::ErrorKind::UnexpectedEof
549        );
550
551        // set_required_data to zero and offset should not change, and slice should be empty.
552        required_len = 0;
553        let offset = reader.get_file_offset();
554        let slice = reader.fill_buf_required(required_len).unwrap();
555        let expected_offset = file_len_valid;
556        assert_eq!(offset, expected_offset);
557        let expected_slice_len = 0;
558        assert_eq!(slice.len(), expected_slice_len);
559    }
560
561    #[test]
562    fn test_buffered_reader_with_extra_data_in_file() {
563        // Setup a sample file with 32 bytes of data read using 16 bytes buffer
564        const BUFFER_SIZE: usize = 16;
565        const FILE_SIZE: usize = 32;
566        let mut sample_file = tempfile().unwrap();
567        let bytes = rand_bytes::<FILE_SIZE>();
568        sample_file.write_all(&bytes).unwrap();
569
570        // Set file valid_len to 30 (i.e. 2 garbage bytes at the end of the file)
571        let valid_len = 30;
572
573        // First read 16 bytes to fill buffer
574        let default_min_read_size = 8;
575        let mut reader = BufferedReader::<BUFFER_SIZE>::new().with_file(&sample_file, valid_len);
576        let offset = reader.get_file_offset();
577        let slice = reader.fill_buf_required(default_min_read_size).unwrap();
578        let mut expected_offset = 0;
579        assert_eq!(offset, expected_offset);
580        assert_eq!(slice.len(), BUFFER_SIZE);
581        assert_eq!(slice, &bytes[0..BUFFER_SIZE]);
582
583        // Consume the data and attempt read next 16 bytes, expect to hit `valid_len`, and only read 14 bytes
584        let mut advance = 16;
585        let mut required_data_len = 16;
586        reader.consume_or_skip(advance);
587        let offset = reader.get_file_offset();
588        expected_offset += advance as FileSize;
589        assert_eq!(offset, expected_offset);
590        assert_eq!(
591            reader
592                .fill_buf_required(required_data_len)
593                .expect_err("should hit EOF")
594                .kind(),
595            io::ErrorKind::UnexpectedEof
596        );
597
598        // Continue reading should yield EOF.
599        advance = 14;
600        required_data_len = 16;
601        reader.consume_or_skip(advance);
602        let offset = reader.get_file_offset();
603        expected_offset += advance as FileSize;
604        assert_eq!(offset, expected_offset);
605        assert_eq!(
606            reader
607                .fill_buf_required(required_data_len)
608                .expect_err("should hit EOF")
609                .kind(),
610            io::ErrorKind::UnexpectedEof
611        );
612
613        // Move the offset passed `valid_len`, expect to hit EOF.
614        advance = 1;
615        required_data_len = 8;
616        reader.consume_or_skip(advance);
617        let offset = reader.get_file_offset();
618        expected_offset += advance as FileSize;
619        assert_eq!(offset, expected_offset);
620        assert_eq!(
621            reader
622                .fill_buf_required(required_data_len)
623                .expect_err("should hit EOF")
624                .kind(),
625            io::ErrorKind::UnexpectedEof
626        );
627
628        // Move the offset passed file_len, expect to hit EOF.
629        advance = 3;
630        required_data_len = 8;
631        reader.consume_or_skip(advance);
632        let offset = reader.get_file_offset();
633        expected_offset += advance as FileSize;
634        assert_eq!(offset, expected_offset);
635        assert_eq!(
636            reader
637                .fill_buf_required(required_data_len)
638                .expect_err("Should hit EOF")
639                .kind(),
640            io::ErrorKind::UnexpectedEof
641        );
642    }
643
644    #[test]
645    fn test_buffered_reader_partial_consume() {
646        // Setup a sample file with 32 bytes of data read using 16 bytes buffer
647        const BUFFER_SIZE: usize = 16;
648        const FILE_SIZE: usize = 32;
649        let mut sample_file = tempfile().unwrap();
650        let bytes = rand_bytes::<FILE_SIZE>();
651        sample_file.write_all(&bytes).unwrap();
652
653        // First read 16 bytes to fill buffer
654        let file_len_valid = 32;
655        let default_min_read_size = 8;
656        let mut reader =
657            BufferedReader::<BUFFER_SIZE>::new().with_file(&sample_file, file_len_valid);
658        let offset = reader.get_file_offset();
659        let slice = reader.fill_buf_required(default_min_read_size).unwrap();
660        let mut expected_offset = 0;
661        assert_eq!(offset, expected_offset);
662        assert_eq!(slice.len(), BUFFER_SIZE);
663        assert_eq!(slice, &bytes[0..BUFFER_SIZE]);
664
665        // Consume the partial data (8 byte) and attempt to read next 8 bytes
666        let mut advance = 8;
667        let mut required_len = 8;
668        reader.consume(advance);
669        let offset = reader.get_file_offset();
670        let slice = reader.fill_buf_required(required_len).unwrap();
671        expected_offset += advance as FileSize;
672        assert_eq!(offset, expected_offset);
673        assert_eq!(slice.len(), required_len);
674        assert_eq!(
675            slice,
676            &bytes[expected_offset as usize..expected_offset as usize + required_len]
677        ); // no need to read more
678
679        // Continue reading should succeed and read the rest 16 bytes.
680        advance = 8;
681        required_len = 16;
682        reader.consume(advance);
683        let offset = reader.get_file_offset();
684        let slice = reader.fill_buf_required(required_len).unwrap();
685        expected_offset += advance as FileSize;
686        assert_eq!(offset, expected_offset);
687        assert_eq!(slice.len(), required_len);
688        assert_eq!(
689            slice,
690            &bytes[expected_offset as usize..expected_offset as usize + required_len]
691        );
692
693        // Continue reading should yield EOF and empty slice.
694        advance = 16;
695        required_len = 16;
696        reader.consume(advance);
697        let offset = reader.get_file_offset();
698        expected_offset += advance as FileSize;
699        assert_eq!(offset, expected_offset);
700        assert_eq!(
701            reader
702                .fill_buf_required(required_len)
703                .expect_err("should hit EOF")
704                .kind(),
705            io::ErrorKind::UnexpectedEof
706        );
707
708        // Attempt to read more than the buffer size
709        required_len = 32;
710        assert_eq!(
711            reader
712                .fill_buf_required(required_len)
713                .expect_err("should fail due to too large required length")
714                .kind(),
715            io::ErrorKind::QuotaExceeded
716        );
717    }
718
719    #[test]
720    fn test_buffered_reader_partial_consume_with_move() {
721        // Setup a sample file with 32 bytes of data read using 16 bytes buffer
722        const BUFFER_SIZE: usize = 16;
723        const FILE_SIZE: usize = 32;
724        let mut sample_file = tempfile().unwrap();
725        let bytes = rand_bytes::<FILE_SIZE>();
726        sample_file.write_all(&bytes).unwrap();
727
728        // First read 16 bytes to fill buffer
729        let valid_len = 32;
730        let default_min_read = 8;
731        let mut reader = BufferedReader::<BUFFER_SIZE>::new().with_file(&sample_file, valid_len);
732        let offset = reader.get_file_offset();
733        let slice = reader.fill_buf_required(default_min_read).unwrap();
734        let mut expected_offset = 0;
735        assert_eq!(offset, expected_offset);
736        assert_eq!(slice.len(), BUFFER_SIZE);
737        assert_eq!(slice, &bytes[0..BUFFER_SIZE]);
738
739        // Consume the partial data (8 bytes) and attempt to read next 16 bytes
740        // This will move the leftover 8bytes and read next 8 bytes.
741        let mut advance = 8;
742        let mut required_data_len = 16;
743        reader.consume(advance);
744        let offset = reader.get_file_offset();
745        let slice = reader.fill_buf_required(required_data_len).unwrap();
746        expected_offset += advance as FileSize;
747        assert_eq!(offset, expected_offset);
748        assert_eq!(slice.len(), required_data_len);
749        assert_eq!(
750            slice,
751            &bytes[expected_offset as usize..expected_offset as usize + required_data_len]
752        );
753
754        // Continue reading should succeed and read the rest 8 bytes.
755        advance = 16;
756        required_data_len = 8;
757        reader.consume(advance);
758        let offset = reader.get_file_offset();
759        let slice = reader.fill_buf_required(required_data_len).unwrap();
760        expected_offset += advance as FileSize;
761        assert_eq!(offset, expected_offset);
762        assert_eq!(slice.len(), required_data_len);
763        assert_eq!(
764            slice,
765            &bytes[expected_offset as usize..expected_offset as usize + required_data_len]
766        );
767    }
768
769    #[test]
770    fn test_fill_buf_required_or_overflow() {
771        // Setup a sample file with 32 bytes of data read using 16 bytes buffer
772        const BUFFER_SIZE: usize = 16;
773        const FILE_SIZE: usize = 32;
774        let mut sample_file = tempfile().unwrap();
775        let bytes = rand_bytes::<FILE_SIZE>();
776        sample_file.write_all(&bytes).unwrap();
777
778        let mut reader = BufReaderWithOverflow::new(
779            BufferedReader::<BUFFER_SIZE>::new().with_file(&sample_file, FILE_SIZE as FileSize),
780            0,
781            usize::MAX,
782        );
783
784        // Case 1: required_len <= BUFFER_SIZE (no overflow needed)
785        let required_len = 8;
786        let slice = reader.fill_buf_required(required_len).unwrap();
787        assert_eq!(&slice[..required_len], &bytes[..required_len]);
788
789        // Consume part of the buffer to simulate partial reading
790        reader.consume_or_skip(required_len);
791
792        // Case 2: required_len > buffer_size (overflow required)
793        let required_len = BUFFER_SIZE + 8;
794        let slice = reader.fill_buf_required(required_len).unwrap();
795
796        // Internal buffer is size `buffer_size`, overflow should extend with the remaining `8` bytes
797        assert_eq!(slice.len(), required_len);
798        assert_eq!(slice, &bytes[8..8 + required_len]);
799
800        // Consume everything to reach EOF
801        reader.consume_or_skip(required_len);
802
803        // Case 3: required_len larger than remaining data (expect UnexpectedEof)
804        let required_len = 64;
805        let result = reader.fill_buf_required(required_len);
806        assert_eq!(result.unwrap_err().kind(), io::ErrorKind::UnexpectedEof);
807
808        // Case 4: required_len = 0 (should return empty slice)
809        let required_len = 0;
810        let offset_before = reader.get_file_offset();
811        let slice = reader.fill_buf_required(required_len).unwrap();
812        assert_eq!(slice.len(), 0);
813        let offset_after = reader.get_file_offset();
814        assert_eq!(offset_before, offset_after);
815    }
816
817    #[test]
818    fn test_overflow_reader_read_and_fill_buf() {
819        const BUFFER_SIZE: usize = 16;
820        const FILE_SIZE: usize = 64;
821        let mut sample_file = tempfile().unwrap();
822        let bytes = rand_bytes::<FILE_SIZE>();
823        sample_file.write_all(&bytes).unwrap();
824
825        let mut reader = BufReaderWithOverflow::new(
826            BufferedReader::<BUFFER_SIZE>::new().with_file(&sample_file, FILE_SIZE as FileSize),
827            0,
828            32,
829        );
830        let buf = reader.fill_buf().unwrap();
831        assert_eq!(buf, &bytes[0..BUFFER_SIZE]);
832
833        reader.consume_or_skip(8);
834        let mut buf = [0; 8];
835        assert_eq!(reader.read(&mut buf).unwrap(), 8);
836        assert_eq!(buf, &bytes[8..BUFFER_SIZE]);
837
838        assert_eq!(
839            reader
840                .fill_buf_required(40)
841                .expect_err("should exceed len limit")
842                .kind(),
843            io::ErrorKind::QuotaExceeded
844        );
845
846        // Required buffer is at maximum configured limit.
847        let buf = reader.fill_buf_required(32).unwrap();
848        assert_eq!(buf, &bytes[BUFFER_SIZE..BUFFER_SIZE + 32]);
849        // Same buffer should be returned.
850        let buf = reader.fill_buf().unwrap();
851        assert_eq!(buf, &bytes[BUFFER_SIZE..BUFFER_SIZE + 32]);
852
853        let mut buf = [0; 48];
854        assert_eq!(reader.read(&mut buf).unwrap(), 48);
855        assert_eq!(buf, &bytes[BUFFER_SIZE..BUFFER_SIZE + 48]);
856
857        assert_eq!(reader.read(&mut buf).unwrap(), 0);
858
859        assert_eq!(
860            reader
861                .fill_buf_required(1)
862                .expect_err("should reach EOF")
863                .kind(),
864            io::ErrorKind::UnexpectedEof
865        );
866    }
867}