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