Browse Source

`no_std`support for the `url` crate (#831)

Dominik Maier 1 year ago
parent
commit
ebd5cfbf6f

+ 14 - 0
.github/workflows/main.yml

@@ -35,6 +35,13 @@ jobs:
       - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{ matrix.rust }}
+      # Add toolchain for no_std tests
+      - run: rustup toolchain install nightly
+      - name: Add `aarch64-unknown-none` toolchain for `no_std` tests
+        if: |
+          matrix.os == 'ubuntu-latest' &&
+          matrix.rust == 'nightly'
+        run: rustup target add aarch64-unknown-none && rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
       - run: cargo build --all-targets
         # Run tests
       - name: Run tests
@@ -52,6 +59,13 @@ jobs:
         continue-on-error: true # Fails on GH actions, but not locally.
       - name: Test `no_std` support
         run: cargo test --no-default-features --features=alloc
+      - name: Build `url` crate for `aarch64-unknown-none` with `no_std`
+        if: |
+          matrix.os == 'ubuntu-latest' &&
+          matrix.rust == 'nightly'
+        run: >
+          cd url
+          && cargo check --target aarch64-unknown-none -v --no-default-features
 
   WASM:
     runs-on: ubuntu-latest

+ 1 - 1
data-url/Cargo.toml

@@ -19,7 +19,7 @@ alloc = []
 tester = "0.9"
 # We pin this transitive dev dep so that MSRV CI can continue to run.
 unicode-width = "=0.1.12"
-serde = {version = "1.0", features = ["derive"]}
+serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
 serde_json = "1.0"
 
 [lib]

+ 3 - 0
idna/src/uts46.rs

