diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 365a11e2..6b4f37d5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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] diff --git a/Cargo.toml b/Cargo.toml index 1a6e9c9d..b8ae6305 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/README.md b/README.md index a0090032..4f1e0c4f 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/byte_str.rs b/src/byte_str.rs index 90872ecb..28bf679b 100644 --- a/src/byte_str.rs +++ b/src/byte_str.rs @@ -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 { diff --git a/src/convert.rs b/src/convert.rs index 682e0ed5..633c0568 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -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::>() .unwrap() .take() diff --git a/src/error.rs b/src/error.rs index 762ee1c2..225b3317 100644 --- a/src/error.rs +++ b/src/error.rs @@ -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; @@ -132,8 +135,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: std::convert::Infallible) -> Error { +impl From for Error { + fn from(err: core::convert::Infallible) -> Error { match err {} } } diff --git a/src/extensions.rs b/src/extensions.rs index f16d762e..7b007ece 100644 --- a/src/extensions.rs +++ b/src/extensions.rs @@ -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, BuildHasherDefault>; diff --git a/src/header/map.rs b/src/header/map.rs index ebbc5937..40adf206 100644 --- a/src/header/map.rs +++ b/src/header/map.rs @@ -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; @@ -116,7 +121,7 @@ pub struct IntoIter { /// associated value. #[derive(Debug)] pub struct Keys<'a, T> { - inner: ::std::slice::Iter<'a, Bucket>, + inner: ::core::slice::Iter<'a, Bucket>, } /// `HeaderMap` value iterator. @@ -209,7 +214,7 @@ pub struct ValueIterMut<'a, T> { #[derive(Debug)] pub struct ValueDrain<'a, T> { first: Option, - next: Option<::std::vec::IntoIter>, + next: Option<::alloc::vec::IntoIter>, lt: PhantomData<&'a mut HeaderMap>, } @@ -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 ===== @@ -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`. diff --git a/src/header/name.rs b/src/header/name.rs index 3d563f4e..013a586f 100644 --- a/src/header/name.rs +++ b/src/header/name.rs @@ -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 /// @@ -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 ) }, )+ } } diff --git a/src/header/value.rs b/src/header/value.rs index 99d1e155..ba6e8416 100644 --- a/src/header/value.rs +++ b/src/header/value.rs @@ -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; @@ -234,7 +239,7 @@ impl HeaderValue { } fn from_shared(src: Bytes) -> Result { - HeaderValue::try_from_generic(src, std::convert::identity) + HeaderValue::try_from_generic(src, core::convert::identity) } fn try_from_generic, F: FnOnce(T) -> Bytes>( diff --git a/src/lib.rs b/src/lib.rs index 0ab5bdfd..eac94bbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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] diff --git a/src/method.rs b/src/method.rs index 7b4584ab..d367c710 100644 --- a/src/method.rs +++ b/src/method.rs @@ -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) /// @@ -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. diff --git a/src/request.rs b/src/request.rs index 324b676c..be58fde9 100644 --- a/src/request.rs +++ b/src/request.rs @@ -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; diff --git a/src/response.rs b/src/response.rs index ab9e49bc..17f5d7f1 100644 --- a/src/response.rs +++ b/src/response.rs @@ -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; diff --git a/src/status.rs b/src/status.rs index 9ad04d20..6c472fb4 100644 --- a/src/status.rs +++ b/src/status.rs @@ -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.). /// diff --git a/src/uri/authority.rs b/src/uri/authority.rs index 07aa6795..fc7b9bcf 100644 --- a/src/uri/authority.rs +++ b/src/uri/authority.rs @@ -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; diff --git a/src/uri/builder.rs b/src/uri/builder.rs index d5f7f49b..d63cff73 100644 --- a/src/uri/builder.rs +++ b/src/uri/builder.rs @@ -1,4 +1,4 @@ -use std::convert::TryInto; +use core::convert::TryInto; use super::{Authority, Parts, PathAndQuery, Scheme}; use crate::Uri; diff --git a/src/uri/mod.rs b/src/uri/mod.rs index 767f0743..8b2ab57b 100644 --- a/src/uri/mod.rs +++ b/src/uri/mod.rs @@ -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; diff --git a/src/uri/path.rs b/src/uri/path.rs index df00c415..c8aa0ee3 100644 --- a/src/uri/path.rs +++ b/src/uri/path.rs @@ -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; diff --git a/src/uri/port.rs b/src/uri/port.rs index 2a7028e2..db23ab81 100644 --- a/src/uri/port.rs +++ b/src/uri/port.rs @@ -1,4 +1,4 @@ -use std::fmt; +use core::fmt; use super::{ErrorKind, InvalidUri}; diff --git a/src/uri/scheme.rs b/src/uri/scheme.rs index dbcc8c3f..584794de 100644 --- a/src/uri/scheme.rs +++ b/src/uri/scheme.rs @@ -1,7 +1,8 @@ -use std::convert::TryFrom; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::str::FromStr; +use alloc::boxed::Box; +use core::convert::TryFrom; +use core::fmt; +use core::hash::{Hash, Hasher}; +use core::str::FromStr; use bytes::Bytes; diff --git a/src/version.rs b/src/version.rs index d8b71306..436ca7df 100644 --- a/src/version.rs +++ b/src/version.rs @@ -19,7 +19,7 @@ //! println!("{:?}", http2); //! ``` -use std::fmt; +use core::fmt; /// Represents a version of the HTTP spec. #[derive(PartialEq, PartialOrd, Copy, Clone, Eq, Ord, Hash)]