Skip to main content

qubit_io/std_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// =============================================================================
8
9//! Extension operations for inspecting standard seekable streams.
10
11use std::io::{
12    Result,
13    Seek,
14    SeekFrom,
15};
16
17/// Extension methods for [`Seek`] values.
18///
19/// `SeekExt` provides stable, position-preserving helpers for seekable streams.
20/// The methods are implemented for every type that implements [`Seek`],
21/// including `dyn Seek` trait objects.
22pub trait SeekExt: Seek {
23    /// Gets the stream size without changing the final stream position.
24    ///
25    /// The original position is captured with [`Seek::stream_position`], then
26    /// the stream is moved to the end to measure its size, and finally the
27    /// original position is restored.
28    ///
29    /// # Compatibility
30    /// If the standard library adds an equivalent `Seek::stream_size` method,
31    /// this extension method may be deprecated in a future release.
32    ///
33    /// # Returns
34    /// The stream size in bytes.
35    ///
36    /// # Errors
37    /// Returns an error when reading the current position, seeking to the end,
38    /// or restoring the original position fails. If restoring fails, the
39    /// restore error is returned because the caller's stream position contract
40    /// was not preserved.
41    fn stream_size(&mut self) -> Result<u64>;
42}
43
44/// Implements stream-size inspection through a type-erased stream.
45///
46/// # Parameters
47/// - `stream`: Stream to measure and restore.
48///
49/// # Returns
50/// The stream size in bytes.
51///
52/// # Errors
53/// Returns an error when querying, changing, or restoring the stream position
54/// fails.
55fn stream_size_impl(stream: &mut dyn Seek) -> Result<u64> {
56    let position = stream.stream_position()?;
57    let size_result = stream.seek(SeekFrom::End(0));
58    let restore_result = stream.seek(SeekFrom::Start(position));
59    match (size_result, restore_result) {
60        (Ok(size), Ok(_)) => Ok(size),
61        (Err(error), Ok(_)) => Err(error),
62        (_, Err(error)) => Err(error),
63    }
64}
65
66impl<T> SeekExt for T
67where
68    T: Seek + ?Sized,
69{
70    /// Gets the stream size without changing its final position.
71    ///
72    /// # Returns
73    /// The stream size in bytes.
74    ///
75    /// # Errors
76    /// Returns an error when querying, changing, or restoring the stream
77    /// position fails.
78    #[inline(always)]
79    fn stream_size(&mut self) -> Result<u64> {
80        let mut stream = self;
81        stream_size_impl(&mut stream)
82    }
83}