qubit_io/std_io/ext/write_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 standard byte writers.
10
11use std::io::Result;
12use std::io::Write;
13
14use crate::util::UncheckedSlice;
15
16/// Extension methods for [`Write`] values.
17///
18/// `WriteExt` provides small method-style helpers for byte writers. The
19/// methods are implemented for every type that implements [`Write`], including
20/// `dyn Write` trait objects.
21///
22/// # Examples
23///
24/// ```
25/// use qubit_io::std_io::ext::WriteExt;
26///
27/// let bytes = b"_abc_";
28/// let mut output = Vec::new();
29/// // SAFETY: 1..3 is within the five-byte source slice.
30/// let written = unsafe { output.write_unchecked(bytes, 1, 2)? };
31/// assert_eq!(2, written);
32/// // SAFETY: 3..4 is within the same source slice.
33/// unsafe { output.write_all_unchecked(bytes, 3, 1)? };
34/// assert_eq!(b"abc", output.as_slice());
35/// # Ok::<(), std::io::Error>(())
36/// ```
37pub trait WriteExt: Write {
38 /// Writes bytes from a range of `buffer` without checking the range bounds
39 /// in release builds.
40 ///
41 /// This method delegates to [`Write::write`] after creating the source
42 /// slice with raw pointer arithmetic. It performs at most one write
43 /// operation and returns the number of bytes written, keeping the same
44 /// short-write and error behavior as [`Write::write`]. A single call may
45 /// accept only a prefix; use [`Self::write_all_unchecked`] when the full
46 /// range must be written.
47 ///
48 /// # Parameters
49 /// - `buffer`: Source buffer.
50 /// - `start_index`: Start offset inside `buffer`.
51 /// - `count`: Maximum number of bytes to write.
52 ///
53 /// # Returns
54 /// The number of bytes written from `buffer[start_index..start_index +
55 /// count]`. The value is in `0..=count`.
56 ///
57 /// # Errors
58 /// Returns the error reported by [`Write::write`].
59 ///
60 /// # Panics
61 /// Panics in debug builds if the requested source range does not fit.
62 ///
63 /// # Safety
64 /// The caller must guarantee that `start_index..start_index + count` is a
65 /// valid range within `buffer` and that `start_index + count` does not
66 /// overflow `usize`.
67 #[inline(always)]
68 unsafe fn write_unchecked(&mut self, buffer: &[u8], start_index: usize, count: usize) -> Result<usize> {
69 // SAFETY: The caller guarantees that the computed pointer and length
70 // form a valid subslice of `buffer`.
71 let source = unsafe { UncheckedSlice::subslice(buffer, start_index, count) };
72 self.write(source)
73 }
74
75 /// Writes exactly `count` bytes from a range of `buffer` without checking
76 /// the range bounds in release builds.
77 ///
78 /// This method delegates to [`Write::write_all`] after creating the source
79 /// slice with raw pointer arithmetic. It keeps the same short-write,
80 /// [`std::io::ErrorKind::Interrupted`], and
81 /// [`std::io::ErrorKind::WriteZero`] behavior as [`Write::write_all`].
82 ///
83 /// # Parameters
84 /// - `buffer`: Source buffer.
85 /// - `start_index`: Start offset inside `buffer`.
86 /// - `count`: Number of bytes to write.
87 ///
88 /// # Returns
89 /// `Ok(())` after the requested range has been written.
90 ///
91 /// # Errors
92 /// Returns the error reported by [`Write::write_all`].
93 ///
94 /// # Panics
95 /// Panics in debug builds if the requested source range does not fit.
96 ///
97 /// # Safety
98 /// The caller must guarantee that `start_index..start_index + count` is a
99 /// valid range within `buffer` and that `start_index + count` does not
100 /// overflow `usize`.
101 #[inline(always)]
102 unsafe fn write_all_unchecked(&mut self, buffer: &[u8], start_index: usize, count: usize) -> Result<()> {
103 // SAFETY: The caller guarantees that the computed pointer and length
104 // form a valid subslice of `buffer`.
105 let source = unsafe { UncheckedSlice::subslice(buffer, start_index, count) };
106 self.write_all(source)
107 }
108}
109
110impl<T> WriteExt for T where T: Write + ?Sized {}