1//! This module contains constructs to work with 16-bit characters (UCS-2 or UTF-16)
2#![allow(dead_code)]
3
4use crate::marker::PhantomData;
5use crate::num::NonZero;
6use crate::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).
10pub 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
17impl 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.
22 pub unsafe fn new(lpwstr: *const u16) -> Option<Self> {
23 Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData })
24 }
25
26 pub fn peek(&self) -> Option<NonZero<u16>> {
27 // SAFETY: It's always safe to read the current item because we don't
28 // ever move out of the array's bounds.
29 unsafe { NonZero::new(*self.lpwstr.as_ptr()) }
30 }
31
32 /// Advance the iterator while `predicate` returns true.
33 /// Returns the number of items it advanced by.
34 pub fn advance_while<P: FnMut(NonZero<u16>) -> bool>(&mut self, mut predicate: P) -> usize {
35 let mut counter = 0;
36 while let Some(w) = self.peek() {
37 if !predicate(w) {
38 break;
39 }
40 counter += 1;
41 self.next();
42 }
43 counter
44 }
45}
46
47impl Iterator for WStrUnits<'_> {
48 // This can never return zero as that marks the end of the string.
49 type Item = NonZero<u16>;
50
51 fn next(&mut self) -> Option<Self::Item> {
52 // SAFETY: If NULL is reached we immediately return.
53 // Therefore it's safe to advance the pointer after that.
54 unsafe {
55 let next: NonZero = self.peek()?;
56 self.lpwstr = NonNull::new_unchecked(self.lpwstr.as_ptr().add(count:1));
57 Some(next)
58 }
59 }
60}
61