Skip to content

no_std support for url #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -51,6 +58,13 @@ jobs:
run: cargo test --test debugger_visualizer --features "url/debugger_visualizer,url_debug_tests/debugger_visualizer" -- --test-threads=1
- 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 +nightly check -Zbuild-std=core,alloc --target aarch64-unknown-none -v --release --no-default-features --features=alloc

WASM:
runs-on: ubuntu-latest
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 }
idna = { version = "0.5.0", path = "../idna", default-features = false }
percent-encoding = { version = "2.3.1", path = "../percent_encoding", default-features = false }
serde = { version = "1.0", optional = true, features = ["derive"] }

[features]
default = []
default = ["std"]
std = ["alloc", "form_urlencoded/std", "idna/std", "percent-encoding/std"]
alloc = ["form_urlencoded/alloc", "idna/alloc", "percent-encoding/alloc"]
# 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 alloc::borrow::ToOwned;
use alloc::string::String;
use alloc::string::ToString;
use alloc::vec::Vec;
use core::cmp;
use core::fmt::{self, Formatter};
use std_core_compat::net::{Ipv4Addr, Ipv6Addr};

use percent_encoding::{percent_decode, utf8_percent_encode, CONTROLS};
#[cfg(feature = "serde")]
Expand Down
108 changes: 74 additions & 34 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 @@ -139,6 +147,21 @@ url = { version = "2", features = ["debugger_visualizer"] }
feature = "debugger_visualizer",
debugger_visualizer(natvis_file = "../../debug_metadata/url.natvis")
)]
#![cfg_attr(not(feature = "std"), no_std)]

// Use std_core_compat for dependencies that
// are in std in the Minimum Supported Rust Version
// and in core in the latest stable release.
#[cfg(feature = "std")]
extern crate std as std_core_compat;

#[cfg(not(feature = "std"))]
extern crate core as std_core_compat;

extern crate alloc;

#[cfg(not(feature = "alloc"))]
compile_error!("the `alloc` feature must currently be enabled");

pub use form_urlencoded;

Expand All @@ -149,22 +172,22 @@ use crate::host::HostInternal;
use crate::parser::{
to_u32, Context, Parser, SchemeType, PATH_SEGMENT, SPECIAL_PATH_SEGMENT, USERINFO,
};
use core::borrow::Borrow;
use core::cmp;
use core::fmt::{self, Write};
use core::hash;
use core::mem;
use core::ops::{Range, RangeFrom, RangeTo};
use core::str;
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;
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
use std::io;
use std::mem;
use std::net::IpAddr;
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
use std::net::{SocketAddr, ToSocketAddrs};
use std::ops::{Range, RangeFrom, RangeTo};
use std::path::{Path, PathBuf};
use std::str;

use std::convert::TryFrom;
use std_core_compat::net::IpAddr;

use alloc::borrow::ToOwned;
use alloc::format;
use alloc::string::String;
use alloc::string::ToString;

use core::convert::TryFrom;

pub use crate::host::Host;
pub use crate::origin::{OpaqueOrigin, Origin};
Expand Down Expand Up @@ -1276,11 +1299,16 @@ impl Url {
/// })
/// }
/// ```
#[cfg(any(unix, windows, target_os = "redox", target_os = "wasi"))]
#[cfg(all(
feature = "std",
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>> {
) -> std::io::Result<Vec<std::net::SocketAddr>> {
use std::io;
use std::net::ToSocketAddrs;
// 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 @@ -2466,9 +2494,12 @@ impl Url {
/// # run().unwrap();
/// # }
/// ```
#[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 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 @@ -2503,9 +2534,12 @@ 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"))]
#[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 @@ -2620,9 +2654,12 @@ impl Url {
/// (That is, if the percent-decoded path contains a NUL byte or,
/// for a Windows path, is not UTF-8.)
#[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, ()> {
pub fn to_file_path(&self) -> Result<std::path::PathBuf, ()> {
if let Some(segments) = self.path_segments() {
let host = match self.host() {
None | Some(Host::Domain("localhost")) => None,
Expand Down Expand Up @@ -2824,9 +2861,9 @@ 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,
path: &std::path::Path,
serialization: &mut String,
) -> Result<(u32, HostInternal), ()> {
#[cfg(any(unix, target_os = "redox"))]
Expand Down Expand Up @@ -2854,18 +2891,19 @@ 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,
path: &std::path::Path,
serialization: &mut String,
) -> Result<(u32, HostInternal), ()> {
path_to_file_url_segments_windows(path, serialization)
}

// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
#[cfg_attr(not(windows), allow(dead_code))]
#[cfg(feature = "std")]
fn path_to_file_url_segments_windows(
path: &Path,
path: &std::path::Path,
serialization: &mut String,
) -> Result<(u32, HostInternal), ()> {
use std::path::{Component, Prefix};
Expand Down Expand Up @@ -2926,16 +2964,17 @@ 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, ()> {
) -> Result<std::path::PathBuf, ()> {
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 @@ -2971,20 +3010,21 @@ 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>,
) -> Result<PathBuf, ()> {
) -> Result<std::path::PathBuf, ()> {
file_url_segments_to_pathbuf_windows(host, segments)
}

// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
#[cfg_attr(not(windows), allow(dead_code))]
#[cfg(feature = "std")]
fn file_url_segments_to_pathbuf_windows(
host: Option<&str>,
mut segments: str::Split<'_, char>,
) -> Result<PathBuf, ()> {
) -> Result<std::path::PathBuf, ()> {
let mut string = if let Some(host) = host {
r"\\".to_owned() + host
} else {
Expand Down Expand Up @@ -3024,7 +3064,7 @@ fn file_url_segments_to_pathbuf_windows(
Err(..) => return Err(()),
}
}
let path = PathBuf::from(string);
let path = std::path::PathBuf::from(string);
debug_assert!(
path.is_absolute(),
"to_file_path() failed to produce an absolute Path"
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
8 changes: 5 additions & 3 deletions url/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
// 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 std_core_compat::error::Error;

use crate::host::{Host, HostInternal};
use crate::Url;
Expand Down
3 changes: 2 additions & 1 deletion url/src/path_segments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
2 changes: 2 additions & 0 deletions url/src/quirks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
2 changes: 1 addition & 1 deletion url/src/slicing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// except according to those terms.

use crate::Url;
use std::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};
use core::ops::{Index, Range, RangeFrom, RangeFull, RangeTo};

impl Index<RangeFull> for Url {
type Output = str;
Expand Down
Loading