@@ -714,6 +714,9 @@ impl From<Errors> for Result<(), Errors> {
 #[cfg(feature = "std")]
 impl std::error::Error for Errors {}
 
+#[cfg(not(feature = "std"))]
+impl core::error::Error for Errors {}
+
 impl fmt::Display for Errors {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Debug::fmt(self, f)

+ 7 - 5
url/Cargo.toml

@@ -10,7 +10,7 @@ documentation = "https://docs.rs/url"
 repository = "https://github.com/servo/rust-url"
 readme = "../README.md"
 keywords = ["url", "parser"]
-categories = ["parser-implementations", "web-programming", "encoding"]
+categories = ["parser-implementations", "web-programming", "encoding", "no_std"]
 license = "MIT OR Apache-2.0"
 include = ["src/**/*", "LICENSE-*", "README.md", "tests/**"]
 edition = "2018"
@@ -25,13 +25,15 @@ bencher = "0.1"
 wasm-bindgen-test = "0.3"
 
 [dependencies]
-form_urlencoded = { version = "1.2.1", path = "../form_urlencoded" }
-idna = { version = "0.5.0", path = "../idna" }
-percent-encoding = { version = "2.3.1", path = "../percent_encoding" }
+form_urlencoded = { version = "1.2.1", path = "../form_urlencoded", default-features = false, features = ["alloc"] }
+idna = { version = "0.5.0", path = "../idna", default-features = false, features = ["alloc"] }
+percent-encoding = { version = "2.3.1", path = "../percent_encoding", default-features = false, features = ["alloc"] }
 serde = { version = "1.0", optional = true, features = ["derive"] }
 
 [features]
-default = []
+default = ["std"]
+std = ["idna/std", "percent-encoding/std", "form_urlencoded/std"]
+
 # Enable to use the #[debugger_visualizer] attribute. This feature requires Rust >= 1.71.
 debugger_visualizer = []
 # Expose internal offsets of the URL.

+ 7 - 3
url/src/host.rs

@@ -6,9 +6,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::cmp;
-use std::fmt::{self, Formatter};
-use std::net::{Ipv4Addr, Ipv6Addr};
+use crate::net::{Ipv4Addr, Ipv6Addr};
+use alloc::borrow::ToOwned;
+use alloc::string::String;
+use alloc::string::ToString;
+use alloc::vec::Vec;
+use core::cmp;
+use core::fmt::{self, Formatter};
 
 use percent_encoding::{percent_decode, utf8_percent_encode, CONTROLS};
 #[cfg(feature = "serde")]

+ 91 - 25
url/src/lib.rs

@@ -73,6 +73,14 @@ assert!(data_url.fragment() == Some(""));
 # run().unwrap();
 ```
 
+## Default Features
+
+Versions `<= 2.5.2` of the crate have no default features. Versions `> 2.5.2` have the default feature 'std'.
+If you are upgrading across this boundary and you have specified `default-features = false`, then
+you will need to add the 'std' feature or the 'alloc' feature to your dependency.
+The 'std' feature has the same behavior as the previous versions. The 'alloc' feature
+provides no_std support.
+
 ## Serde
 
 Enable the `serde` feature to include `Deserialize` and `Serialize` implementations for `url::Url`.
@@ -134,6 +142,7 @@ url = { version = "2", features = ["debugger_visualizer"] }
 
 */
 
+#![no_std]
 #![doc(html_root_url = "https://docs.rs/url/2.5.2")]
 #![cfg_attr(
     feature = "debugger_visualizer",
@@ -145,29 +154,48 @@ url = { version = "2", features = ["debugger_visualizer"] }
 
 pub use form_urlencoded;
 
+// For forwards compatibility
+#[cfg(feature = "std")]
+extern crate std;
+
+#[macro_use]
+extern crate alloc;
+
 #[cfg(feature = "serde")]
 extern crate serde;
 
 use crate::host::HostInternal;
-use crate::parser::{
-    to_u32, Context, Parser, SchemeType, PATH_SEGMENT, SPECIAL_PATH_SEGMENT, USERINFO,
-};
-use percent_encoding::{percent_decode, percent_encode, utf8_percent_encode};
-use std::borrow::Borrow;
-use std::cmp;
-use std::fmt::{self, Write};
-use std::hash;
+
+use crate::net::IpAddr;
+#[cfg(feature = "std")]
 #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
-use std::io;
-use std::mem;
-use std::net::IpAddr;
+use crate::net::{SocketAddr, ToSocketAddrs};
+use crate::parser::{to_u32, Context, Parser, SchemeType, USERINFO};
+use alloc::borrow::ToOwned;
+use alloc::str;
+use alloc::string::{String, ToString};
+use core::borrow::Borrow;
+use core::convert::TryFrom;
+use core::fmt::Write;
+use core::ops::{Range, RangeFrom, RangeTo};
+use core::{cmp, fmt, hash, mem};
+use percent_encoding::utf8_percent_encode;
+#[cfg(feature = "std")]
 #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
-use std::net::{SocketAddr, ToSocketAddrs};
-use std::ops::{Range, RangeFrom, RangeTo};
+use std::io;
+#[cfg(feature = "std")]
 use std::path::{Path, PathBuf};
-use std::str;
 
-use std::convert::TryFrom;
+/// `std` version of `net`
+#[cfg(feature = "std")]
+pub(crate) mod net {
+    pub use std::net::*;
+}
+/// `no_std` nightly version of `net`
+#[cfg(not(feature = "std"))]
+pub(crate) mod net {
+    pub use core::net::*;
+}
 
 pub use crate::host::Host;
 pub use crate::origin::{OpaqueOrigin, Origin};
@@ -1279,11 +1307,12 @@ impl Url {
     ///     })
     /// }
     /// ```
+    #[cfg(feature = "std")]
     #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
     pub fn socket_addrs(
         &self,
         default_port_number: impl Fn() -> Option<u16>,
-    ) -> io::Result<Vec<SocketAddr>> {
+    ) -> io::Result<alloc::vec::Vec<SocketAddr>> {
         // Note: trying to avoid the Vec allocation by returning `impl AsRef<[SocketAddr]>`
         // causes borrowck issues because the return value borrows `default_port_number`:
         //
@@ -1353,7 +1382,11 @@ impl Url {
     ///
     /// ```
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let url = Url::parse("https://example.com/foo/bar")?;
@@ -1767,7 +1800,11 @@ impl Url {
     ///
     /// ```
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let mut url = Url::parse("ssh://example.net:2048/")?;
@@ -1786,7 +1823,11 @@ impl Url {
     ///
     /// ```rust
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let mut url = Url::parse("https://example.org/")?;
@@ -2469,9 +2510,14 @@ impl Url {
     /// # run().unwrap();
     /// # }
     /// ```
-    #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
+    ///
+    /// This method is only available if the `std` Cargo feature is enabled.
+    #[cfg(all(
+        feature = "std",
+        any(unix, windows, target_os = "redox", target_os = "wasi")
+    ))]
     #[allow(clippy::result_unit_err)]
-    pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
+    pub fn from_file_path<P: AsRef<std::path::Path>>(path: P) -> Result<Url, ()> {
         let mut serialization = "file://".to_owned();
         let host_start = serialization.len() as u32;
         let (host_end, host) = path_to_file_url_segments(path.as_ref(), &mut serialization)?;
@@ -2506,9 +2552,14 @@ impl Url {
     ///
     /// Note that `std::path` does not consider trailing slashes significant
     /// and usually does not include them (e.g. in `Path::parent()`).
-    #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
+    ///
+    /// This method is only available if the `std` Cargo feature is enabled.
+    #[cfg(all(
+        feature = "std",
+        any(unix, windows, target_os = "redox", target_os = "wasi")
+    ))]
     #[allow(clippy::result_unit_err)]
-    pub fn from_directory_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
+    pub fn from_directory_path<P: AsRef<std::path::Path>>(path: P) -> Result<Url, ()> {
         let mut url = Url::from_file_path(path)?;
         if !url.serialization.ends_with('/') {
             url.serialization.push('/')
@@ -2622,8 +2673,13 @@ impl Url {
     /// or if `Path::new_opt()` returns `None`.
     /// (That is, if the percent-decoded path contains a NUL byte or,
     /// for a Windows path, is not UTF-8.)
+    ///
+    /// This method is only available if the `std` Cargo feature is enabled.
     #[inline]
-    #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
+    #[cfg(all(
+        feature = "std",
+        any(unix, windows, target_os = "redox", target_os = "wasi")
+    ))]
     #[allow(clippy::result_unit_err)]
     pub fn to_file_path(&self) -> Result<PathBuf, ()> {
         if let Some(segments) = self.path_segments() {
@@ -2827,11 +2883,13 @@ impl<'de> serde::Deserialize<'de> for Url {
     }
 }
 
-#[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
+#[cfg(all(feature = "std", any(unix, target_os = "redox", target_os = "wasi")))]
 fn path_to_file_url_segments(
     path: &Path,
     serialization: &mut String,
 ) -> Result<(u32, HostInternal), ()> {
+    use parser::SPECIAL_PATH_SEGMENT;
+    use percent_encoding::percent_encode;
     #[cfg(any(unix, target_os = "redox"))]
     use std::os::unix::prelude::OsStrExt;
     #[cfg(target_os = "wasi")]
@@ -2857,7 +2915,7 @@ fn path_to_file_url_segments(
     Ok((host_end, HostInternal::None))
 }
 
-#[cfg(windows)]
+#[cfg(all(feature = "std", windows))]
 fn path_to_file_url_segments(
     path: &Path,
     serialization: &mut String,
@@ -2866,11 +2924,14 @@ fn path_to_file_url_segments(
 }
 
 // Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
+#[cfg(feature = "std")]
 #[cfg_attr(not(windows), allow(dead_code))]
 fn path_to_file_url_segments_windows(
     path: &Path,
     serialization: &mut String,
 ) -> Result<(u32, HostInternal), ()> {
+    use crate::parser::PATH_SEGMENT;
+    use percent_encoding::percent_encode;
     use std::path::{Component, Prefix};
     if !path.is_absolute() {
         return Err(());
@@ -2929,16 +2990,19 @@ fn path_to_file_url_segments_windows(
     Ok((host_end, host_internal))
 }
 
-#[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
+#[cfg(all(feature = "std", any(unix, target_os = "redox", target_os = "wasi")))]
 fn file_url_segments_to_pathbuf(
     host: Option<&str>,
     segments: str::Split<'_, char>,
 ) -> Result<PathBuf, ()> {
+    use alloc::vec::Vec;
+    use percent_encoding::percent_decode;
     use std::ffi::OsStr;
     #[cfg(any(unix, target_os = "redox"))]
     use std::os::unix::prelude::OsStrExt;
     #[cfg(target_os = "wasi")]
     use std::os::wasi::prelude::OsStrExt;
+    use std::path::PathBuf;
 
     if host.is_some() {
         return Err(());
@@ -2974,7 +3038,7 @@ fn file_url_segments_to_pathbuf(
     Ok(path)
 }
 
-#[cfg(windows)]
+#[cfg(all(feature = "std", windows))]
 fn file_url_segments_to_pathbuf(
     host: Option<&str>,
     segments: str::Split<char>,
@@ -2983,11 +3047,13 @@ fn file_url_segments_to_pathbuf(
 }
 
 // Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
+#[cfg(feature = "std")]
 #[cfg_attr(not(windows), allow(dead_code))]
 fn file_url_segments_to_pathbuf_windows(
     host: Option<&str>,
     mut segments: str::Split<'_, char>,
 ) -> Result<PathBuf, ()> {
+    use percent_encoding::percent_decode;
     let mut string = if let Some(host) = host {
         r"\\".to_owned() + host
     } else {

+ 4 - 1
url/src/origin.rs

@@ -9,7 +9,10 @@
 use crate::host::Host;
 use crate::parser::default_port;
 use crate::Url;
-use std::sync::atomic::{AtomicUsize, Ordering};
+use alloc::borrow::ToOwned;
+use alloc::format;
+use alloc::string::String;
+use core::sync::atomic::{AtomicUsize, Ordering};
 
 pub fn url_origin(url: &Url) -> Origin {
     let scheme = url.scheme();

+ 9 - 4
url/src/parser.rs

@@ -6,9 +6,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::error::Error;
-use std::fmt::{self, Formatter, Write};
-use std::str;
+use alloc::string::String;
+use alloc::string::ToString;
+use core::fmt::{self, Formatter, Write};
+use core::str;
 
 use crate::host::{Host, HostInternal};
 use crate::Url;
@@ -72,7 +73,11 @@ macro_rules! simple_enum_error {
     }
 }
 
-impl Error for ParseError {}
+#[cfg(feature = "std")]
+impl std::error::Error for ParseError {}
+
+#[cfg(not(feature = "std"))]
+impl core::error::Error for ParseError {}
 
 simple_enum_error! {
     EmptyHost => "empty host",

+ 22 - 1
url/src/path_segments.rs

@@ -8,7 +8,8 @@
 
 use crate::parser::{self, to_u32, SchemeType};
 use crate::Url;
-use std::str;
+use alloc::string::String;
+use core::str;
 
 /// Exposes methods to manipulate the path of an URL that is not cannot-be-base.
 ///
@@ -19,7 +20,11 @@ use std::str;
 ///
 /// ```rust
 /// use url::Url;
+///
+/// # #[cfg(feature = "std")]
 /// # use std::error::Error;
+/// # #[cfg(not(feature = "std"))]
+/// # use core::error::Error;
 ///
 /// # fn run() -> Result<(), Box<dyn Error>> {
 /// let mut url = Url::parse("mailto:me@example.com")?;
@@ -78,7 +83,11 @@ impl<'a> PathSegmentsMut<'a> {
     ///
     /// ```rust
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let mut url = Url::parse("https://github.com/servo/rust-url/")?;
@@ -106,7 +115,11 @@ impl<'a> PathSegmentsMut<'a> {
     ///
     /// ```rust
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let mut url = Url::parse("https://github.com/servo/rust-url/")?;
@@ -181,7 +194,11 @@ impl<'a> PathSegmentsMut<'a> {
     ///
     /// ```rust
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let mut url = Url::parse("https://github.com/")?;
@@ -201,7 +218,11 @@ impl<'a> PathSegmentsMut<'a> {
     ///
     /// ```rust
     /// use url::Url;
+    ///
+    /// # #[cfg(feature = "std")]
     /// # use std::error::Error;
+    /// # #[cfg(not(feature = "std"))]
+    /// # use core::error::Error;
     ///
     /// # fn run() -> Result<(), Box<dyn Error>> {
     /// let mut url = Url::parse("https://github.com/servo")?;

+ 2 - 0
url/src/quirks.rs

@@ -13,6 +13,8 @@
 
 use crate::parser::{default_port, Context, Input, Parser, SchemeType};
 use crate::{Host, ParseError, Position, Url};
+use alloc::string::String;
+use alloc::string::ToString;
 
 /// Internal components / offsets of a URL.
 ///

+ 2 - 1
url/src/slicing.rs

@@ -6,8 +6,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use core::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};
+
 use crate::Url;
-use std::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};
 
 impl Index<RangeFull> for Url {
     type Output = str;

+ 47 - 8
url/tests/unit.rs

@@ -7,13 +7,39 @@
 // except according to those terms.
 
 //! Unit tests
+#![no_std]
 
-use std::borrow::Cow;
-use std::cell::{Cell, RefCell};
-use std::net::{Ipv4Addr, Ipv6Addr};
+#[cfg(feature = "std")]
+extern crate std;
+
+#[macro_use]
+extern crate alloc;
+
+use alloc::borrow::Cow;
+use alloc::borrow::ToOwned;
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+use core::cell::{Cell, RefCell};
+#[cfg(feature = "std")]
+use std::dbg;
+use url::{form_urlencoded, Host, Origin, Url};
+
+/// `std` version of `net`
+#[cfg(feature = "std")]
+pub(crate) mod net {
+    pub use std::net::*;
+}
+/// `no_std` nightly version of `net`
+#[cfg(not(feature = "std"))]
+pub(crate) mod net {
+    pub use core::net::*;
+}
+
+use crate::net::{Ipv4Addr, Ipv6Addr};
+
+#[cfg(feature = "std")]
 #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 use std::path::{Path, PathBuf};
-use url::{form_urlencoded, Host, Origin, Url};
 
 // https://rustwasm.github.io/wasm-bindgen/wasm-bindgen-test/usage.html
 #[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
@@ -23,7 +49,7 @@ wasm_bindgen_test_configure!(run_in_browser);
 
 #[test]
 fn size() {
-    use std::mem::size_of;
+    use core::mem::size_of;
     assert_eq!(size_of::<Url>(), size_of::<Option<Url>>());
 }
 
@@ -124,6 +150,7 @@ fn test_set_empty_query() {
     assert_eq!(base.as_str(), "moz://example.com/path");
 }
 
+#[cfg(feature = "std")]
 #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 macro_rules! assert_from_file_path {
     ($path: expr) => {
@@ -138,6 +165,7 @@ macro_rules! assert_from_file_path {
 }
 
 #[test]
+#[cfg(feature = "std")]
 #[cfg(any(unix, windows))]
 fn new_file_paths() {
     if cfg!(unix) {
@@ -160,7 +188,7 @@ fn new_file_paths() {
 }
 
 #[test]
-#[cfg(unix)]
+#[cfg(all(feature = "std", unix))]
 fn new_path_bad_utf8() {
     use std::ffi::OsStr;
     use std::os::unix::prelude::*;
@@ -171,7 +199,7 @@ fn new_path_bad_utf8() {
 }
 
 #[test]
-#[cfg(windows)]
+#[cfg(all(feature = "std", windows))]
 fn new_path_windows_fun() {
     assert_from_file_path!(r"C:\foo\bar", "/C:/foo/bar");
     assert_from_file_path!("C:\\foo\\ba\0r", "/C:/foo/ba%00r");
@@ -192,6 +220,10 @@ fn new_path_windows_fun() {
 }
 
 #[test]
+#[cfg(all(
+    feature = "std",
+    any(unix, windows, target_os = "redox", target_os = "wasi")
+))]
 #[cfg(any(unix, windows))]
 fn new_directory_paths() {
     if cfg!(unix) {
@@ -258,6 +290,7 @@ fn issue_124() {
 }
 
 #[test]
+#[cfg(feature = "std")]
 fn test_equality() {
     use std::collections::hash_map::DefaultHasher;
     use std::hash::{Hash, Hasher};
@@ -448,6 +481,7 @@ fn issue_61() {
 }
 
 #[test]
+#[cfg(feature = "std")]
 #[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
 #[cfg(not(windows))]
 /// https://github.com/servo/rust-url/issues/197
@@ -539,6 +573,7 @@ fn test_leading_dots() {
 }
 
 #[test]
+#[cfg(feature = "std")]
 /// https://github.com/servo/rust-url/issues/302
 fn test_origin_hash() {
     use std::collections::hash_map::DefaultHasher;
@@ -633,6 +668,7 @@ fn test_origin_unicode_serialization() {
 }
 
 #[test]
+#[cfg(feature = "std")]
 #[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
 fn test_socket_addrs() {
     use std::net::ToSocketAddrs;
@@ -815,6 +851,7 @@ fn test_expose_internals() {
 }
 
 #[test]
+#[cfg(feature = "std")]
 #[cfg(windows)]
 fn test_windows_unc_path() {
     let url = Url::from_file_path(Path::new(r"\\host\share\path\file.txt")).unwrap();
@@ -923,8 +960,8 @@ fn test_options_reuse() {
 }
 
 /// https://github.com/servo/rust-url/issues/505
-#[cfg(windows)]
 #[test]
+#[cfg(all(feature = "std", windows))]
 fn test_url_from_file_path() {
     use std::path::PathBuf;
     use url::Url;
@@ -936,6 +973,7 @@ fn test_url_from_file_path() {
 }
 
 /// https://github.com/servo/rust-url/issues/505
+#[cfg(feature = "std")]
 #[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
 #[cfg(not(windows))]
 #[test]
@@ -1309,6 +1347,7 @@ fn test_file_with_drive_and_path() {
     assert_eq!(url2.to_string(), "file:///p:/a");
 }
 
+#[cfg(feature = "std")]
 #[test]
 fn issue_864() {
     let mut url = url::Url::parse("file://").unwrap();