Skip to content
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

no_std support for form_urlencoded, data-url and idna #722

Merged
merged 6 commits into from
Apr 2, 2023
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ jobs:
matrix.os == 'windows-latest' &&
matrix.rust == 'nightly'
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

WASM:
runs-on: ubuntu-latest
Expand Down
6 changes: 6 additions & 0 deletions data-url/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ name = "data-url"
version = "0.2.0"
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
description = "Processing of data: URL according to WHATWG’s Fetch Standard"
categories = ["no_std"]
repository = "https://github.com/servo/rust-url"
license = "MIT OR Apache-2.0"
edition = "2018"
autotests = false
rust-version = "1.51"

[features]
default = ["std"]
std = ["alloc"]
alloc = []

[dev-dependencies]
tester = "0.9"
serde = {version = "1.0", features = ["derive"]}
Expand Down
2 changes: 2 additions & 0 deletions data-url/src/forgiving_base64.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! <https://infra.spec.whatwg.org/#forgiving-base64-decode>

use alloc::vec::Vec;

#[derive(Debug)]
pub struct InvalidBase64(InvalidBase64Details);

Expand Down
13 changes: 13 additions & 0 deletions data-url/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,19 @@
//! assert_eq!(body, b"Hello World!");
//! assert!(fragment.is_none());
//! ```
#![no_std]

