Skip to content

Commit ebd5cfb

Browse files
authored
no_stdsupport for the url crate (#831)
1 parent 7eccac9 commit ebd5cfb

File tree

12 files changed

+209
-49
lines changed

12 files changed

+209
-49
lines changed

.github/workflows/main.yml

+14
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ jobs:
3535
- uses: dtolnay/rust-toolchain@master
3636
with:
3737
toolchain: ${{ matrix.rust }}
38+
# Add toolchain for no_std tests
39+
- run: rustup toolchain install nightly
40+
- name: Add `aarch64-unknown-none` toolchain for `no_std` tests
41+
if: |
42+
matrix.os == 'ubuntu-latest' &&
43+
matrix.rust == 'nightly'
44+
run: rustup target add aarch64-unknown-none && rustup component add rust-src --toolchain nightly-x86_64-unknown-linux-gnu
3845
- run: cargo build --all-targets
3946
# Run tests
4047
- name: Run tests
@@ -52,6 +59,13 @@ jobs:
5259
continue-on-error: true # Fails on GH actions, but not locally.
5360
- name: Test `no_std` support
5461
run: cargo test --no-default-features --features=alloc
62+
- name: Build `url` crate for `aarch64-unknown-none` with `no_std`
63+
if: |
64+
matrix.os == 'ubuntu-latest' &&
65+
matrix.rust == 'nightly'
66+
run: >
67+
cd url
68+
&& cargo check --target aarch64-unknown-none -v --no-default-features
5569
5670
WASM:
5771
runs-on: ubuntu-latest

data-url/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ alloc = []
1919
tester = "0.9"
2020
# We pin this transitive dev dep so that MSRV CI can continue to run.
2121
unicode-width = "=0.1.12"
22-
serde = {version = "1.0", features = ["derive"]}
22+
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
2323
serde_json = "1.0"
2424

2525
[lib]

idna/src/uts46.rs

+3
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,9 @@ impl From<Errors> for Result<(), Errors> {
714714
#[cfg(feature = "std")]
715715
impl std::error::Error for Errors {}
716716

717+
#[cfg(not(feature = "std"))]
718+
impl core::error::Error for Errors {}
719+
717720
impl fmt::Display for Errors {
718721
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719722
fmt::Debug::fmt(self, f)

url/Cargo.toml

+7-5
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ documentation = "https://docs.rs/url"
1010
repository = "https://github.com/servo/rust-url"
1111
readme = "../README.md"
1212
keywords = ["url", "parser"]
13-
categories = ["parser-implementations", "web-programming", "encoding"]
13+
categories = ["parser-implementations", "web-programming", "encoding", "no_std"]
1414
license = "MIT OR Apache-2.0"
1515
include = ["src/**/*", "LICENSE-*", "README.md", "tests/**"]
1616
edition = "2018"
@@ -25,13 +25,15 @@ bencher = "0.1"
2525
wasm-bindgen-test = "0.3"
2626

2727
[dependencies]
28-
form_urlencoded = { version = "1.2.1", path = "../form_urlencoded" }
29-
idna = { version = "0.5.0", path = "../idna" }
30-
percent-encoding = { version = "2.3.1", path = "../percent_encoding" }
28+
form_urlencoded = { version = "1.2.1", path = "../form_urlencoded", default-features = false, features = ["alloc"] }
29+
idna = { version = "0.5.0", path = "../idna", default-features = false, features = ["alloc"] }
30+
percent-encoding = { version = "2.3.1", path = "../percent_encoding", default-features = false, features = ["alloc"] }
3131
serde = { version = "1.0", optional = true, features = ["derive"] }
3232

3333
[features]
34-
default = []
34+
default = ["std"]
35+
std = ["idna/std", "percent-encoding/std", "form_urlencoded/std"]
36+
3537
# Enable to use the #[debugger_visualizer] attribute. This feature requires Rust >= 1.71.
3638
debugger_visualizer = []
3739
# Expose internal offsets of the URL.

url/src/host.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9-
use std::cmp;
10-
use std::fmt::{self, Formatter};
11-
use std::net::{Ipv4Addr, Ipv6Addr};
9+
use crate::net::{Ipv4Addr, Ipv6Addr};
10+
use alloc::borrow::ToOwned;
11+
use alloc::string::String;
12+
use alloc::string::ToString;
13+
use alloc::vec::Vec;
14+
use core::cmp;
15+
use core::fmt::{self, Formatter};
1216

1317
use percent_encoding::{percent_decode, utf8_percent_encode, CONTROLS};
1418
#[cfg(feature = "serde")]

url/src/lib.rs

+91-25
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ assert!(data_url.fragment() == Some(""));
7373
# run().unwrap();
7474
```
7575
76+
## Default Features
77+
78+
Versions `<= 2.5.2` of the crate have no default features. Versions `> 2.5.2` have the default feature 'std'.
79+
If you are upgrading across this boundary and you have specified `default-features = false`, then
80+
you will need to add the 'std' feature or the 'alloc' feature to your dependency.
81+
The 'std' feature has the same behavior as the previous versions. The 'alloc' feature
82+
provides no_std support.
83+
7684
## Serde
7785
7886
Enable the `serde` feature to include `Deserialize` and `Serialize` implementations for `url::Url`.
@@ -134,6 +142,7 @@ url = { version = "2", features = ["debugger_visualizer"] }
134142
135143
*/
136144

145+
#![no_std]
137146
#![doc(html_root_url = "https://docs.rs/url/2.5.2")]
138147
#![cfg_attr(
139148
feature = "debugger_visualizer",
@@ -145,29 +154,48 @@ url = { version = "2", features = ["debugger_visualizer"] }
145154

146155
pub use form_urlencoded;
147156

157+
// For forwards compatibility
158+
#[cfg(feature = "std")]
159+
extern crate std;
160+
161+
#[macro_use]
162+
extern crate alloc;
163+
148164
#[cfg(feature = "serde")]
149165
extern crate serde;
150166

151167
use crate::host::HostInternal;
152-
use crate::parser::{
153-
to_u32, Context, Parser, SchemeType, PATH_SEGMENT, SPECIAL_PATH_SEGMENT, USERINFO,
154-
};
155-
use percent_encoding::{percent_decode, percent_encode, utf8_percent_encode};
156-
use std::borrow::Borrow;
157-
use std::cmp;
158-
use std::fmt::{self, Write};
159-
use std::hash;
168+
169+
use crate::net::IpAddr;
170+
#[cfg(feature = "std")]
160171
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
161-
use std::io;
162-
use std::mem;
163-
use std::net::IpAddr;
172+
use crate::net::{SocketAddr, ToSocketAddrs};
173+
use crate::parser::{to_u32, Context, Parser, SchemeType, USERINFO};
174+
use alloc::borrow::ToOwned;
175+
use alloc::str;
176+
use alloc::string::{String, ToString};
177+
use core::borrow::Borrow;
178+
use core::convert::TryFrom;
179+
use core::fmt::Write;
180+
use core::ops::{Range, RangeFrom, RangeTo};
181+
use core::{cmp, fmt, hash, mem};
182+
use percent_encoding::utf8_percent_encode;
183+
#[cfg(feature = "std")]
164184
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
165-
use std::net::{SocketAddr, ToSocketAddrs};
166-
use std::ops::{Range, RangeFrom, RangeTo};
185+
use std::io;
186+
#[cfg(feature = "std")]
167187
use std::path::{Path, PathBuf};
168-
use std::str;
169188

170-
use std::convert::TryFrom;
189+
/// `std` version of `net`
190+
#[cfg(feature = "std")]
191+
pub(crate) mod net {
192+
pub use std::net::*;
193+
}
194+
/// `no_std` nightly version of `net`
195+
#[cfg(not(feature = "std"))]
196+
pub(crate) mod net {
197+
pub use core::net::*;
198+
}
171199

172200
pub use crate::host::Host;
173201
pub use crate::origin::{OpaqueOrigin, Origin};
@@ -1279,11 +1307,12 @@ impl Url {
12791307
/// })
12801308
/// }
12811309
/// ```
1310+
#[cfg(feature = "std")]
12821311
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
12831312
pub fn socket_addrs(
12841313
&self,
12851314
default_port_number: impl Fn() -> Option<u16>,
1286-
) -> io::Result<Vec<SocketAddr>> {
1315+
) -> io::Result<alloc::vec::Vec<SocketAddr>> {
12871316
// Note: trying to avoid the Vec allocation by returning `impl AsRef<[SocketAddr]>`
12881317
// causes borrowck issues because the return value borrows `default_port_number`:
12891318
//
@@ -1353,7 +1382,11 @@ impl Url {
13531382
///
13541383
/// ```
13551384
/// use url::Url;
1385+
///
1386+
/// # #[cfg(feature = "std")]
13561387
/// # use std::error::Error;
1388+
/// # #[cfg(not(feature = "std"))]
1389+
/// # use core::error::Error;
13571390
///
13581391
/// # fn run() -> Result<(), Box<dyn Error>> {
13591392
/// let url = Url::parse("https://example.com/foo/bar")?;
@@ -1767,7 +1800,11 @@ impl Url {
17671800
///
17681801
/// ```
17691802
/// use url::Url;
1803+
///
1804+
/// # #[cfg(feature = "std")]
17701805
/// # use std::error::Error;
1806+
/// # #[cfg(not(feature = "std"))]
1807+
/// # use core::error::Error;
17711808
///
17721809
/// # fn run() -> Result<(), Box<dyn Error>> {
17731810
/// let mut url = Url::parse("ssh://example.net:2048/")?;
@@ -1786,7 +1823,11 @@ impl Url {
17861823
///
17871824
/// ```rust
17881825
/// use url::Url;
1826+
///
1827+
/// # #[cfg(feature = "std")]
17891828
/// # use std::error::Error;
1829+
/// # #[cfg(not(feature = "std"))]
1830+
/// # use core::error::Error;
17901831
///
17911832
/// # fn run() -> Result<(), Box<dyn Error>> {
17921833
/// let mut url = Url::parse("https://example.org/")?;
@@ -2469,9 +2510,14 @@ impl Url {
24692510
/// # run().unwrap();
24702511
/// # }
24712512
/// ```
2472-
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
2513+
///
2514+
/// This method is only available if the `std` Cargo feature is enabled.
2515+
#[cfg(all(
2516+
feature = "std",
2517+
any(unix, windows, target_os = "redox", target_os = "wasi")
2518+
))]
24732519
#[allow(clippy::result_unit_err)]
2474-
pub fn from_file_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
2520+
pub fn from_file_path<P: AsRef<std::path::Path>>(path: P) -> Result<Url, ()> {
24752521
let mut serialization = "file://".to_owned();
24762522
let host_start = serialization.len() as u32;
24772523
let (host_end, host) = path_to_file_url_segments(path.as_ref(), &mut serialization)?;
@@ -2506,9 +2552,14 @@ impl Url {
25062552
///
25072553
/// Note that `std::path` does not consider trailing slashes significant
25082554
/// and usually does not include them (e.g. in `Path::parent()`).
2509-
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
2555+
///
2556+
/// This method is only available if the `std` Cargo feature is enabled.
2557+
#[cfg(all(
2558+
feature = "std",
2559+
any(unix, windows, target_os = "redox", target_os = "wasi")
2560+
))]
25102561
#[allow(clippy::result_unit_err)]
2511-
pub fn from_directory_path<P: AsRef<Path>>(path: P) -> Result<Url, ()> {
2562+
pub fn from_directory_path<P: AsRef<std::path::Path>>(path: P) -> Result<Url, ()> {
25122563
let mut url = Url::from_file_path(path)?;
25132564
if !url.serialization.ends_with('/') {
25142565
url.serialization.push('/')
@@ -2622,8 +2673,13 @@ impl Url {
26222673
/// or if `Path::new_opt()` returns `None`.
26232674
/// (That is, if the percent-decoded path contains a NUL byte or,
26242675
/// for a Windows path, is not UTF-8.)
2676+
///
2677+
/// This method is only available if the `std` Cargo feature is enabled.
26252678
#[inline]
2626-
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
2679+
#[cfg(all(
2680+
feature = "std",
2681+
any(unix, windows, target_os = "redox", target_os = "wasi")
2682+
))]
26272683
#[allow(clippy::result_unit_err)]
26282684
pub fn to_file_path(&self) -> Result<PathBuf, ()> {
26292685
if let Some(segments) = self.path_segments() {
@@ -2827,11 +2883,13 @@ impl<'de> serde::Deserialize<'de> for Url {
28272883
}
28282884
}
28292885

2830-
#[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
2886+
#[cfg(all(feature = "std", any(unix, target_os = "redox", target_os = "wasi")))]
28312887
fn path_to_file_url_segments(
28322888
path: &Path,
28332889
serialization: &mut String,
28342890
) -> Result<(u32, HostInternal), ()> {
2891+
use parser::SPECIAL_PATH_SEGMENT;
2892+
use percent_encoding::percent_encode;
28352893
#[cfg(any(unix, target_os = "redox"))]
28362894
use std::os::unix::prelude::OsStrExt;
28372895
#[cfg(target_os = "wasi")]
@@ -2857,7 +2915,7 @@ fn path_to_file_url_segments(
28572915
Ok((host_end, HostInternal::None))
28582916
}
28592917

2860-
#[cfg(windows)]
2918+
#[cfg(all(feature = "std", windows))]
28612919
fn path_to_file_url_segments(
28622920
path: &Path,
28632921
serialization: &mut String,
@@ -2866,11 +2924,14 @@ fn path_to_file_url_segments(
28662924
}
28672925

28682926
// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
2927+
#[cfg(feature = "std")]
28692928
#[cfg_attr(not(windows), allow(dead_code))]
28702929
fn path_to_file_url_segments_windows(
28712930
path: &Path,
28722931
serialization: &mut String,
28732932
) -> Result<(u32, HostInternal), ()> {
2933+
use crate::parser::PATH_SEGMENT;
2934+
use percent_encoding::percent_encode;
28742935
use std::path::{Component, Prefix};
28752936
if !path.is_absolute() {
28762937
return Err(());
@@ -2929,16 +2990,19 @@ fn path_to_file_url_segments_windows(
29292990
Ok((host_end, host_internal))
29302991
}
29312992

2932-
#[cfg(any(unix, target_os = "redox", target_os = "wasi"))]
2993+
#[cfg(all(feature = "std", any(unix, target_os = "redox", target_os = "wasi")))]
29332994
fn file_url_segments_to_pathbuf(
29342995
host: Option<&str>,
29352996
segments: str::Split<'_, char>,
29362997
) -> Result<PathBuf, ()> {
2998+
use alloc::vec::Vec;
2999+
use percent_encoding::percent_decode;
29373000
use std::ffi::OsStr;
29383001
#[cfg(any(unix, target_os = "redox"))]
29393002
use std::os::unix::prelude::OsStrExt;
29403003
#[cfg(target_os = "wasi")]
29413004
use std::os::wasi::prelude::OsStrExt;
3005+
use std::path::PathBuf;
29423006

29433007
if host.is_some() {
29443008
return Err(());
@@ -2974,7 +3038,7 @@ fn file_url_segments_to_pathbuf(
29743038
Ok(path)
29753039
}
29763040

2977-
#[cfg(windows)]
3041+
#[cfg(all(feature = "std", windows))]
29783042
fn file_url_segments_to_pathbuf(
29793043
host: Option<&str>,
29803044
segments: str::Split<char>,
@@ -2983,11 +3047,13 @@ fn file_url_segments_to_pathbuf(
29833047
}
29843048

29853049
// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
3050+
#[cfg(feature = "std")]
29863051
#[cfg_attr(not(windows), allow(dead_code))]
29873052
fn file_url_segments_to_pathbuf_windows(
29883053
host: Option<&str>,
29893054
mut segments: str::Split<'_, char>,
29903055
) -> Result<PathBuf, ()> {
3056+
use percent_encoding::percent_decode;
29913057
let mut string = if let Some(host) = host {
29923058
r"\\".to_owned() + host
29933059
} else {

url/src/origin.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
use crate::host::Host;
1010
use crate::parser::default_port;
1111
use crate::Url;
12-
use std::sync::atomic::{AtomicUsize, Ordering};
12+
use alloc::borrow::ToOwned;
13+
use alloc::format;
14+
use alloc::string::String;
15+
use core::sync::atomic::{AtomicUsize, Ordering};
1316

1417
pub fn url_origin(url: &Url) -> Origin {
1518
let scheme = url.scheme();

0 commit comments

Comments
 (0)