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

wip: no_std #732

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ std = []
[dependencies]
bytes = "1"
fnv = "1.0.5"
hashbrown = "0.12.0"
Copy link
Author

Choose a reason for hiding this comment

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

not sure how to put this behind a no_std flag (replaces std::HashMap)

itoa = "1"

[dev-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion benches/src/header_map/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ macro_rules! bench {
use fnv::FnvHasher;
use http::header::*;
use seahash::SeaHasher;
use std::hash::BuildHasherDefault;

#[allow(unused_imports)]
use test::{self, Bencher};

Expand Down
9 changes: 5 additions & 4 deletions src/byte_str.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bytes::Bytes;
use core::ops;

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

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub(crate) struct ByteStr {
Expand Down Expand Up @@ -34,7 +35,7 @@ impl ByteStr {
/// behavior to call this with `bytes` that is not valid UTF-8.
pub unsafe fn from_utf8_unchecked(bytes: Bytes) -> ByteStr {
if cfg!(debug_assertions) {
match str::from_utf8(&bytes) {
match core::str::from_utf8(&bytes) {
Ok(_) => (),
Err(err) => panic!(
"ByteStr::from_utf8_unchecked() with invalid bytes; error = {}, bytes = {:?}",
Expand All @@ -54,7 +55,7 @@ impl ops::Deref for ByteStr {
fn deref(&self) -> &str {
let b: &[u8] = self.bytes.as_ref();
// Safety: the invariant of `bytes` is that it contains valid UTF-8.
unsafe { str::from_utf8_unchecked(b) }
unsafe { core::str::from_utf8_unchecked(b) }
}
}

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
31 changes: 19 additions & 12 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::error;
use std::fmt;
use std::result;
#![allow(dead_code)]

use core::convert;
use core::result;

use crate::header;
use crate::header::MaxSizeReached;
Expand All @@ -14,13 +15,15 @@ use crate::uri;
/// functions in this crate, but all other errors can be converted to this
/// error. Consumers of this crate can typically consume and work with this form
/// of error for conversions with the `?` operator.
#[derive(Debug)]
pub struct Error {
inner: ErrorKind,
}

/// A `Result` typedef to use with the `http::Error` type
pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
enum ErrorKind {
StatusCode(status::InvalidStatusCode),
Method(method::InvalidMethod),
Expand All @@ -31,7 +34,8 @@ enum ErrorKind {
MaxSizeReached(MaxSizeReached),
}

impl fmt::Debug for Error {
#[cfg(feature = "std")]
impl std::fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple("http::Error")
// Skip the noise of the ErrorKind enum
Expand All @@ -40,13 +44,15 @@ impl fmt::Debug for Error {
}
}

impl fmt::Display for Error {
#[cfg(feature = "std")]
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self.get_ref(), f)
}
}

impl Error {
#[cfg(feature = "std")]
impl std::error::Error for Error {
/// Return true if the underlying error has the same type as T.
pub fn is<T: error::Error + 'static>(&self) -> bool {
self.get_ref().is::<T>()
Expand All @@ -68,10 +74,11 @@ impl Error {
}
}

impl error::Error for Error {
#[cfg(feature = "std")]
impl std::error::Error for Error {
// Return any available cause from the inner error. Note the inner error is
// not itself the cause.
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.get_ref().source()
}
}
Expand Down Expand Up @@ -132,13 +139,13 @@ impl From<header::InvalidHeaderValue> for Error {
}
}

impl From<std::convert::Infallible> for Error {
fn from(err: std::convert::Infallible) -> Error {
impl From<convert::Infallible> for Error {
fn from(err: convert::Infallible) -> Error {
match err {}
}
}

#[cfg(test)]
/*#[cfg(test)]
mod tests {
use super::*;

Expand All @@ -157,4 +164,4 @@ mod tests {
panic!("Bad status allowed!");
}
}
}
}*/
8 changes: 4 additions & 4 deletions src/extensions.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::fmt;
use std::hash::{BuildHasherDefault, Hasher};
use core::{any::{Any, TypeId}, fmt, hash::{BuildHasherDefault, Hasher}};

use alloc::boxed::Box;
use hashbrown::HashMap;

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

Expand Down
38 changes: 19 additions & 19 deletions src/header/map.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
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 core::convert::TryFrom;
use core::iter::{FromIterator, FusedIterator};
use core::marker::PhantomData;
use core::{fmt, mem, ops, ptr, slice};
use core::hash::{Hash, Hasher};

use alloc::boxed::Box;
use alloc::vec;
use alloc::vec::Vec;
use hashbrown::HashMap;

use crate::Error;

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

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

Expand Down Expand Up @@ -316,7 +319,7 @@ enum Link {
enum Danger {
Green,
Yellow,
Red(RandomState),
Red, // TODO: no_std?
}

// Constants related to detecting DOS attacks.
Expand Down Expand Up @@ -520,7 +523,7 @@ impl<T> HeaderMap<T> {

Ok(HeaderMap {
mask: (raw_cap - 1) as Size,
indices: vec![Pos::none(); raw_cap].into_boxed_slice(),
indices: alloc::vec![Pos::none(); raw_cap].into_boxed_slice(),
entries: Vec::with_capacity(raw_cap),
extra_values: Vec::new(),
danger: Danger::Green,
Expand Down Expand Up @@ -3526,12 +3529,12 @@ impl Pos {

impl Danger {
fn is_red(&self) -> bool {
matches!(*self, Danger::Red(_))
matches!(*self, Danger::Red)
}

fn set_red(&mut self) {
debug_assert!(self.is_yellow());
*self = Danger::Red(RandomState::new());
*self = Danger::Red;
}

fn is_yellow(&self) -> bool {
Expand Down Expand Up @@ -3572,6 +3575,7 @@ impl fmt::Display for MaxSizeReached {
}
}

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

// ===== impl Utils =====
Expand Down Expand Up @@ -3612,12 +3616,6 @@ where
const MASK: u64 = (MAX_SIZE as u64) - 1;

let hash = match *danger {
// Safe hash
Danger::Red(ref hasher) => {
let mut h = hasher.build_hasher();
k.hash(&mut h);
h.finish()
}
// Fast hash
_ => {
let mut h = FnvHasher::default();
Expand Down Expand Up @@ -3733,6 +3731,8 @@ mod into_header_name {
}

mod as_header_name {
use alloc::string::String;

use super::{Entry, HdrName, HeaderMap, HeaderName, InvalidHeaderName, MaxSizeReached};

/// A marker trait used to identify values that can be used as search keys
Expand Down
29 changes: 14 additions & 15 deletions src/header/name.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
use core::{borrow::Borrow, convert::TryFrom, fmt, mem::MaybeUninit, str::FromStr};
use core::hash::{Hash, Hasher};

use crate::byte_str::ByteStr;
use alloc::{string::String, vec::Vec};
use bytes::{Bytes, BytesMut};

use std::borrow::Borrow;
use std::convert::TryFrom;
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
///
/// Header field names identify the header. Header sets may include multiple
Expand Down Expand Up @@ -89,7 +85,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 Expand Up @@ -118,15 +114,15 @@ macro_rules! standard_headers {
assert_eq!(HeaderName::from_bytes(name_bytes).unwrap(), HeaderName::from(std));

// Test upper case
let upper = std::str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase();
let upper = core::str::from_utf8(name_bytes).expect("byte string constants are all utf-8").to_uppercase();
assert_eq!(HeaderName::from_bytes(upper.as_bytes()).unwrap(), HeaderName::from(std));
}
}

#[test]
fn test_standard_headers_into_bytes() {
for &(std, name_bytes) in TEST_HEADERS {
let name = std::str::from_utf8(name_bytes).unwrap();
let name = core::str::from_utf8(name_bytes).unwrap();
let std = HeaderName::from(std);
// Test lower case
let bytes: Bytes =
Expand Down Expand Up @@ -1516,7 +1512,8 @@ impl fmt::Display for InvalidHeaderName {
}
}

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

// ===== HdrName =====

Expand Down Expand Up @@ -1668,11 +1665,13 @@ fn uninit_u8_array() -> [MaybeUninit<u8>; SCRATCH_BUF_SIZE] {
// Safety: All elements of `slice` must be initialized to prevent
// undefined behavior.
unsafe fn slice_assume_init<T>(slice: &[MaybeUninit<T>]) -> &[T] {
&*(slice as *const [MaybeUninit<T>] as *const [T])
unsafe { &*(slice as *const [MaybeUninit<T>] as *const [T]) }
}

#[cfg(test)]
mod tests {
use alloc::vec;

use self::StandardHeader::Vary;
use super::*;

Expand Down Expand Up @@ -1705,7 +1704,7 @@ mod tests {

let long = &ONE_TOO_LONG[0..super::super::MAX_HEADER_NAME_LEN];

let long_str = std::str::from_utf8(long).unwrap();
let long_str = core::str::from_utf8(long).unwrap();
assert_eq!(HeaderName::from_static(long_str), long_str); // shouldn't panic!

assert!(
Expand All @@ -1722,7 +1721,7 @@ mod tests {
#[should_panic]
fn test_static_invalid_name_lengths() {
// Safety: ONE_TOO_LONG contains only the UTF-8 safe, single-byte codepoint b'a'.
let _ = HeaderName::from_static(unsafe { std::str::from_utf8_unchecked(ONE_TOO_LONG) });
let _ = HeaderName::from_static(unsafe { core::str::from_utf8_unchecked(ONE_TOO_LONG) });
}

#[test]
Expand Down
Loading