From 348a0585054d633b50f515d95e3c42ea8721e106 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Tue, 8 Nov 2022 23:23:08 +0530 Subject: Extract WStrUnits to sys_common::wstr This commit extracts WStrUnits from sys::windows::args to sys_common::wstr. This allows using the same structure for other targets which use wtf8 (example UEFI). This was originally a part of https://github.com/rust-lang/rust/pull/100316 Signed-off-by: Ayush Singh --- library/std/src/sys_common/mod.rs | 1 + library/std/src/sys_common/wstr.rs | 59 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 library/std/src/sys_common/wstr.rs (limited to 'library/std/src/sys_common') diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 8c19f9332dc..53259e8dbbd 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -35,6 +35,7 @@ pub mod thread; pub mod thread_info; pub mod thread_local_dtor; pub mod thread_parker; +pub mod wstr; pub mod wtf8; cfg_if::cfg_if! { diff --git a/library/std/src/sys_common/wstr.rs b/library/std/src/sys_common/wstr.rs new file mode 100644 index 00000000000..b230fd1a829 --- /dev/null +++ b/library/std/src/sys_common/wstr.rs @@ -0,0 +1,59 @@ +//! This module contains constructs to work with 16-bit characters (UCS-2 or UTF-16) +#![allow(dead_code)] + +use crate::marker::PhantomData; +use crate::num::NonZeroU16; +use crate::ptr::NonNull; + +/// A safe iterator over a LPWSTR +/// (aka a pointer to a series of UTF-16 code units terminated by a NULL). +pub struct WStrUnits<'a> { + // The pointer must never be null... + lpwstr: NonNull, + // ...and the memory it points to must be valid for this lifetime. + lifetime: PhantomData<&'a [u16]>, +} + +impl WStrUnits<'_> { + /// Create the iterator. Returns `None` if `lpwstr` is null. + /// + /// SAFETY: `lpwstr` must point to a null-terminated wide string that lives + /// at least as long as the lifetime of this struct. + pub unsafe fn new(lpwstr: *const u16) -> Option { + Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData }) + } + + pub fn peek(&self) -> Option { + // SAFETY: It's always safe to read the current item because we don't + // ever move out of the array's bounds. + unsafe { NonZeroU16::new(*self.lpwstr.as_ptr()) } + } + + /// Advance the iterator while `predicate` returns true. + /// Returns the number of items it advanced by. + pub fn advance_while bool>(&mut self, mut predicate: P) -> usize { + let mut counter = 0; + while let Some(w) = self.peek() { + if !predicate(w) { + break; + } + counter += 1; + self.next(); + } + counter + } +} + +impl Iterator for WStrUnits<'_> { + // This can never return zero as that marks the end of the string. + type Item = NonZeroU16; + fn next(&mut self) -> Option { + // SAFETY: If NULL is reached we immediately return. + // Therefore it's safe to advance the pointer after that. + unsafe { + let next = self.peek()?; + self.lpwstr = NonNull::new_unchecked(self.lpwstr.as_ptr().add(1)); + Some(next) + } + } +} -- cgit 1.4.1-3-g733a5