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