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