Skip to content

Commit d584f5a

Browse files
authored
Rollup merge of #69937 - TyPR124:osstr_ascii, r=dtolnay
ASCII methods on OsStr Would close #69566 I don't know enough about encodings to know if this is a valid change, however the comment on the issue suggests it could be. This does two things: 1. Makes ASCII methods available on OsStr 2. Makes it possible to obtain a `&mut OsStr`. This is necessary to actually use `OsStr::make_ascii_*case` methods since they modify the underlying value. As far as I can tell, the only way to modify a `&mut OsStr` is via the methods I just added. My original hope was to have these methods on `OsStrExt` for Windows, since the standard library already assumes `make_ascii_uppercase` is valid in Windows (see the change I made to windows/process.rs). If it is found these are not valid changes on non-Windows platforms, I can move the methods to the ext trait instead.
2 parents 7762131 + 271d43b commit d584f5a

File tree

5 files changed

+235
-11
lines changed

5 files changed

+235
-11
lines changed

src/libstd/ffi/os_str.rs

+141
Original file line numberDiff line numberDiff line change
@@ -698,6 +698,147 @@ impl OsStr {
698698
fn bytes(&self) -> &[u8] {
699699
unsafe { &*(&self.inner as *const _ as *const [u8]) }
700700
}
701+
702+
/// Converts this string to its ASCII lower case equivalent in-place.
703+
///
704+
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
705+
/// but non-ASCII letters are unchanged.
706+
///
707+
/// To return a new lowercased value without modifying the existing one, use
708+
/// [`to_ascii_lowercase`].
709+
///
710+
/// [`to_ascii_lowercase`]: #method.to_ascii_lowercase
711+
///
712+
/// # Examples
713+
///
714+
/// ```
715+
/// #![feature(osstring_ascii)]
716+
/// use std::ffi::OsString;
717+
///
718+
/// let mut s = OsString::from("GRÜßE, JÜRGEN ❤");
719+
///
720+
/// s.make_ascii_lowercase();
721+
///
722+
/// assert_eq!("grÜße, jÜrgen ❤", s);
723+
/// ```
724+
#[unstable(feature = "osstring_ascii", issue = "70516")]
725+
pub fn make_ascii_lowercase(&mut self) {
726+
self.inner.make_ascii_lowercase()
727+
}
728+
729+
/// Converts this string to its ASCII upper case equivalent in-place.
730+
///
731+
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
732+
/// but non-ASCII letters are unchanged.
733+
///
734+
/// To return a new uppercased value without modifying the existing one, use
735+
/// [`to_ascii_uppercase`].
736+
///
737+
/// [`to_ascii_uppercase`]: #method.to_ascii_uppercase
738+
///
739+
/// # Examples
740+
///
741+
/// ```
742+
/// #![feature(osstring_ascii)]
743+
/// use std::ffi::OsString;
744+
///
745+
/// let mut s = OsString::from("Grüße, Jürgen ❤");
746+
///
747+
/// s.make_ascii_uppercase();
748+
///
749+
/// assert_eq!("GRüßE, JüRGEN ❤", s);
750+
/// ```
751+
#[unstable(feature = "osstring_ascii", issue = "70516")]
752+
pub fn make_ascii_uppercase(&mut self) {
753+
self.inner.make_ascii_uppercase()
754+
}
755+
756+
/// Returns a copy of this string where each character is mapped to its
757+
/// ASCII lower case equivalent.
758+
///
759+
/// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
760+
/// but non-ASCII letters are unchanged.
761+
///
762+
/// To lowercase the value in-place, use [`make_ascii_lowercase`].
763+
///
764+
/// [`make_ascii_lowercase`]: #method.make_ascii_lowercase
765+
///
766+
/// # Examples
767+
///
768+
/// ```
769+
/// #![feature(osstring_ascii)]
770+
/// use std::ffi::OsString;
771+
/// let s = OsString::from("Grüße, Jürgen ❤");
772+
///
773+
/// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase());
774+
/// ```
775+
#[unstable(feature = "osstring_ascii", issue = "70516")]
776+
pub fn to_ascii_lowercase(&self) -> OsString {
777+
OsString::from_inner(self.inner.to_ascii_lowercase())
778+
}
779+
780+
/// Returns a copy of this string where each character is mapped to its
781+
/// ASCII upper case equivalent.
782+
///
783+
/// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
784+
/// but non-ASCII letters are unchanged.
785+
///
786+
/// To uppercase the value in-place, use [`make_ascii_uppercase`].
787+
///
788+
/// [`make_ascii_uppercase`]: #method.make_ascii_uppercase
789+
///
790+
/// # Examples
791+
///
792+
/// ```
793+
/// #![feature(osstring_ascii)]
794+
/// use std::ffi::OsString;
795+
/// let s = OsString::from("Grüße, Jürgen ❤");
796+
///
797+
/// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase());
798+
/// ```
799+
#[unstable(feature = "osstring_ascii", issue = "70516")]
800+
pub fn to_ascii_uppercase(&self) -> OsString {
801+
OsString::from_inner(self.inner.to_ascii_uppercase())
802+
}
803+
804+
/// Checks if all characters in this string are within the ASCII range.
805+
///
806+
/// # Examples
807+
///
808+
/// ```
809+
/// #![feature(osstring_ascii)]
810+
/// use std::ffi::OsString;
811+
///
812+
/// let ascii = OsString::from("hello!\n");
813+
/// let non_ascii = OsString::from("Grüße, Jürgen ❤");
814+
///
815+
/// assert!(ascii.is_ascii());
816+
/// assert!(!non_ascii.is_ascii());
817+
/// ```
818+
#[unstable(feature = "osstring_ascii", issue = "70516")]
819+
pub fn is_ascii(&self) -> bool {
820+
self.inner.is_ascii()
821+
}
822+
823+
/// Checks that two strings are an ASCII case-insensitive match.
824+
///
825+
/// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`,
826+
/// but without allocating and copying temporaries.
827+
///
828+
/// # Examples
829+
///
830+
/// ```
831+
/// #![feature(osstring_ascii)]
832+
/// use std::ffi::OsString;
833+
///
834+
/// assert!(OsString::from("Ferris").eq_ignore_ascii_case("FERRIS"));
835+
/// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS"));
836+
/// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS"));
837+
/// ```
838+
#[unstable(feature = "osstring_ascii", issue = "70516")]
839+
pub fn eq_ignore_ascii_case<S: ?Sized + AsRef<OsStr>>(&self, other: &S) -> bool {
840+
self.inner.eq_ignore_ascii_case(&other.as_ref().inner)
841+
}
701842
}
702843

