Skip to content

Commit

Permalink
no_std support.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sunfishcode committed Jan 14, 2025
1 parent 68845bd commit ef5d9d6
Show file tree
Hide file tree
Showing 22 changed files with 139 additions and 71 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,19 @@ jobs:
- name: Test
run: cargo check -p http

no-std:
name: Check no_std
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust
uses: dtolnay/rust-toolchain@stable

- name: Check
run: cargo check --no-default-features --features=no-std

wasm:
name: WASM
#needs: [style]
Expand Down
11 changes: 7 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,16 @@ exclude = [
]

[features]
default = ["std"]
std = []
default = ["std", "bytes/default", "fnv/default"]
std = ["bytes/std", "fnv/std"]
no-std = ["hashbrown", "ahash"]

[dependencies]
bytes = "1"
fnv = "1.0.5"
bytes = { version = "1", default-features = false }
fnv = { version = "1.0.5", default-features = false }
itoa = "1"
hashbrown = { version = "0.15.2", optional = true }
ahash = { version = "0.8.6", default-features = false, optional = true }

[dev-dependencies]
quickcheck = "1"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ This project follows the [Tokio MSRV][msrv] and is currently set to `1.49`.

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

# no-std support

For no-std support, disable the default "std" feature and enable the "no-std"
feature. no-std support has an MSRV of Rust 1.81.

# License

Licensed under either of
Expand Down
3 changes: 2 additions & 1 deletion src/byte_str.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bytes::Bytes;

