nt_string/unicode_string/
str.rs1use core::cmp::Ordering;
5use core::iter::Copied;
6use core::marker::PhantomData;
7use core::slice::Iter;
8use core::{fmt, mem, slice};
9
10use widestring::{U16CStr, U16Str};
11
12use crate::error::{NtStringError, Result};
13use crate::helpers::{cmp_iter, RawNtString};
14
15use super::iter::{Chars, CharsLossy};
16
17#[derive(Clone, Copy, Debug)]
21#[repr(transparent)]
22pub struct NtUnicodeStr<'a> {
23 raw: RawNtString<*const u16>,
24 _lifetime: PhantomData<&'a ()>,
25}
26
27impl<'a> NtUnicodeStr<'a> {
28 pub fn as_ptr(&self) -> *const Self {
31 self as *const Self
32 }
33
34 pub fn as_slice(&self) -> &'a [u16] {
36 unsafe { slice::from_raw_parts(self.raw.buffer, self.len_in_elements()) }
37 }
38
39 pub fn as_u16str(&self) -> &'a U16Str {
43 U16Str::from_slice(self.as_slice())
44 }
45
46 pub fn capacity(&self) -> u16 {
48 self.raw.maximum_length
49 }
50
51 #[allow(unused)]
53 pub(crate) fn capacity_in_elements(&self) -> usize {
54 usize::from(self.raw.maximum_length) / mem::size_of::<u16>()
55 }
56
57 pub fn chars(&self) -> Chars<'_> {
66 Chars::new(self)
67 }
68
69 pub fn chars_lossy(&self) -> CharsLossy<'_> {
78 CharsLossy::new(self)
79 }
80
81 pub const unsafe fn from_raw_parts(
103 buffer: *const u16,
104 length: u16,
105 maximum_length: u16,
106 ) -> Self {
107 debug_assert!(length <= maximum_length);
108
109 Self {
110 raw: RawNtString {
111 length,
112 maximum_length,
113 buffer,
114 },
115 _lifetime: PhantomData,
116 }
117 }
118
119 pub fn is_empty(&self) -> bool {
121 self.raw.length == 0
122 }
123
124 pub fn len(&self) -> u16 {
129 self.raw.length
130 }
131
132 pub(crate) fn len_in_elements(&self) -> usize {
137 usize::from(self.raw.length) / mem::size_of::<u16>()
138 }
139
140 #[allow(unused)]
142 pub(crate) fn remaining_capacity(&self) -> u16 {
143 debug_assert!(self.raw.maximum_length >= self.raw.length);
144 self.raw.maximum_length - self.raw.length
145 }
146
147 pub fn try_from_u16(buffer: &'a [u16]) -> Result<Self> {
161 let length = Self::try_length_from_u16(buffer)?;
162
163 Ok(Self {
164 raw: RawNtString {
165 length,
166 maximum_length: length,
167 buffer: buffer.as_ptr(),
168 },
169 _lifetime: PhantomData,
170 })
171 }
172
173 pub fn try_from_u16_until_nul(buffer: &'a [u16]) -> Result<Self> {
189 let (length, maximum_length) = Self::try_length_from_u16_until_nul(buffer)?;
190
191 Ok(Self {
192 raw: RawNtString {
193 length,
194 maximum_length,
195 buffer: buffer.as_ptr(),
196 },
197 _lifetime: PhantomData,
198 })
199 }
200
201 pub(crate) fn try_length_from_u16(buffer: &[u16]) -> Result<u16> {
202 let elements = buffer.len();
203 let length_usize = elements
204 .checked_mul(mem::size_of::<u16>())
205 .ok_or(NtStringError::BufferSizeExceedsU16)?;
206 let length =
207 u16::try_from(length_usize).map_err(|_| NtStringError::BufferSizeExceedsU16)?;
208
209 Ok(length)
210 }
211
212 pub(crate) fn try_length_from_u16_cstr(u16cstr: &U16CStr) -> Result<(u16, u16)> {
213 let buffer = u16cstr.as_slice_with_nul();
214
215 let maximum_length_in_elements = buffer.len();
217 let maximum_length_in_bytes = maximum_length_in_elements
218 .checked_mul(mem::size_of::<u16>())
219 .ok_or(NtStringError::BufferSizeExceedsU16)?;
220 let maximum_length = u16::try_from(maximum_length_in_bytes)
221 .map_err(|_| NtStringError::BufferSizeExceedsU16)?;
222
223 debug_assert!(maximum_length >= mem::size_of::<u16>() as u16);
225 let length = maximum_length - mem::size_of::<u16>() as u16;
226
227 Ok((length, maximum_length))
228 }
229
230 pub(crate) fn try_length_from_u16_until_nul(buffer: &[u16]) -> Result<(u16, u16)> {
231 match buffer.iter().position(|x| *x == 0) {
232 Some(nul_pos) => {
233 let maximum_elements = nul_pos
235 .checked_add(1)
236 .ok_or(NtStringError::BufferSizeExceedsU16)?;
237 let maximum_length_usize = maximum_elements
238 .checked_mul(mem::size_of::<u16>())
239 .ok_or(NtStringError::BufferSizeExceedsU16)?;
240 let maximum_length = u16::try_from(maximum_length_usize)
241 .map_err(|_| NtStringError::BufferSizeExceedsU16)?;
242
243 let length = maximum_length - mem::size_of::<u16>() as u16;
245
246 Ok((length, maximum_length))
247 }
248 None => Err(NtStringError::NulNotFound),
249 }
250 }
251
252 pub(crate) fn u16_iter(&'a self) -> Copied<Iter<'a, u16>> {
253 self.as_slice().iter().copied()
254 }
255}
256
257impl<'a> fmt::Display for NtUnicodeStr<'a> {
258 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
259 for single_char in self.chars_lossy() {
260 single_char.fmt(f)?;
261 }
262
263 Ok(())
264 }
265}
266
267impl<'a> Eq for NtUnicodeStr<'a> {}
268
269impl<'a> Ord for NtUnicodeStr<'a> {
270 fn cmp(&self, other: &Self) -> Ordering {
271 cmp_iter(self.u16_iter(), other.u16_iter())
272 }
273}
274
275impl<'a, 'b> PartialEq<NtUnicodeStr<'a>> for NtUnicodeStr<'b> {
276 fn eq(&self, other: &NtUnicodeStr<'a>) -> bool {
278 self.as_slice() == other.as_slice()
279 }
280}
281
282impl<'a> PartialEq<str> for NtUnicodeStr<'a> {
283 fn eq(&self, other: &str) -> bool {
284 cmp_iter(self.u16_iter(), other.encode_utf16()) == Ordering::Equal
285 }
286}
287
288impl<'a> PartialEq<NtUnicodeStr<'a>> for str {
289 fn eq(&self, other: &NtUnicodeStr<'a>) -> bool {
290 cmp_iter(self.encode_utf16(), other.u16_iter()) == Ordering::Equal
291 }
292}
293
294impl<'a> PartialEq<&str> for NtUnicodeStr<'a> {
295 fn eq(&self, other: &&str) -> bool {
296 cmp_iter(self.u16_iter(), other.encode_utf16()) == Ordering::Equal
297 }
298}
299
300impl<'a> PartialEq<NtUnicodeStr<'a>> for &str {
301 fn eq(&self, other: &NtUnicodeStr<'a>) -> bool {
302 cmp_iter(self.encode_utf16(), other.u16_iter()) == Ordering::Equal
303 }
304}
305
306impl<'a> PartialOrd for NtUnicodeStr<'a> {
307 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
308 Some(self.cmp(other))
309 }
310}
311
312impl<'a> PartialOrd<str> for NtUnicodeStr<'a> {
313 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
314 Some(cmp_iter(self.u16_iter(), other.encode_utf16()))
315 }
316}
317
318impl<'a> PartialOrd<NtUnicodeStr<'a>> for str {
319 fn partial_cmp(&self, other: &NtUnicodeStr<'a>) -> Option<Ordering> {
320 Some(cmp_iter(self.encode_utf16(), other.u16_iter()))
321 }
322}
323
324impl<'a> PartialOrd<&str> for NtUnicodeStr<'a> {
325 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
326 Some(cmp_iter(self.u16_iter(), other.encode_utf16()))
327 }
328}
329
330impl<'a> PartialOrd<NtUnicodeStr<'a>> for &str {
331 fn partial_cmp(&self, other: &NtUnicodeStr<'a>) -> Option<Ordering> {
332 Some(cmp_iter(self.encode_utf16(), other.u16_iter()))
333 }
334}
335
336impl<'a> TryFrom<&'a U16CStr> for NtUnicodeStr<'a> {
337 type Error = NtStringError;
338
339 fn try_from(value: &'a U16CStr) -> Result<Self> {
344 let (length, maximum_length) = Self::try_length_from_u16_cstr(value)?;
345
346 Ok(Self {
347 raw: RawNtString {
348 length,
349 maximum_length,
350 buffer: value.as_ptr(),
351 },
352 _lifetime: PhantomData,
353 })
354 }
355}
356
357impl<'a> TryFrom<&'a U16Str> for NtUnicodeStr<'a> {
358 type Error = NtStringError;
359
360 fn try_from(value: &'a U16Str) -> Result<Self> {
365 Self::try_from_u16(value.as_slice())
366 }
367}