Skip to main content

qubit_io/ext/
write_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    Write,
13};
14
15/// Extension methods for values that implement both [`Write`] and [`Seek`].
16///
17/// `WriteSeekExt` provides position-preserving write helpers for random-access
18/// output use cases such as patching headers, offsets, and indexes after a
19/// stream has already been written.
20pub trait WriteSeekExt: Write + Seek {
21    /// Writes all bytes at `offset` and restores the original position.
22    ///
23    /// This method seeks to `offset`, delegates to [`Write::write_all`], and
24    /// then restores the position that was current before the call.
25    ///
26    /// # Parameters
27    /// - `offset`: Absolute byte offset from the start of the stream.
28    /// - `buffer`: Bytes to write.
29    ///
30    /// # Errors
31    /// Returns an error when reading the current position, seeking to `offset`,
32    /// writing bytes, or restoring the original position fails. If restoration
33    /// fails, the restoration error is returned.
34    fn write_all_at_preserving_position(
35        &mut self,
36        offset: u64,
37        buffer: &[u8],
38    ) -> Result<()>;
39}
40
41impl<T> WriteSeekExt for T
42where
43    T: Write + Seek + ?Sized,
44{
45    #[inline]
46    fn write_all_at_preserving_position(
47        &mut self,
48        offset: u64,
49        buffer: &[u8],
50    ) -> Result<()> {
51        let position = self.stream_position()?;
52        let write_result = match self.seek(SeekFrom::Start(offset)) {
53            Ok(_) => self.write_all(buffer),
54            Err(error) => Err(error),
55        };
56        let restore_result = self.seek(SeekFrom::Start(position));
57        match (write_result, restore_result) {
58            (Ok(()), Ok(_)) => Ok(()),
59            (Err(error), Ok(_)) => Err(error),
60            (_, Err(error)) => Err(error),
61        }
62    }
63}