use std::{ops, str};
use alloc::string::String;
use core::{ops, str};

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub(crate) struct ByteStr {
Expand Down
4 changes: 2 additions & 2 deletions src/convert.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
macro_rules! if_downcast_into {
($in_ty:ty, $out_ty:ty, $val:ident, $body:expr) => {{
if std::any::TypeId::of::<$in_ty>() == std::any::TypeId::of::<$out_ty>() {
if core::any::TypeId::of::<$in_ty>() == core::any::TypeId::of::<$out_ty>() {
// Store the value in an `Option` so we can `take`
// it after casting to `&mut dyn Any`.
let mut slot = Some($val);
// Re-write the `$val` ident with the downcasted value.
let $val = (&mut slot as &mut dyn std::any::Any)
let $val = (&mut slot as &mut dyn core::any::Any)
.downcast_mut::<Option<$out_ty>>()
.unwrap()
.take()
Expand Down
11 changes: 7 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#[cfg(not(feature = "std"))]
use core::error;
use core::fmt;
use core::result;
#[cfg(feature = "std")]
use std::error;
use std::fmt;
use std::result;

use crate::header;
use crate::header::MaxSizeReached;
Expand Down Expand Up @@ -132,8 +135,8 @@ impl From<header::InvalidHeaderValue> for Error {
}
}

impl From<std::convert::Infallible> for Error {
fn from(err: std::convert::Infallible) -> Error {
impl From<core::convert::Infallible> for Error {
fn from(err: core::convert::Infallible) -> Error {
match err {}
}
}
Expand Down
10 changes: 7 additions & 3 deletions src/extensions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::any::{Any, TypeId};
use alloc::boxed::Box;
use core::any::{Any, TypeId};
use core::fmt;
use core::hash::{BuildHasherDefault, Hasher};
#[cfg(not(feature = "std"))]
use hashbrown::HashMap;
#[cfg(feature = "std")]
use std::collections::HashMap;
use std::fmt;
use std::hash::{BuildHasherDefault, Hasher};

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

Expand Down
27 changes: 18 additions & 9 deletions src/header/map.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use std::collections::hash_map::RandomState;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::hash::{BuildHasher, Hash, Hasher};
use std::iter::{FromIterator, FusedIterator};
use std::marker::PhantomData;
use std::{fmt, mem, ops, ptr, vec};
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use core::convert::TryFrom;
use core::hash::{BuildHasher, Hash, Hasher};
use core::iter::{FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::{fmt, mem, ops, ptr};
#[cfg(feature = "std")]
use std::collections::{hash_map::RandomState, HashMap};
#[cfg(not(feature = "std"))]
use {ahash::RandomState, hashbrown::HashMap};

use crate::Error;

Expand Down Expand Up @@ -116,7 +121,7 @@ pub struct IntoIter<T> {
/// associated value.
#[derive(Debug)]
pub struct Keys<'a, T> {
inner: ::std::slice::Iter<'a, Bucket<T>>,
inner: ::core::slice::Iter<'a, Bucket<T>>,
}

/// `HeaderMap` value iterator.
Expand Down Expand Up @@ -209,7 +214,7 @@ pub struct ValueIterMut<'a, T> {
#[derive(Debug)]
pub struct ValueDrain<'a, T> {
first: Option<T>,
next: Option<::std::vec::IntoIter<T>>,
next: Option<::alloc::vec::IntoIter<T>>,
lt: PhantomData<&'a mut HeaderMap<T>>,
}

Expand Down Expand Up @@ -3574,7 +3579,10 @@ impl fmt::Display for MaxSizeReached {
}
}

#[cfg(feature = "std")]
impl std::error::Error for MaxSizeReached {}
#[cfg(not(feature = "std"))]
impl core::error::Error for MaxSizeReached {}

// ===== impl Utils =====

Expand Down Expand Up @@ -3736,6 +3744,7 @@ mod into_header_name {

mod as_header_name {
use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName, MaxSizeReached};
use alloc::string::String;

/// A marker trait used to identify values that can be used as search keys
/// to a `HeaderMap`.
Expand Down
19 changes: 12 additions & 7 deletions src/header/name.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
use crate::byte_str::ByteStr;
use bytes::{Bytes, BytesMut};

use std::borrow::Borrow;
use std::convert::TryFrom;
use alloc::string::String;
use alloc::vec::Vec;
use core::borrow::Borrow;
use core::convert::TryFrom;
#[cfg(not(feature = "std"))]
use core::error::Error;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::mem::MaybeUninit;
use core::str::FromStr;
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem::MaybeUninit;
use std::str::FromStr;

/// Represents an HTTP header field name
///
Expand Down Expand Up @@ -89,7 +94,7 @@ macro_rules! standard_headers {
match *self {
// Safety: test_parse_standard_headers ensures these &[u8]s are &str-safe.
$(
StandardHeader::$konst => unsafe { std::str::from_utf8_unchecked( $name_bytes ) },
StandardHeader::$konst => unsafe { core::str::from_utf8_unchecked( $name_bytes ) },
)+
}
}
Expand Down
17 changes: 11 additions & 6 deletions src/header/value.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use bytes::{Bytes, BytesMut};

use std::convert::TryFrom;
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::TryFrom;
#[cfg(not(feature = "std"))]
use core::error::Error;
use core::fmt::Write;
use core::hash::{Hash, Hasher};
use core::str::FromStr;
use core::{cmp, fmt, str};
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt::Write;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::{cmp, fmt, str};

use crate::header::name::HeaderName;

Expand Down Expand Up @@ -234,7 +239,7 @@ impl HeaderValue {
}

fn from_shared(src: Bytes) -> Result<HeaderValue, InvalidHeaderValue> {
HeaderValue::try_from_generic(src, std::convert::identity)
HeaderValue::try_from_generic(src, core::convert::identity)
}

fn try_from_generic<T: AsRef<[u8]>, F: FnOnce(T) -> Bytes>(
Expand Down
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,10 +154,9 @@
//! ```
#![deny(warnings, missing_docs, missing_debug_implementations)]
#![cfg_attr(not(feature = "std"), no_std)]

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

#[cfg(test)]
#[macro_use]
Expand Down
14 changes: 10 additions & 4 deletions src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
use self::extension::{AllocatedExtension, InlineExtension};
use self::Inner::*;

use std::convert::TryFrom;
use core::convert::TryFrom;
#[cfg(not(feature = "std"))]
use core::error::Error;
use core::str::FromStr;
use core::{fmt, str};
#[cfg(feature = "std")]
use std::error::Error;
use std::str::FromStr;
use std::{fmt, str};

/// The Request Method (VERB)
///
Expand Down Expand Up @@ -306,7 +309,10 @@ impl Error for InvalidMethod {}

mod extension {
use super::InvalidMethod;
use std::str;
use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use core::str;

#[derive(Clone, PartialEq, Eq, Hash)]
// Invariant: the first self.1 bytes of self.0 are valid UTF-8.
Expand Down
6 changes: 3 additions & 3 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
//! }
//! ```
use std::any::Any;
use std::convert::TryInto;
use std::fmt;
use core::any::Any;
use core::convert::TryInto;
use core::fmt;

use crate::header::{HeaderMap, HeaderName, HeaderValue};
use crate::method::Method;
Expand Down
6 changes: 3 additions & 3 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
//! // ...
//! ```
use std::any::Any;
use std::convert::TryInto;
use std::fmt;
use core::any::Any;
use core::convert::TryInto;
use core::fmt;

use crate::header::{HeaderMap, HeaderName, HeaderValue};
use crate::status::StatusCode;
Expand Down
12 changes: 8 additions & 4 deletions src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@
//! assert!(StatusCode::OK.is_success());
//! ```
use std::convert::TryFrom;
use crate::alloc::borrow::ToOwned;
use core::convert::TryFrom;
#[cfg(not(feature = "std"))]
use core::error::Error;
use core::fmt;
use core::num::NonZeroU16;
use core::str::FromStr;
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;
use std::num::NonZeroU16;
use std::str::FromStr;

/// An HTTP status code (`status-code` in RFC 9110 et al.).
///
Expand Down
10 changes: 6 additions & 4 deletions src/uri/authority.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::convert::TryFrom;
use std::hash::{Hash, Hasher};
use std::str::FromStr;
use std::{cmp, fmt, str};
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::TryFrom;
use core::hash::{Hash, Hasher};
use core::str::FromStr;
use core::{cmp, fmt, str};

use bytes::Bytes;

Expand Down
2 changes: 1 addition & 1 deletion src/uri/builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::convert::TryInto;
use core::convert::TryInto;

use super::{Authority, Parts, PathAndQuery, Scheme};
use crate::Uri;
Expand Down
14 changes: 10 additions & 4 deletions src/uri/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,20 @@
//! ```
use crate::byte_str::ByteStr;
use std::convert::TryFrom;

use bytes::Bytes;

use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::TryFrom;
#[cfg(not(feature = "std"))]
use core::error::Error;
use core::fmt;
use core::hash::{Hash, Hasher};
use core::str::{self, FromStr};
#[cfg(feature = "std")]
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::str::{self, FromStr};

use self::scheme::Scheme2;

Expand Down
8 changes: 5 additions & 3 deletions src/uri/path.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::convert::TryFrom;
use std::str::FromStr;
use std::{cmp, fmt, hash, str};
use alloc::string::String;
use alloc::vec::Vec;
use core::convert::TryFrom;
use core::str::FromStr;
use core::{cmp, fmt, hash, str};

use bytes::Bytes;

Expand Down
2 changes: 1 addition & 1 deletion src/uri/port.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::fmt;
use core::fmt;

use super::{ErrorKind, InvalidUri};

Expand Down
Loading

0 comments on commit ef5d9d6

Please sign in to comment.