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