Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 463b3bc

Browse files
committedDec 3, 2023
Add str-based os_str implementation for wasm
On `wasm` the only legal way to construct an OS string is from a UTF-8 string. Every other platform publicly guarantees (through some extension trait) either arbitrary bytes or (transcoded) UTF-16. Therefore `wasm` can base its OS strings on UTF-8 strings. The implementation is largely copied from the `unix` implementation, but without the validation and with slightly more liberal use of `#[inline]`. An immediate benefit is that conversion back to UTF-8 strings is free. But the motivation is that we want the `unix` implementation to express that it can be sliced at arbitrary points, and this would be inappropriate for `wasm` since it lacks an extension trait.
1 parent 7ceaf19 commit 463b3bc

File tree

3 files changed

+277
-3
lines changed

3 files changed

+277
-3
lines changed
 

‎library/std/src/sys/unsupported/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ pub mod locks;
1111
pub mod net;
1212
pub mod once;
1313
pub mod os;
14-
#[path = "../unix/os_str.rs"]
1514
pub mod os_str;
1615
#[path = "../unix/path.rs"]
1716
pub mod path;
+275
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,275 @@
1+
//! The underlying OsString/OsStr implementation on platforms where there isn't
2+
//! any particular OS encoding: just a `String`/`str`.
3+
4+
use crate::borrow::Cow;
5+
use crate::collections::TryReserveError;
6+
use crate::fmt;
7+
use crate::mem;
8+
use crate::rc::Rc;
9+
use crate::str;
10+
use crate::string::String;
11+
use crate::sync::Arc;
12+
use crate::sys_common::{AsInner, FromInner, IntoInner};
13+
14+
#[derive(Hash)]
15+
#[repr(transparent)]
16+
pub struct Buf {
17+
pub inner: String,
18+
}
19+
20+
#[repr(transparent)]
21+
pub struct Slice {
22+
pub inner: str,
23+
}
24+
25+
impl fmt::Debug for Slice {
26+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
fmt::Debug::fmt(&self.inner, formatter)
28+
}
29+
}
30+
31+
impl fmt::Display for Slice {
32+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
33+
fmt::Display::fmt(&self.inner, formatter)
34+
}
35+
}
36+
37+
impl fmt::Debug for Buf {
38+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
39+
fmt::Debug::fmt(self.as_slice(), formatter)
40+
}
41+
}
42+
43+
impl fmt::Display for Buf {
44+
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
45+
fmt::Display::fmt(self.as_slice(), formatter)
46+
}
47+
}
48+
49+
impl Clone for Buf {
50+
#[inline]
51+
fn clone(&self) -> Self {
52+
Buf { inner: self.inner.clone() }
53+
}
54+
55+
#[inline]
56+
fn clone_from(&mut self, source: &Self) {
57+
self.inner.clone_from(&source.inner)
58+
}
59+
}
60+
61+
impl IntoInner<String> for Buf {
62+
fn into_inner(self) -> String {
63+
self.inner
64+
}
65+
}
66+
67+
impl FromInner<String> for Buf {
68+
fn from_inner(inner: String) -> Self {
69+
Buf { inner }
70+
}
71+
}
72+
73+
impl AsInner<str> for Buf {
74+
#[inline]
75+
fn as_inner(&self) -> &str {
76+
&self.inner
77+
}
78+
}
79+
80+
impl Buf {
81+
#[inline]
82+
pub fn into_encoded_bytes(self) -> Vec<u8> {
83+
self.inner.into_bytes()
84+
}
85+
86+
#[inline]
87+
pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self {
88+
Self { inner: unsafe { String::from_utf8_unchecked(s) } }
89+
}
90+
91+
#[inline]
92+
pub fn from_string(s: String) -> Buf {
93+
Buf { inner: s }
94+
}
95+
96+
#[inline]
97+
pub fn with_capacity(capacity: usize) -> Buf {
98+
Buf { inner: String::with_capacity(capacity) }
99+
}
100+
101+
#[inline]
102+
pub fn clear(&mut self) {
103+
self.inner.clear()
104+
}
105+
106+
#[inline]
107+
pub fn capacity(&self) -> usize {
108+
self.inner.capacity()
109+
}
110+
111+
#[inline]
112+
pub fn reserve(&mut self, additional: usize) {
113+
self.inner.reserve(additional)
114+
}
115+
116+
#[inline]
117+
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
118+
self.inner.try_reserve(additional)
119+
}
120+
121+
#[inline]
122+
pub fn reserve_exact(&mut self, additional: usize) {
123+
self.inner.reserve_exact(additional)
124+
}
125+
126+
#[inline]
127+
pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
128+
self.inner.try_reserve_exact(additional)
129+
}
130+
131+
#[inline]
132+
pub fn shrink_to_fit(&mut self) {
133+
self.inner.shrink_to_fit()
134+
}
135+
136+
#[inline]
137+
pub fn shrink_to(&mut self, min_capacity: usize) {
138+
self.inner.shrink_to(min_capacity)
139+
}
140+
141+
#[inline]
142+
pub fn as_slice(&self) -> &Slice {
143+
// SAFETY: Slice just wraps str,
144+
// and &*self.inner is &str, therefore
145+
// transmuting &str to &Slice is safe.
146+
unsafe { mem::transmute(&*self.inner) }
147+
}
148+
149+
#[inline]
150+
pub fn as_mut_slice(&mut self) -> &mut Slice {
151+
// SAFETY: Slice just wraps str,
152+
// and &mut *self.inner is &mut str, therefore
153+
// transmuting &mut str to &mut Slice is safe.
154+
unsafe { mem::transmute(&mut *self.inner) }
155+
}
156+
157+
#[inline]
158+
pub fn into_string(self) -> Result<String, Buf> {
159+
Ok(self.inner)
160+
}
161+
162+
#[inline]
163+
pub fn push_slice(&mut self, s: &Slice) {
164+
self.inner.push_str(&s.inner)
165+
}
166+
167+
#[inline]
168+
pub fn into_box(self) -> Box<Slice> {
169+
unsafe { mem::transmute(self.inner.into_boxed_str()) }
170+
}
171+
172+
#[inline]
173+
pub fn from_box(boxed: Box<Slice>) -> Buf {
174+
let inner: Box<str> = unsafe { mem::transmute(boxed) };
175+
Buf { inner: inner.into_string() }
176+
}
177+
178+
#[inline]
179+
pub fn into_arc(&self) -> Arc<Slice> {
180+
self.as_slice().into_arc()
181+
}
182+
183+
#[inline]
184+
pub fn into_rc(&self) -> Rc<Slice> {
185+
self.as_slice().into_rc()
186+
}
187+
}
188+
189+
impl Slice {
190+
#[inline]
191+
pub fn as_encoded_bytes(&self) -> &[u8] {
192+
self.inner.as_bytes()
193+
}
194+
195+
#[inline]
196+
pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice {
197+
unsafe { mem::transmute(s) }
198+
}
199+
200+
#[inline]
201+
pub fn from_str(s: &str) -> &Slice {
202+
unsafe { mem::transmute(s) }
203+
}
204+
205+
#[inline]
206+
pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> {
207+
Ok(&self.inner)
208+
}
209+
210+
#[inline]
211+
pub fn to_string_lossy(&self) -> Cow<'_, str> {
212+
Cow::Borrowed(&self.inner)
213+
}
214+
215+
pub fn to_owned(&self) -> Buf {
216+
Buf { inner: self.inner.to_owned() }
217+
}
218+
219+
pub fn clone_into(&self, buf: &mut Buf) {
220+
self.inner.clone_into(&mut buf.inner)
221+
}
222+
223+
#[inline]
224+
pub fn into_box(&self) -> Box<Slice> {
225+
let boxed: Box<str> = self.inner.into();
226+
unsafe { mem::transmute(boxed) }
227+
}
228+
229+
pub fn empty_box() -> Box<Slice> {
230+
let boxed: Box<str> = Default::default();
231+
unsafe { mem::transmute(boxed) }
232+
}
233+
234+
#[inline]
235+
pub fn into_arc(&self) -> Arc<Slice> {
236+
let arc: Arc<str> = Arc::from(&self.inner);
237+
unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
238+
}
239+
240+
#[inline]
241+
pub fn into_rc(&self) -> Rc<Slice> {
242+
let rc: Rc<str> = Rc::from(&self.inner);
243+
unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
244+
}
245+
246+
#[inline]
247+
pub fn make_ascii_lowercase(&mut self) {
248+
self.inner.make_ascii_lowercase()
249+
}
250+
251+
#[inline]
252+
pub fn make_ascii_uppercase(&mut self) {
253+
self.inner.make_ascii_uppercase()
254+
}
255+
256+
#[inline]
257+
pub fn to_ascii_lowercase(&self) -> Buf {
258+
Buf { inner: self.inner.to_ascii_lowercase() }
259+
}
260+
261+
#[inline]
262+
pub fn to_ascii_uppercase(&self) -> Buf {
263+
Buf { inner: self.inner.to_ascii_uppercase() }
264+
}
265+
266+
#[inline]
267+
pub fn is_ascii(&self) -> bool {
268+
self.inner.is_ascii()
269+
}
270+
271+
#[inline]
272+
pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
273+
self.inner.eq_ignore_ascii_case(&other.inner)
274+
}
275+
}

‎library/std/src/sys/wasm/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
//! wide/production use yet, it's still all in the experimental category. This
99
//! will likely change over time.
1010
//!
11-
//! Currently all functions here are basically stubs that immediately return
11+
//! Currently most functions here are basically stubs that immediately return
1212
//! errors. The hope is that with a portability lint we can turn actually just
1313
//! remove all this and just omit parts of the standard library if we're
1414
//! compiling for wasm. That way it's a compile time error for something that's
@@ -30,7 +30,7 @@ pub mod io;
3030
pub mod net;
3131
#[path = "../unsupported/os.rs"]
3232
pub mod os;
33-
#[path = "../unix/os_str.rs"]
33+
#[path = "../unsupported/os_str.rs"]
3434
pub mod os_str;
3535
#[path = "../unix/path.rs"]
3636
pub mod path;

0 commit comments

Comments
 (0)
Please sign in to comment.