xref: /drstd/src/std/sys_common/wstr.rs (revision 9670759b785600bf6315e4173e46a602f16add7a)
1 //! This module contains constructs to work with 16-bit characters (UCS-2 or UTF-16)
2 #![allow(dead_code)]
3 
4 use crate::std::marker::PhantomData;
5 use crate::std::num::NonZeroU16;
6 use crate::std::ptr::NonNull;
7 
8 /// A safe iterator over a LPWSTR
9 /// (aka a pointer to a series of UTF-16 code units terminated by a NULL).
10 pub struct WStrUnits<'a> {
11     // The pointer must never be null...
12     lpwstr: NonNull<u16>,
13     // ...and the memory it points to must be valid for this lifetime.
14     lifetime: PhantomData<&'a [u16]>,
15 }
16 
17 impl WStrUnits<'_> {
18     /// Create the iterator. Returns `None` if `lpwstr` is null.
19     ///
20     /// SAFETY: `lpwstr` must point to a null-terminated wide string that lives
21     /// at least as long as the lifetime of this struct.
new(lpwstr: *const u16) -> Option<Self>22     pub unsafe fn new(lpwstr: *const u16) -> Option<Self> {
23         Some(Self {
24             lpwstr: NonNull::new(lpwstr as _)?,
25             lifetime: PhantomData,
26         })
27     }
28 
peek(&self) -> Option<NonZeroU16>29     pub fn peek(&self) -> Option<NonZeroU16> {
30         // SAFETY: It's always safe to read the current item because we don't
31         // ever move out of the array's bounds.
32         unsafe { NonZeroU16::new(*self.lpwstr.as_ptr()) }
33     }
34 
35     /// Advance the iterator while `predicate` returns true.
36     /// Returns the number of items it advanced by.
advance_while<P: FnMut(NonZeroU16) -> bool>(&mut self, mut predicate: P) -> usize37     pub fn advance_while<P: FnMut(NonZeroU16) -> bool>(&mut self, mut predicate: P) -> usize {
38         let mut counter = 0;
39         while let Some(w) = self.peek() {
40             if !predicate(w) {
41                 break;
42             }
43             counter += 1;
44             self.next();
45         }
46         counter
47     }
48 }
49 
50 impl Iterator for WStrUnits<'_> {
51     // This can never return zero as that marks the end of the string.
52     type Item = NonZeroU16;
next(&mut self) -> Option<NonZeroU16>53     fn next(&mut self) -> Option<NonZeroU16> {
54         // SAFETY: If NULL is reached we immediately return.
55         // Therefore it's safe to advance the pointer after that.
56         unsafe {
57             let next = self.peek()?;
58             self.lpwstr = NonNull::new_unchecked(self.lpwstr.as_ptr().add(1));
59             Some(next)
60         }
61     }
62 }
63