Skip to content

Commit ef5d9d6

Browse files
committed
no_std support.
This PR is similar to other no-std PRs, however it takes the approach of using the new [`core::error`] module in Rust 1.81. This means that no-std mode has an MSRV of Rust 1.81, while the existing MSRV of 1.49 is still supported for existing users, as suggested [here]. This PR also preserves semver compatibility, and avoids adding any new dependencies or required features for existing users. And it avoids modifying the tests and benchmark sources, as those don't need to be no-std. And it avoids making any unrelated changes. And, it adds CI coverage and README.md documentation. [here]: hyperium#563 (comment) [`core::error`]: https://doc.rust-lang.org/stable/core/error/index.html Fixes hyperium#551.
1 parent 68845bd commit ef5d9d6

22 files changed

+139
-71
lines changed

.github/workflows/ci.yml

+13
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,19 @@ jobs:
9090
- name: Test
9191
run: cargo check -p http
9292

93+
no-std:
94+
name: Check no_std
95+
runs-on: ubuntu-latest
96+
steps:
97+
- name: Checkout
98+
uses: actions/checkout@v4
99+
100+
- name: Install Rust
101+
uses: dtolnay/rust-toolchain@stable
102+
103+
- name: Check
104+
run: cargo check --no-default-features --features=no-std
105+
93106
wasm:
94107
name: WASM
95108
#needs: [style]

Cargo.toml

+7-4
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,16 @@ exclude = [
3333
]
3434

3535
[features]
36-
default = ["std"]
37-
std = []
36+
default = ["std", "bytes/default", "fnv/default"]
37+
std = ["bytes/std", "fnv/std"]
38+
no-std = ["hashbrown", "ahash"]
3839

3940
[dependencies]
40-
bytes = "1"
41-
fnv = "1.0.5"
41+
bytes = { version = "1", default-features = false }
42+
fnv = { version = "1.0.5", default-features = false }
4243
itoa = "1"
44+
hashbrown = { version = "0.15.2", optional = true }
45+
ahash = { version = "0.8.6", default-features = false, optional = true }
4346

4447
[dev-dependencies]
4548
quickcheck = "1"

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,11 @@ This project follows the [Tokio MSRV][msrv] and is currently set to `1.49`.
6666

6767
[msrv]: https://github.com/tokio-rs/tokio/#supported-rust-versions
6868

69+
# no-std support
70+
71+
For no-std support, disable the default "std" feature and enable the "no-std"
72+
feature. no-std support has an MSRV of Rust 1.81.
73+
6974
# License
7075

7176
Licensed under either of

src/byte_str.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use bytes::Bytes;
22

3-
use std::{ops, str};
3+
use alloc::string::String;
4+
use core::{ops, str};
45

