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