Skip to content

Commit

Permalink
no_stdsupport for the url crate (#831)
Browse files Browse the repository at this point in the history
  • Loading branch information
domenukk authored Oct 17, 2024
1 parent 7eccac9 commit ebd5cfb
Show file tree
Hide file tree
Showing 12 changed files with 209 additions and 49 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion data-url/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
3 changes: 3 additions & 0 deletions idna/src/uts46.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 7 additions & 5 deletions url/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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.
Expand Down
10 changes: 7 additions & 3 deletions url/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
116 changes: 91 additions & 25 deletions url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down Expand Up @@ -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",
Expand All @@ -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};
Expand Down Expand Up @@ -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`:
//
Expand Down Expand Up @@ -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")?;
Expand Down Expand Up @@ -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/")?;
Expand All @@ -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/")?;
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -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('/')
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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")]
Expand All @@ -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,
Expand All @@ -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(());
Expand Down Expand Up @@ -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(());
Expand Down Expand Up @@ -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>,
Expand All @@ -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 {
Expand Down
5 changes: 4 additions & 1 deletion url/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading

0 comments on commit ebd5cfb

Please sign in to comment.