[go: nahoru, domu]

Skip to content

Commit

Permalink
rust: Auto merge of #104160 - Ayush1325:windows-args, r=m-ou-se
Browse files Browse the repository at this point in the history
Commit: 1dcf6add3d1c8c68ebebc28dbd5edd9806346432
  • Loading branch information
bors authored and sourcegraph-bot committed Dec 1, 2022
1 parent cd0d52a commit bc1f5d0
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 52 deletions.
54 changes: 2 additions & 52 deletions rust/library/std/src/sys/windows/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,16 @@ mod tests;
use crate::ffi::OsString;
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
use crate::num::NonZeroU16;
use crate::os::windows::prelude::*;
use crate::path::PathBuf;
use crate::ptr::NonNull;
use crate::sys::c;
use crate::sys::process::ensure_no_nuls;
use crate::sys::windows::os::current_exe;
use crate::sys_common::wstr::WStrUnits;
use crate::vec;

use core::iter;
use crate::iter;

/// This is the const equivalent to `NonZeroU16::new(n).unwrap()`
///
Expand Down Expand Up @@ -199,55 +198,6 @@ impl ExactSizeIterator for Args {
}
}

/// A safe iterator over a LPWSTR
/// (aka a pointer to a series of UTF-16 code units terminated by a NULL).
struct WStrUnits<'a> {
// The pointer must never be null...
lpwstr: NonNull<u16>,
// ...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.
unsafe fn new(lpwstr: *const u16) -> Option<Self> {
Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData })
}
fn peek(&self) -> Option<NonZeroU16> {
// 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.
fn advance_while<P: FnMut(NonZeroU16) -> 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<NonZeroU16> {
// 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)
}
}
}

#[derive(Debug)]
pub(crate) enum Arg {
/// Add quotes (if needed)
Expand Down
1 change: 1 addition & 0 deletions rust/library/std/src/sys_common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,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! {
Expand Down
59 changes: 59 additions & 0 deletions rust/library/std/src/sys_common/wstr.rs
Original file line number Diff line number Diff line change
@@ -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<u16>,
// ...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<Self> {
Some(Self { lpwstr: NonNull::new(lpwstr as _)?, lifetime: PhantomData })
}

pub fn peek(&self) -> Option<NonZeroU16> {
// 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<P: FnMut(NonZeroU16) -> 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<NonZeroU16> {
// 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)
}
}
}

0 comments on commit bc1f5d0

Please sign in to comment.