Skip to content

Commit

Permalink
Merge pull request #1 from OverOrion/no_std_net
Browse files Browse the repository at this point in the history
Add support for `no_std`
  • Loading branch information
OverOrion authored Apr 20, 2023
2 parents 6385c81 + 6d622ab commit 947f64c
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 65 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ jobs:
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
# Add toolchain for no_std tests
- run: rustup toolchain install nightly
- run: rustup target add aarch64-unknown-none
- run: cargo build --all-targets
# Run tests
- name: Run tests
Expand All @@ -49,6 +52,8 @@ jobs:
run: cargo test --test debugger_visualizer --features "url/serde,url/debugger_visualizer" -- --test-threads=1
- name: Test `no_std` support
run: cargo test --no-default-features --features=alloc
- name: Build `aarch64-unknown-none` with `no_std`
run: cargo +nightly build -Zbuild-std=core,alloc --target aarch64-unknown-none -v --release --no-default-features --features=alloc

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 @@ -17,7 +17,7 @@ alloc = []

[dev-dependencies]
tester = "0.9"
serde = {version = "1.0", features = ["derive"]}
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
serde_json = "1.0"

[lib]
Expand Down
2 changes: 1 addition & 1 deletion idna/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ name = "unit"
assert_matches = "1.3"
bencher = "0.1"
tester = "0.9"
serde_json = "1.0"
serde_json = { version = "1.0" }

[dependencies]
unicode-bidi = { version = "0.3.10", default-features = false, features = ["hardcoded-data"] }
Expand Down
2 changes: 1 addition & 1 deletion idna/src/uts46.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ impl Idna {
return Errors::default();
}
let mut errors = processing(domain, self.config, &mut self.normalized, out);
self.output = std::mem::replace(out, String::with_capacity(out.len()));
self.output = core::mem::replace(out, String::with_capacity(out.len()));
let mut first = true;
for label in self.output.split('.') {
if !first {
Expand Down
3 changes: 1 addition & 2 deletions idna/tests/punycode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@

use crate::test::TestFn;
use idna::punycode::{decode, encode_str};
use serde_json::map::Map;
use serde_json::Value;
use serde_json::{map::Map, Value};
use std::str::FromStr;

fn one_test(decoded: &str, encoded: &str) {
Expand Down
15 changes: 10 additions & 5 deletions url/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,23 @@ debugger_test = "0.1"
debugger_test_parser = "0.1"

[dependencies]
form_urlencoded = { version = "1.1.0", path = "../form_urlencoded" }
idna = { version = "0.3.0", path = "../idna" }
percent-encoding = { version = "2.2.0", path = "../percent_encoding" }
serde = {version = "1.0", optional = true, features = ["derive"]}
form_urlencoded = { version = "1.1.0", path = "../form_urlencoded", default-features = false, features = ["alloc"] }
idna = { version = "0.3.0", path = "../idna", default-features = false, features = ["alloc"] }
percent-encoding = { version = "2.2.0", path = "../percent_encoding", default-features = false, features = ["alloc"] }
data-url = { version = "0.2.0", path = "../data-url", default-features = false, features = ["alloc"] }
serde = {version = "1.0", optional = true, default-features = false, features = ["alloc", "derive"]}
no-std-net = { version = "0.6.0", default-features = false }

[features]
default = []
default = ["std"]
std = ["idna/std", "percent-encoding/std", "form_urlencoded/std", "no-std-net/std", "alloc"]
alloc = []
# UNSTABLE FEATURES (requires Rust nightly)
# Enable to use the #[debugger_visualizer] attribute.
debugger_visualizer = []
# Expose internal offsets of the URL.
expose_internals = []
serde = ["dep:serde", "no-std-net/serde"]

[[bench]]
name = "parse_url"
Expand Down
13 changes: 10 additions & 3 deletions url/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,16 @@
// 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,
string::{String, ToString},
vec::Vec,
};
use core::{
cmp,
fmt::{self, Formatter},
};
use no_std_net::{Ipv4Addr, Ipv6Addr};

use percent_encoding::{percent_decode, utf8_percent_encode, CONTROLS};
#[cfg(feature = "serde")]
Expand Down
139 changes: 111 additions & 28 deletions url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,27 +127,44 @@ url = { version = "2", features = ["serde"] }
feature(debugger_visualizer),
debugger_visualizer(natvis_file = "../../debug_metadata/url.natvis")
)]
#![no_std]

pub use form_urlencoded;

// For forwards compatibility
#[cfg(feature = "std")]
extern crate std;

#[macro_use]
extern crate alloc;

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

#[cfg(feature = "serde")]
extern crate serde;

