nt_string/unicode_string/strmut.rs
1// Copyright 2023 Colin Finck <colin@reactos.org>
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4use core::cmp::Ordering;
5use core::marker::PhantomData;
6use core::ops::Deref;
7use core::{fmt, mem, slice};
8
9use widestring::{U16CStr, U16Str};
10
11use crate::error::Result;
12use crate::helpers::RawNtString;
13use crate::NtStringError;
14
15use super::{impl_eq, impl_partial_cmp, NtUnicodeStr};
16
17/// A mutable reference to a `UNICODE_STRING` (equivalent of `&mut str`).
18///
19/// See the [module-level documentation](super) for more details.
20#[derive(Debug)]
21#[repr(transparent)]
22pub struct NtUnicodeStrMut<'a> {
23 raw: RawNtString<*mut u16>,
24 _lifetime: PhantomData<&'a ()>,
25}
26
27impl<'a> NtUnicodeStrMut<'a> {
28 /// Returns a `*mut NtUnicodeStrMut` pointer
29 /// (mainly for non-Rust interfaces that expect a mutable `UNICODE_STRING*`).
30 pub fn as_mut_ptr(&mut self) -> *mut Self {
31 self as *mut Self
32 }
33
34 /// Returns a mutable slice to the raw `u16` codepoints of the string.
35 pub fn as_mut_slice(&mut self) -> &'a mut [u16] {
36 unsafe { slice::from_raw_parts_mut(self.raw.buffer, self.len_in_elements()) }
37 }
38
39 /// Returns a mutable [`U16Str`] reference for this string.
40 ///
41 /// The [`U16Str`] will only contain the characters and not the NUL terminator.
42 pub fn as_mut_u16str(&mut self) -> &'a U16Str {
43 U16Str::from_slice_mut(self.as_mut_slice())
44 }
45
46 /// Returns an immutable [`NtUnicodeStr`] reference for this string.
47 pub fn as_unicode_str(&'a self) -> &NtUnicodeStr<'a> {
48 self.deref()
49 }
50
51 /// Truncates this string, removing all contents.
52 ///
53 /// While this means the string will have a length of zero, it does not touch its capacity.
54 pub fn clear(&mut self) {
55 self.raw.length = 0;
56 }
57
58 /// Creates an [`NtUnicodeStrMut`] from a [`u16`] string buffer, a byte length of the string,
59 /// and a buffer capacity in bytes (also known as "maximum length").
60 ///
61 /// The string is expected to consist of valid UTF-16 characters.
62 /// The buffer may or may not be NUL-terminated.
63 /// In any case, `length` does NOT include the terminating NUL character.
64 ///
65 /// This function is `unsafe` and you are advised to use any of the safe `try_from_*`
66 /// functions over this one if possible.
67 ///
68 /// # Safety
69 ///
70 /// Behavior is undefined if any of the following conditions are violated:
71 ///
72 /// * `length` must be less than or equal to `maximum_length`.
73 /// * `buffer` must be valid for at least `maximum_length` bytes.
74 /// * `buffer` must point to `length` consecutive properly initialized bytes.
75 /// * `buffer` must be valid for the duration of lifetime `'a`.
76 pub const unsafe fn from_raw_parts(buffer: *mut u16, length: u16, maximum_length: u16) -> Self {
77 debug_assert!(length <= maximum_length);
78
79 Self {
80 raw: RawNtString {
81 length,
82 maximum_length,
83 buffer,
84 },
85 _lifetime: PhantomData,
86 }
87 }
88
89 /// Removes the last character from the string and returns it.
90 ///
91 /// An [`NtStringError::UnpairedUtf16Surrogate`] error is returned if the last character is an unpaired surrogate.
92 /// In that case, the unpaired surrogate codepoint is removed from the string anyway.
93 ///
94 /// `None` is returned if this string is empty.
95 ///
96 /// [`NtStringError::UnpairedUtf16Surrogate`]: crate::error::NtStringError::UnpairedUtf16Surrogate
97 pub fn pop(&mut self) -> Option<Result<char>> {
98 match self.chars().rev().next()? {
99 Ok(c) => {
100 self.raw.length -= (c.len_utf16() * mem::size_of::<u16>()) as u16;
101 Some(Ok(c))
102 }
103 Err(e) => {
104 // An unpaired surrogate is always a single character.
105 self.raw.length -= mem::size_of::<u16>() as u16;
106 Some(Err(e))
107 }
108 }
109 }
110
111 /// Creates an [`NtUnicodeStrMut`] from an existing [`u16`] string buffer without a terminating NUL character.
112 ///
113 /// The string is expected to consist of valid UTF-16 characters.
114 ///
115 /// The given buffer becomes the internal buffer of the [`NtUnicodeStrMut`] and therefore won't be NUL-terminated.
116 /// See the [module-level documentation](super) for the implications of that.
117 ///
118 /// This function has *O*(1) complexity.
119 ///
120 /// If you have a NUL-terminated buffer, either use [`try_from_u16_until_nul`] or convert from a [`U16CStr`]
121 /// using the corresponding [`TryFrom`] implementation.
122 ///
123 /// [`try_from_u16_until_nul`]: Self::try_from_u16_until_nul
124 pub fn try_from_u16(buffer: &mut [u16]) -> Result<Self> {
125 let unicode_str = NtUnicodeStr::try_from_u16(buffer)?;
126
127 // SAFETY: `unicode_str` was created from a mutable `buffer` and
128 // `NtUnicodeStr` and `NtUnicodeStrMut` have the same memory layout,
129 // so we can safely transmute `NtUnicodeStr` to `NtUnicodeStrMut`.
130 let unicode_str_mut = unsafe { mem::transmute(unicode_str) };
131
132 Ok(unicode_str_mut)
133 }
134
135 /// Creates an [`NtUnicodeStrMut`] from an existing [`u16`] string buffer that contains at least one NUL character.
136 ///
137 /// The string is expected to consist of valid UTF-16 characters.
138 ///
139 /// The string will be terminated at the NUL character.
140 /// An [`NtStringError::NulNotFound`] error is returned if no NUL character could be found.
141 /// As a consequence, this function has *O*(*n*) complexity.
142 ///
143 /// The resulting internal `buffer` of [`NtUnicodeStrMut`] will be NUL-terminated.
144 /// See the [module-level documentation](super) for the implications of that.
145 ///
146 /// Use [`try_from_u16`] if you have a buffer that is not NUL-terminated.
147 /// You can also convert from a NUL-terminated [`U16CStr`] in *O*(1) via the corresponding [`TryFrom`] implementation.
148 ///
149 /// [`try_from_u16`]: Self::try_from_u16
150 pub fn try_from_u16_until_nul(buffer: &mut [u16]) -> Result<Self> {
151 let unicode_str = NtUnicodeStr::try_from_u16_until_nul(buffer)?;
152
153 // SAFETY: `unicode_str` was created from a mutable `buffer` and
154 // `NtUnicodeStr` and `NtUnicodeStrMut` have the same memory layout,
155 // so we can safely transmute `NtUnicodeStr` to `NtUnicodeStrMut`.
156 let unicode_str_mut = unsafe { mem::transmute(unicode_str) };
157
158 Ok(unicode_str_mut)
159 }
160}
161
162impl<'a> Deref for NtUnicodeStrMut<'a> {
163 type Target = NtUnicodeStr<'a>;
164
165 fn deref(&self) -> &Self::Target {
166 // SAFETY: `NtUnicodeStr` and `NtUnicodeStrMut` have the same memory layout,
167 // with the additional constraint of an immutable `buffer` pointer in `NtUnicodeStr`,
168 // so we can safely transmute `NtUnicodeStrMut` to `NtUnicodeStr`.
169 unsafe { mem::transmute(self) }
170 }
171}
172
173impl<'a> fmt::Display for NtUnicodeStrMut<'a> {
174 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
175 fmt::Display::fmt(self.deref(), f)
176 }
177}
178
179impl<'a> Eq for NtUnicodeStrMut<'a> {}
180
181impl<'a> Ord for NtUnicodeStrMut<'a> {
182 fn cmp(&self, other: &Self) -> Ordering {
183 Ord::cmp(self.deref(), other.deref())
184 }
185}
186
187impl<'a> TryFrom<&'a mut U16CStr> for NtUnicodeStrMut<'a> {
188 type Error = NtStringError;
189
190 /// Converts a mutable [`U16CStr`] reference into an [`NtUnicodeStrMut`].
191 ///
192 /// The internal buffer will be NUL-terminated.
193 /// See the [module-level documentation](super) for the implications of that.
194 fn try_from(value: &'a mut U16CStr) -> Result<Self> {
195 let unicode_str = NtUnicodeStr::try_from(&*value)?;
196
197 // SAFETY: `unicode_str` was created from a mutable `value` and
198 // `NtUnicodeStr` and `NtUnicodeStrMut` have the same memory layout,
199 // so we can safely transmute `NtUnicodeStr` to `NtUnicodeStrMut`.
200 let unicode_str_mut = unsafe { mem::transmute(unicode_str) };
201
202 Ok(unicode_str_mut)
203 }
204}
205
206impl<'a> TryFrom<&'a mut U16Str> for NtUnicodeStrMut<'a> {
207 type Error = NtStringError;
208
209 /// Converts a [`U16Str`] reference into an [`NtUnicodeStr`].
210 ///
211 /// The internal buffer will NOT be NUL-terminated.
212 /// See the [module-level documentation](super) for the implications of that.
213 fn try_from(value: &'a mut U16Str) -> Result<Self> {
214 Self::try_from_u16(value.as_mut_slice())
215 }
216}
217
218impl_eq! { NtUnicodeStrMut<'a>, NtUnicodeStrMut<'b> }
219impl_eq! { NtUnicodeStr<'a>, NtUnicodeStrMut<'b> }
220impl_eq! { NtUnicodeStrMut<'a>, NtUnicodeStr<'b> }
221impl_eq! { NtUnicodeStrMut<'a>, str }
222impl_eq! { str, NtUnicodeStrMut<'a> }
223impl_eq! { NtUnicodeStrMut<'a>, &str }
224impl_eq! { &str, NtUnicodeStrMut<'a> }
225
226impl_partial_cmp! { NtUnicodeStrMut<'a>, NtUnicodeStrMut<'b> }
227impl_partial_cmp! { NtUnicodeStr<'a>, NtUnicodeStrMut<'b> }
228impl_partial_cmp! { NtUnicodeStrMut<'a>, NtUnicodeStr<'b> }
229impl_partial_cmp! { NtUnicodeStrMut<'a>, str }
230impl_partial_cmp! { str, NtUnicodeStrMut<'a> }
231impl_partial_cmp! { NtUnicodeStrMut<'a>, &str }
232impl_partial_cmp! { &str, NtUnicodeStrMut<'a> }