703844
#[stable(feature = "box_from_os_str", since = "1.17.0")]

src/libstd/sys/windows/os_str.rs

+30
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,34 @@ impl Slice {
179179
let rc = self.inner.into_rc();
180180
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
181181
}
182+
183+
#[inline]
184+
pub fn make_ascii_lowercase(&mut self) {
185+
self.inner.make_ascii_lowercase()
186+
}
187+
188+
#[inline]
189+
pub fn make_ascii_uppercase(&mut self) {
190+
self.inner.make_ascii_uppercase()
191+
}
192+
193+
#[inline]
194+
pub fn to_ascii_lowercase(&self) -> Buf {
195+
Buf { inner: self.inner.to_ascii_lowercase() }
196+
}
197+
198+
#[inline]
199+
pub fn to_ascii_uppercase(&self) -> Buf {
200+
Buf { inner: self.inner.to_ascii_uppercase() }
201+
}
202+
203+
#[inline]
204+
pub fn is_ascii(&self) -> bool {
205+
self.inner.is_ascii()
206+
}
207+
208+
#[inline]
209+
pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
210+
self.inner.eq_ignore_ascii_case(&other.inner)
211+
}
182212
}

src/libstd/sys/windows/process.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::sys::mutex::Mutex;
2020
use crate::sys::pipe::{self, AnonPipe};
2121
use crate::sys::stdio;
2222
use crate::sys_common::process::CommandEnv;
23-
use crate::sys_common::{AsInner, FromInner, IntoInner};
23+
use crate::sys_common::AsInner;
2424

