diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 91ccf6fdbbe..9f448f9fe4e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -257,6 +257,13 @@ jobs: - name: Check compilation for freeBSD run: cargo check --target x86_64-unknown-freebsd ${{ env.CARGO_ARGS_NO_SSL }} + - uses: dtolnay/rust-toolchain@stable + with: + target: wasm32-wasip2 + + - name: Check compilation for wasip2 + run: cargo check --target wasm32-wasip2 ${{ env.CARGO_ARGS_NO_SSL }} + # - name: Prepare repository for redox compilation # run: bash scripts/redox/uncomment-cargo.sh # - name: Check compilation for Redox diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs index 0181562d043..d52ed063867 100644 --- a/crates/common/src/lib.rs +++ b/crates/common/src/lib.rs @@ -1,7 +1,5 @@ //! A crate to hold types and functions common to all rustpython components. -#![cfg_attr(all(target_os = "wasi", target_env = "p2"), feature(wasip2))] - extern crate alloc; #[macro_use] diff --git a/crates/common/src/os.rs b/crates/common/src/os.rs index a0935239742..ef8547289a2 100644 --- a/crates/common/src/os.rs +++ b/crates/common/src/os.rs @@ -94,9 +94,61 @@ pub fn bytes_as_os_str(b: &[u8]) -> Result<&std::ffi::OsStr, Utf8Error> { #[cfg(unix)] pub use std::os::unix::ffi; -#[cfg(target_os = "wasi")] + +// WASIp1 uses stable std::os::wasi::ffi +#[cfg(all(target_os = "wasi", not(target_env = "p2")))] pub use std::os::wasi::ffi; +// WASIp2: std::os::wasip2::ffi is unstable, so we provide a stable implementation +// leveraging WASI's UTF-8 string guarantee +#[cfg(all(target_os = "wasi", target_env = "p2"))] +pub mod ffi { + use std::ffi::{OsStr, OsString}; + + pub trait OsStrExt: sealed::Sealed { + fn as_bytes(&self) -> &[u8]; + fn from_bytes(slice: &[u8]) -> &Self; + } + + impl OsStrExt for OsStr { + fn as_bytes(&self) -> &[u8] { + // WASI strings are guaranteed to be UTF-8 + self.to_str().expect("wasip2 strings are UTF-8").as_bytes() + } + + fn from_bytes(slice: &[u8]) -> &OsStr { + // WASI strings are guaranteed to be UTF-8 + OsStr::new(std::str::from_utf8(slice).expect("wasip2 strings are UTF-8")) + } + } + + pub trait OsStringExt: sealed::Sealed { + fn from_vec(vec: Vec) -> Self; + fn into_vec(self) -> Vec; + } + + impl OsStringExt for OsString { + fn from_vec(vec: Vec) -> OsString { + // WASI strings are guaranteed to be UTF-8 + OsString::from(String::from_utf8(vec).expect("wasip2 strings are UTF-8")) + } + + fn into_vec(self) -> Vec { + // WASI strings are guaranteed to be UTF-8 + self.to_str() + .expect("wasip2 strings are UTF-8") + .as_bytes() + .to_vec() + } + } + + mod sealed { + pub trait Sealed {} + impl Sealed for std::ffi::OsStr {} + impl Sealed for std::ffi::OsString {} + } +} + #[cfg(windows)] pub fn errno_to_winerror(errno: i32) -> i32 { use libc::*; diff --git a/crates/stdlib/src/lib.rs b/crates/stdlib/src/lib.rs index ae69f6f8673..48192c26479 100644 --- a/crates/stdlib/src/lib.rs +++ b/crates/stdlib/src/lib.rs @@ -2,7 +2,6 @@ // how `mod` works, but we want this sometimes for pymodule declarations #![allow(clippy::module_inception)] -#![cfg_attr(all(target_os = "wasi", target_env = "p2"), feature(wasip2))] #[macro_use] extern crate rustpython_derive; diff --git a/crates/stdlib/src/select.rs b/crates/stdlib/src/select.rs index 09a85cf1c00..bc8aded5478 100644 --- a/crates/stdlib/src/select.rs +++ b/crates/stdlib/src/select.rs @@ -61,7 +61,7 @@ mod platform { #[cfg(target_os = "wasi")] mod platform { pub use libc::{FD_SETSIZE, timeval}; - pub use std::os::wasi::io::RawFd; + pub use std::os::fd::RawFd; pub fn check_err(x: i32) -> bool { x < 0 diff --git a/src/lib.rs b/src/lib.rs index c489782ded7..b73725a0fe2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,7 +44,6 @@ //! //! See [`rustpython_derive`](../rustpython_derive/index.html) crate for documentation on macros used in the example above. -#![cfg_attr(all(target_os = "wasi", target_env = "p2"), feature(wasip2))] #![allow(clippy::needless_doctest_main)] #[macro_use] diff --git a/src/settings.rs b/src/settings.rs index 71a9c5a3f06..1847e22c2d4 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -407,8 +407,10 @@ pub(crate) use env::split_paths; pub(crate) fn split_paths + ?Sized>( s: &T, ) -> impl Iterator + '_ { - use std::os::wasi::ffi::OsStrExt; - let s = s.as_ref().as_bytes(); - s.split(|b| *b == b':') - .map(|x| std::ffi::OsStr::from_bytes(x).to_owned().into()) + let s = s.as_ref().as_encoded_bytes(); + s.split(|b| *b == b':').map(|x| { + unsafe { std::ffi::OsStr::from_encoded_bytes_unchecked(x) } + .to_owned() + .into() + }) }