56
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
67
pub(crate) struct ByteStr {

src/convert.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
macro_rules! if_downcast_into {
22
($in_ty:ty, $out_ty:ty, $val:ident, $body:expr) => {{
3-
if std::any::TypeId::of::<$in_ty>() == std::any::TypeId::of::<$out_ty>() {
3+
if core::any::TypeId::of::<$in_ty>() == core::any::TypeId::of::<$out_ty>() {
44
// Store the value in an `Option` so we can `take`
55
// it after casting to `&mut dyn Any`.
66
let mut slot = Some($val);
77
// Re-write the `$val` ident with the downcasted value.
8-
let $val = (&mut slot as &mut dyn std::any::Any)
8+
let $val = (&mut slot as &mut dyn core::any::Any)
99
.downcast_mut::<Option<$out_ty>>()
1010
.unwrap()
1111
.take()

src/error.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1+
#[cfg(not(feature = "std"))]
2+
use core::error;
3+
use core::fmt;
4+
use core::result;
5+
#[cfg(feature = "std")]
16
use std::error;
2-
use std::fmt;
3-
use std::result;
47

58
use crate::header;
69
use crate::header::MaxSizeReached;
@@ -132,8 +135,8 @@ impl From<header::InvalidHeaderValue> for Error {
132135
}
133136
}
134137

135-
impl From<std::convert::Infallible> for Error {
136-
fn from(err: std::convert::Infallible) -> Error {
138+
impl From<core::convert::Infallible> for Error {
139+
fn from(err: core::convert::Infallible) -> Error {
137140
match err {}
138141
}
139142
}

src/extensions.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1-
use std::any::{Any, TypeId};
1+
use alloc::boxed::Box;
2+
use core::any::{Any, TypeId};
3+
use core::fmt;
4+
use core::hash::{BuildHasherDefault, Hasher};
5+
#[cfg(not(feature = "std"))]
6+
use hashbrown::HashMap;
7+
#[cfg(feature = "std")]
28
use std::collections::HashMap;
3-
use std::fmt;
4-
use std::hash::{BuildHasherDefault, Hasher};
59

610
type AnyMap = HashMap<TypeId, Box<dyn AnyClone + Send + Sync>, BuildHasherDefault<IdHasher>>;
711

src/header/map.rs

+18-9
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
use std::collections::hash_map::RandomState;
2-
use std::collections::HashMap;
3-
use std::convert::TryFrom;
4-
use std::hash::{BuildHasher, Hash, Hasher};
5-
use std::iter::{FromIterator, FusedIterator};
6-
use std::marker::PhantomData;
7-
use std::{fmt, mem, ops, ptr, vec};
1+
use alloc::boxed::Box;
2+
use alloc::vec;
3+
use alloc::vec::Vec;
4+
use core::convert::TryFrom;
5+
use core::hash::{BuildHasher, Hash, Hasher};
6+
use core::iter::{FromIterator, FusedIterator};
7+
use core::marker::PhantomData;
8+
use core::{fmt, mem, ops, ptr};
9+
#[cfg(feature = "std")]
10+
use std::collections::{hash_map::RandomState, HashMap};
11+
#[cfg(not(feature = "std"))]
12+
use {ahash::RandomState, hashbrown::HashMap};
813

914
use crate::Error;
1015

@@ -116,7 +121,7 @@ pub struct IntoIter<T> {
116121
/// associated value.
117122
#[derive(Debug)]
118123
pub struct Keys<'a, T> {
119-
inner: ::std::slice::Iter<'a, Bucket<T>>,
124+
inner: ::core::slice::Iter<'a, Bucket<T>>,
120125
}
121126

122127
/// `HeaderMap` value iterator.
@@ -209,7 +214,7 @@ pub struct ValueIterMut<'a, T> {
209214
#[derive(Debug)]
210215
pub struct ValueDrain<'a, T> {
211216
first: Option<T>,
212-
next: Option<::std::vec::IntoIter<T>>,
217+
next: Option<::alloc::vec::IntoIter<T>>,
213218
lt: PhantomData<&'a mut HeaderMap<T>>,
214219
}
215220

@@ -3574,7 +3579,10 @@ impl fmt::Display for MaxSizeReached {
35743579
}
35753580
}
35763581

3582+
#[cfg(feature = "std")]
35773583
impl std::error::Error for MaxSizeReached {}
3584+
#[cfg(not(feature = "std"))]
3585+
impl core::error::Error for MaxSizeReached {}
35783586

35793587
// ===== impl Utils =====
35803588

@@ -3736,6 +3744,7 @@ mod into_header_name {
37363744

37373745
mod as_header_name {
37383746
use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName, MaxSizeReached};
3747+
use alloc::string::String;
37393748

37403749
/// A marker trait used to identify values that can be used as search keys
37413750
/// to a `HeaderMap`.

src/header/name.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
use crate::byte_str::ByteStr;
22
use bytes::{Bytes, BytesMut};
33

4-
use std::borrow::Borrow;
5-
use std::convert::TryFrom;
4+
use alloc::string::String;
5+
use alloc::vec::Vec;
6+
use core::borrow::Borrow;
7+
use core::convert::TryFrom;
8+
#[cfg(not(feature = "std"))]
9+
use core::error::Error;
10+
use core::fmt;
11+
use core::hash::{Hash, Hasher};
12+
use core::mem::MaybeUninit;
13+
use core::str::FromStr;
14+
#[cfg(feature = "std")]
615
use std::error::Error;
7-
use std::fmt;
8-
use std::hash::{Hash, Hasher};
9-
use std::mem::MaybeUninit;
10-
use std::str::FromStr;
1116

1217
/// Represents an HTTP header field name
1318
///
@@ -89,7 +94,7 @@ macro_rules! standard_headers {
8994
match *self {
9095
// Safety: test_parse_standard_headers ensures these &[u8]s are &str-safe.
9196
$(
92-
StandardHeader::$konst => unsafe { std::str::from_utf8_unchecked( $name_bytes ) },
97+
StandardHeader::$konst => unsafe { core::str::from_utf8_unchecked( $name_bytes ) },
9398
)+
9499
}
95100
}

src/header/value.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
use bytes::{Bytes, BytesMut};
22

3-
use std::convert::TryFrom;
3+
use alloc::string::String;
4+
use alloc::vec::Vec;
5+
use core::convert::TryFrom;
6+
#[cfg(not(feature = "std"))]
7+
use core::error::Error;
8+
use core::fmt::Write;
9+
use core::hash::{Hash, Hasher};
10+
use core::str::FromStr;
11+
use core::{cmp, fmt, str};
12+
#[cfg(feature = "std")]
413
use std::error::Error;
5-
use std::fmt::Write;
6-
use std::hash::{Hash, Hasher};
7-
use std::str::FromStr;
8-
use std::{cmp, fmt, str};
914

1015
use crate::header::name::HeaderName;
1116

@@ -234,7 +239,7 @@ impl HeaderValue {
234239
}
235240

236241
fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
237-
HeaderValue::try_from_generic(src, std::convert::identity)
242+
HeaderValue::try_from_generic(src, core::convert::identity)
238243
}
239244

240245
fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(

src/lib.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,9 @@
154154
//! ```
155155
156156
#![deny(warnings, missing_docs, missing_debug_implementations)]
157+
#![cfg_attr(not(feature = "std"), no_std)]
157158

158-
//#![cfg_attr(not(feature = "std"), no_std)]
159-
#[cfg(not(feature = "std"))]
160-
compile_error!("`std` feature currently required, support for `no_std` may be added later");
159+
extern crate alloc;
161160

162161
#[cfg(test)]
163162
#[macro_use]

src/method.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
use self::extension::{AllocatedExtension, InlineExtension};
1919
use self::Inner::*;
2020

21-
use std::convert::TryFrom;
21+
use core::convert::TryFrom;
22+
#[cfg(not(feature = "std"))]
23+
use core::error::Error;
24+
use core::str::FromStr;
25+
use core::{fmt, str};
26+
#[cfg(feature = "std")]
2227
use std::error::Error;
23-
use std::str::FromStr;
24-
use std::{fmt, str};
2528

2629
/// The Request Method (VERB)
2730
///
@@ -306,7 +309,10 @@ impl Error for InvalidMethod {}
306309

307310
mod extension {
308311
use super::InvalidMethod;
309-
use std::str;
312+
use alloc::boxed::Box;
313+
use alloc::vec;
314+
use alloc::vec::Vec;
315+
use core::str;
310316

311317
#[derive(Clone, PartialEq, Eq, Hash)]
312318
// Invariant: the first self.1 bytes of self.0 are valid UTF-8.

src/request.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@
5252
//! }
5353
//! ```
5454
55-
use std::any::Any;
56-
use std::convert::TryInto;
57-
use std::fmt;
55+
use core::any::Any;
56+
use core::convert::TryInto;
57+
use core::fmt;
5858

5959
use crate::header::{HeaderMap, HeaderName, HeaderValue};
6060
use crate::method::Method;

src/response.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,9 @@
6161
//! // ...
6262
//! ```
6363
64-
use std::any::Any;
65-
use std::convert::TryInto;
66-
use std::fmt;
64+
use core::any::Any;
65+
use core::convert::TryInto;
66+
use core::fmt;
6767

6868
use crate::header::{HeaderMap, HeaderName, HeaderValue};
6969
use crate::status::StatusCode;

src/status.rs

+8-4
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@
1414
//! assert!(StatusCode::OK.is_success());
1515
//! ```
1616
17-
use std::convert::TryFrom;
17+
use crate::alloc::borrow::ToOwned;
18+
use core::convert::TryFrom;
19+
#[cfg(not(feature = "std"))]
20+
use core::error::Error;
21+
use core::fmt;
22+
use core::num::NonZeroU16;
23+
use core::str::FromStr;
24+
#[cfg(feature = "std")]
1825
use std::error::Error;
19-
use std::fmt;
20-
use std::num::NonZeroU16;
21-
use std::str::FromStr;
2226

2327
/// An HTTP status code (`status-code` in RFC 9110 et al.).
2428
///

src/uri/authority.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
use std::convert::TryFrom;
2-
use std::hash::{Hash, Hasher};
3-
use std::str::FromStr;
4-
use std::{cmp, fmt, str};
1+
use alloc::string::String;
2+
use alloc::vec::Vec;
3+
use core::convert::TryFrom;
4+
use core::hash::{Hash, Hasher};
5+
use core::str::FromStr;
6+
use core::{cmp, fmt, str};
57

68
use bytes::Bytes;
79

src/uri/builder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::convert::TryInto;
1+
use core::convert::TryInto;
22

33
use super::{Authority, Parts, PathAndQuery, Scheme};
44
use crate::Uri;

src/uri/mod.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,20 @@
2323
//! ```
2424
2525
use crate::byte_str::ByteStr;
26-
use std::convert::TryFrom;
2726

2827
use bytes::Bytes;
2928

29+
use alloc::boxed::Box;
30+
use alloc::string::String;
31+
use alloc::vec::Vec;
32+
use core::convert::TryFrom;
33+
#[cfg(not(feature = "std"))]
34+
use core::error::Error;
35+
use core::fmt;
36+
use core::hash::{Hash, Hasher};
37+
use core::str::{self, FromStr};
38+
#[cfg(feature = "std")]
3039
use std::error::Error;
31-
use std::fmt;
32-
use std::hash::{Hash, Hasher};
33-
use std::str::{self, FromStr};
3440

3541
use self::scheme::Scheme2;
3642

src/uri/path.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
use std::convert::TryFrom;
2-
use std::str::FromStr;
3-
use std::{cmp, fmt, hash, str};
1+
use alloc::string::String;
2+
use alloc::vec::Vec;
3+
use core::convert::TryFrom;
4+
use core::str::FromStr;
5+
use core::{cmp, fmt, hash, str};
46

57
use bytes::Bytes;
68

src/uri/port.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::fmt;
1+
use core::fmt;
22

33
use super::{ErrorKind, InvalidUri};
44

0 commit comments

Comments
 (0)