2525
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
2626

@@ -33,10 +33,9 @@ use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
3333
pub struct EnvKey(OsString);
3434

3535
impl From<OsString> for EnvKey {
36-
fn from(k: OsString) -> Self {
37-
let mut buf = k.into_inner().into_inner();
38-
buf.make_ascii_uppercase();
39-
EnvKey(FromInner::from_inner(FromInner::from_inner(buf)))
36+
fn from(mut k: OsString) -> Self {
37+
k.make_ascii_uppercase();
38+
EnvKey(k)
4039
}
4140
}
4241

src/libstd/sys_common/os_str_bytes.rs

+30
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,36 @@ impl Slice {
195195
let rc: Rc<[u8]> = Rc::from(&self.inner);
196196
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
197197
}
198+
199+
#[inline]
200+
pub fn make_ascii_lowercase(&mut self) {
201+
self.inner.make_ascii_lowercase()
202+
}
203+
204+
#[inline]
205+
pub fn make_ascii_uppercase(&mut self) {
206+
self.inner.make_ascii_uppercase()
207+
}
208+
209+
#[inline]
210+
pub fn to_ascii_lowercase(&self) -> Buf {
211+
Buf { inner: self.inner.to_ascii_lowercase() }
212+
}
213+
214+
#[inline]
215+
pub fn to_ascii_uppercase(&self) -> Buf {
216+
Buf { inner: self.inner.to_ascii_uppercase() }
217+
}
218+
219+
#[inline]
220+
pub fn is_ascii(&self) -> bool {
221+
self.inner.is_ascii()
222+
}
223+
224+
#[inline]
225+
pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
226+
self.inner.eq_ignore_ascii_case(&other.inner)
227+
}
198228
}
199229

200230
/// Platform-specific extensions to [`OsString`].

src/libstd/sys_common/wtf8.rs

+30-6
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,36 @@ impl Wtf8 {
637637
let rc: Rc<[u8]> = Rc::from(&self.bytes);
638638
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Wtf8) }
639639
}
640+
641+
#[inline]
642+
pub fn make_ascii_lowercase(&mut self) {
643+
self.bytes.make_ascii_lowercase()
644+
}
645+
646+
#[inline]
647+
pub fn make_ascii_uppercase(&mut self) {
648+
self.bytes.make_ascii_uppercase()
649+
}
650+
651+
#[inline]
652+
pub fn to_ascii_lowercase(&self) -> Wtf8Buf {
653+
Wtf8Buf { bytes: self.bytes.to_ascii_lowercase() }
654+
}
655+
656+
#[inline]
657+
pub fn to_ascii_uppercase(&self) -> Wtf8Buf {
658+
Wtf8Buf { bytes: self.bytes.to_ascii_uppercase() }
659+
}
660+
661+
#[inline]
662+
pub fn is_ascii(&self) -> bool {
663+
self.bytes.is_ascii()
664+
}
665+
666+
#[inline]
667+
pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
668+
self.bytes.eq_ignore_ascii_case(&other.bytes)
669+
}
640670
}
641671

642672
/// Returns a slice of the given string for the byte range [`begin`..`end`).
@@ -837,12 +867,6 @@ impl Hash for Wtf8 {
837867
}
838868
}
839869

840-
impl Wtf8 {
841-
pub fn make_ascii_uppercase(&mut self) {
842-
self.bytes.make_ascii_uppercase()
843-
}
844-
}
845-
846870
#[cfg(test)]
847871
mod tests {
848872
use super::*;

0 commit comments

Comments
 (0)