Skip to main content

qubit_io/ext/
seek_ext.rs

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