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}