use crate::host::HostInternal;
use crate::parser::{to_u32, Context, Parser, SchemeType, 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 std::io;
use std::mem;
use std::net::{IpAddr, SocketAddr, ToSocketAddrs};
use std::ops::{Range, RangeFrom, RangeTo};
use std::path::{Path, PathBuf};
use std::str;

use std::convert::TryFrom;
use crate::parser::{to_u32, Context, Parser, SchemeType, USERINFO};
use alloc::borrow::ToOwned;
use alloc::string::{String, ToString};
use core::borrow::Borrow;
use core::cmp;
use core::convert::TryFrom;
use core::fmt::{self, Write};
use core::hash;
use core::mem;
use core::ops::{Range, RangeFrom, RangeTo};
use core::str;
use no_std_net::IpAddr;
use percent_encoding::utf8_percent_encode;

#[cfg(feature = "std")]
use std::{
io,
net::{SocketAddr, ToSocketAddrs},
path::{Path, PathBuf},
};

pub use crate::host::Host;
pub use crate::origin::{OpaqueOrigin, Origin};
Expand Down Expand Up @@ -1237,10 +1254,11 @@ impl Url {
/// })
/// }
/// ```
#[cfg(feature = "std")]
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 All @@ -1249,6 +1267,7 @@ impl Url {
// > This RFC proposes that *all* type parameters are considered in scope
// > for `impl Trait` in return position

// TODO: Return custom error type to support no_std
fn io_result<T>(opt: Option<T>, message: &str) -> io::Result<T> {
opt.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, message))
}
Expand Down Expand Up @@ -1310,9 +1329,23 @@ impl Url {
///
/// ```
/// use url::Url;
/// # use std::error::Error;
///
/// # fn run() -> Result<(), Box<dyn Error>> {
/// # use url::ParseError;
/// # #[derive(Debug)]
/// # /// A simple wrapper error struct for `no_std` support
/// # struct TestError;
/// # impl From<ParseError> for TestError {
/// # fn from(value: ParseError) -> Self {
/// # TestError {}
/// # }
/// # }
/// # impl From<&str> for TestError {
/// # fn from(value: &str) -> Self {
/// # TestError {}
/// # }
/// # }
///
/// # fn run() -> Result<(), TestError> {
/// let url = Url::parse("https://example.com/foo/bar")?;
/// let mut path_segments = url.path_segments().ok_or_else(|| "cannot be base")?;
/// assert_eq!(path_segments.next(), Some("foo"));
Expand Down Expand Up @@ -1717,9 +1750,22 @@ impl Url {
///
/// ```
/// use url::Url;
/// # use std::error::Error;
/// # use url::ParseError;
/// # #[derive(Debug)]
/// # /// A simple wrapper error struct for `no_std` support
/// # struct TestError;
/// # impl From<ParseError> for TestError {
/// # fn from(value: ParseError) -> Self {
/// # TestError {}
/// # }
/// # }
/// # impl From<&str> for TestError {
/// # fn from(value: &str) -> Self {
/// # TestError {}
/// # }
/// # }
///
/// # fn run() -> Result<(), Box<dyn Error>> {
/// # fn run() -> Result<(), TestError> {
/// let mut url = Url::parse("ssh://example.net:2048/")?;
///
/// url.set_port(Some(4096)).map_err(|_| "cannot be base")?;
Expand All @@ -1736,9 +1782,22 @@ impl Url {
///
/// ```rust
/// use url::Url;
/// # use std::error::Error;
/// # use url::ParseError;
/// # #[derive(Debug)]
/// # /// A simple wrapper error struct for `no_std` support
/// # struct TestError;
/// # impl From<ParseError> for TestError {
/// # fn from(value: ParseError) -> Self {
/// # TestError {}
/// # }
/// # }
/// # impl From<&str> for TestError {
/// # fn from(value: &str) -> Self {
/// # TestError {}
/// # }
/// # }
///
/// # fn run() -> Result<(), Box<dyn Error>> {
/// # fn run() -> Result<(), TestError> {
/// let mut url = Url::parse("https://example.org/")?;
///
/// url.set_port(Some(443)).map_err(|_| "cannot be base")?;
Expand Down Expand Up @@ -2419,7 +2478,12 @@ 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, ()> {
let mut serialization = "file://".to_owned();
Expand Down Expand Up @@ -2456,7 +2520,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"))]
///
/// 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, ()> {
let mut url = Url::from_file_path(path)?;
Expand Down Expand Up @@ -2572,8 +2641,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 @@ -2777,11 +2851,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 crate::parser::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 @@ -2807,20 +2883,23 @@ 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,
) -> Result<(u32, HostInternal), ()> {
path_to_file_url_segments_windows(path, serialization)
}

#[cfg(feature = "std")]
// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
#[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 @@ -2879,11 +2958,13 @@ 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;
Expand Down Expand Up @@ -2924,20 +3005,22 @@ 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, ()> {
file_url_segments_to_pathbuf_windows(host, segments)
}

#[cfg(feature = "std")]
// Build this unconditionally to alleviate https://github.com/servo/rust-url/issues/102
#[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
3 changes: 2 additions & 1 deletion url/src/origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
use crate::host::Host;
use crate::parser::default_port;
use crate::Url;
use std::sync::atomic::{AtomicUsize, Ordering};
use alloc::{borrow::ToOwned, 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 947f64c

Please sign in to comment.