Skip to main content

qubit_io/ext/
seek_ext.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8use std::io::{
9    Result,
10    Seek,
11    SeekFrom,
12};
13
14/// Extension methods for [`Seek`] values.
15///
16/// `SeekExt` provides stable, position-preserving helpers for seekable streams.
17/// The methods are implemented for every type that implements [`Seek`],
18/// including `dyn Seek` trait objects.
19pub trait SeekExt: Seek {
20    /// Gets the stream size without changing the final stream position.
21    ///
22    /// The original position is captured with [`Seek::stream_position`], then
23    /// the stream is moved to the end to measure its size, and finally the
24    /// original position is restored.
25    ///
26    /// # Compatibility
27    /// If the standard library adds an equivalent `Seek::stream_size` method,
28    /// this extension method may be deprecated in a future release.
29    ///
30    /// # Returns
31    /// The stream size in bytes.
32    ///
33    /// # Errors
34    /// Returns an error when reading the current position, seeking to the end,
35    /// or restoring the original position fails. If restoring fails, the
36    /// restore error is returned because the caller's stream position contract
37    /// was not preserved.
38    fn stream_size(&mut self) -> Result<u64>;
39}
40
41impl<T> SeekExt for T
42where
43    T: Seek + ?Sized,
44{
45    #[inline]
46    fn stream_size(&mut self) -> Result<u64> {
47        let mut stream = self;
48        stream_size_impl(&mut stream)
49    }
50}
51
52/// Gets the size of `stream` and restores its original position.
53///
54/// # Parameters
55/// - `stream`: Seekable stream to inspect.
56///
57/// # Returns
58/// Stream size in bytes.
59///
60/// # Errors
61/// Returns an error when position lookup, end seeking, or restoration fails.
62fn stream_size_impl(stream: &mut dyn Seek) -> Result<u64> {
63    let position = stream.stream_position()?;
64    let size_result = stream.seek(SeekFrom::End(0));
65    let restore_result = stream.seek(SeekFrom::Start(position));
66    match (size_result, restore_result) {
67        (Ok(size), Ok(_)) => Ok(size),
68        (Err(error), Ok(_)) => Err(error),
69        (_, Err(error)) => Err(error),
70    }
71}