Skip to main content

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 {}