// For forwards compatibility
#[cfg(feature = "std")]
extern crate std as _;
Comment on lines +19 to +21
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To expand on this: We include it to force no_std users to disable the std feature (since otherwise their program won't compile). This ensures that if we in the future want to add something that relies on std, we can.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain how that works? Or point me to a resource that does that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we didn't have this line, a user could add a dependency on data-url on a platform like the Arduino, and since we've specified #![no_std] in the crate, compilation will succeed, even though the std feature is enabled.

Let's say that in the future, we wanted to add an error type to this crate, and have it implement std::error::Error. To do so, we'd have to introduce a #[cfg(feature = "std")] extern crate std;. But since the hypothetical Arduino user didn't specify default-features = false, their crate would now fail to build.

With this line in place to begin with, we know the user has specified default-features = false to even compile the library.

For reference, the error looks something like this (can be simulated with -Zbuild-std=core,alloc):

error[E0463]: can't find crate for `std`
 --> data-url/src/lib.rs:21:1
  |
  | extern crate std as _;
  | ^^^^^^^^^^^^^^^^^^^^^^ can't find crate
  |

Did that clear it up? Or do you want me to try explaining it in a different way? Unfortunately, I haven't found many resources for "building Rust libraries that work well with no_std", so I can't really link to a blog post or something explaining the details, this is mostly figured out by trial and error :/


#[macro_use]
extern crate alloc;

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

use alloc::{string::String, vec::Vec};

macro_rules! require {
($condition: expr) => {
Expand Down
5 changes: 3 additions & 2 deletions data-url/src/mime.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::fmt::{self, Write};
use std::str::FromStr;
use alloc::{borrow::ToOwned, string::String, vec::Vec};
use core::fmt::{self, Write};
use core::str::FromStr;

/// <https://mimesniff.spec.whatwg.org/#mime-type-representation>
#[derive(Debug, PartialEq, Eq)]
Expand Down
8 changes: 7 additions & 1 deletion form_urlencoded/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name = "form_urlencoded"
version = "1.1.0"
authors = ["The rust-url developers"]
description = "Parser and serializer for the application/x-www-form-urlencoded syntax, as used by HTML forms."
categories = ["no_std"]
repository = "https://github.com/servo/rust-url"
license = "MIT OR Apache-2.0"
edition = "2018"
Expand All @@ -11,5 +12,10 @@ rust-version = "1.51"
[lib]
test = false

[features]
default = ["std"]
std = ["alloc", "percent-encoding/std"]
alloc = ["percent-encoding/alloc"]

[dependencies]
percent-encoding = { version = "2.2.0", path = "../percent_encoding" }
percent-encoding = { version = "2.2.0", default-features = false, path = "../percent_encoding" }
15 changes: 13 additions & 2 deletions form_urlencoded/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,21 @@
//!
//! Converts between a string (such as an URL’s query string)
//! and a sequence of (name, value) pairs.
#![no_std]

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

extern crate alloc;

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

use alloc::borrow::{Borrow, Cow, ToOwned};
use alloc::string::String;
use core::str;
use percent_encoding::{percent_decode, percent_encode_byte};
use std::borrow::{Borrow, Cow};
use std::str;

/// Convert a byte string in the `application/x-www-form-urlencoded` syntax
/// into a iterator of (name, value) pairs.
Expand Down
10 changes: 8 additions & 2 deletions idna/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name = "idna"
version = "0.3.0"
authors = ["The rust-url developers"]
description = "IDNA (Internationalizing Domain Names in Applications) and Punycode."
categories = ["no_std"]
repository = "https://github.com/servo/rust-url/"
license = "MIT OR Apache-2.0"
autotests = false
Expand All @@ -12,6 +13,11 @@ rust-version = "1.51"
[lib]
doctest = false

[features]
default = ["std"]
std = ["alloc", "unicode-bidi/std", "unicode-normalization/std"]
alloc = []

[[test]]
name = "tests"
harness = false
Expand All @@ -26,8 +32,8 @@ tester = "0.9"
serde_json = "1.0"

[dependencies]
unicode-bidi = "0.3"
unicode-normalization = "0.1.17"
unicode-bidi = { version = "0.3.10", default-features = false, features = ["hardcoded-data"] }
unicode-normalization = { version = "0.1.22", default-features = false }

[[bench]]
name = "all"
Expand Down
12 changes: 12 additions & 0 deletions idna/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,23 @@
//! > This document specifies a mechanism
//! > that minimizes the impact of this transition for client software,
//! > allowing client software to access domains that are valid under either system.
#![no_std]

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

extern crate alloc;

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

#[cfg(test)]
#[macro_use]
extern crate assert_matches;

use alloc::string::String;

pub mod punycode;
mod uts46;

Expand Down
7 changes: 4 additions & 3 deletions idna/src/punycode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@
//! `encode_str` and `decode_to_string` provide convenience wrappers
//! that convert from and to Rust’s UTF-8 based `str` and `String` types.

use std::char;
use std::u32;
use alloc::{string::String, vec::Vec};
use core::char;
use core::u32;

// Bootstring parameters for Punycode
static BASE: u32 = 36;
Expand Down Expand Up @@ -168,7 +169,7 @@ impl Decoder {
}

pub(crate) struct Decode<'a> {
base: std::str::Chars<'a>,
base: core::str::Chars<'a>,
pub(crate) insertions: &'a [(usize, char)],
inserted: usize,
position: usize,
Expand Down
11 changes: 7 additions & 4 deletions idna/src/uts46.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

use self::Mapping::*;
use crate::punycode;
use std::{error::Error as StdError, fmt};

use alloc::string::String;
use core::fmt;
use unicode_bidi::{bidi_class, BidiClass};
use unicode_normalization::char::is_combining_mark;
use unicode_normalization::{is_nfc, UnicodeNormalization};
Expand Down Expand Up @@ -70,10 +72,10 @@ fn find_char(codepoint: char) -> &'static Mapping {
}

struct Mapper<'a> {
chars: std::str::Chars<'a>,
chars: core::str::Chars<'a>,
config: Config,
errors: &'a mut Errors,
slice: Option<std::str::Chars<'static>>,
slice: Option<core::str::Chars<'static>>,
}

impl<'a> Iterator for Mapper<'a> {
Expand Down Expand Up @@ -708,7 +710,8 @@ impl From<Errors> for Result<(), Errors> {
}
}

impl StdError for Errors {}
#[cfg(feature = "std")]
impl std::error::Error for Errors {}

impl fmt::Display for Errors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand Down
4 changes: 3 additions & 1 deletion percent_encoding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ name = "percent-encoding"
version = "2.2.0"
authors = ["The rust-url developers"]
description = "Percent encoding and decoding"
categories = ["no_std"]
repository = "https://github.com/servo/rust-url/"
license = "MIT OR Apache-2.0"
edition = "2018"
rust-version = "1.51"

[features]
default = ["alloc"]
default = ["std"]
std = ["alloc"]
alloc = []
6 changes: 5 additions & 1 deletion percent_encoding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@
//!
//! assert_eq!(utf8_percent_encode("foo <bar>", FRAGMENT).to_string(), "foo%20%3Cbar%3E");
//! ```

#![no_std]

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

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

Expand Down