mirror of
https://github.com/openharmony/third_party_rust_http.git
synced 2026-07-19 14:43:33 -04:00
add conversions of integers into HeaderValue (#218)
Implements `From<uN> for HeaderValue`, where `uN` is a bunch of integer types. This allows converting a number easily and efficiently into a `HeaderValue`.
It's especially nice when combined with the request/response builders:
```rust
let res = Response::builder()
.header("content-length", my_str.len())
.body(my_str)?;
```
This commit is contained in:
@@ -24,6 +24,7 @@ categories = ["web-programming"]
|
||||
[dependencies]
|
||||
bytes = "0.4"
|
||||
fnv = "1.0.5"
|
||||
itoa = "0.4.1"
|
||||
|
||||
[dev-dependencies]
|
||||
indexmap = "1.0"
|
||||
|
||||
@@ -111,3 +111,34 @@ impl From<header::InvalidHeaderValueBytes> for Error {
|
||||
Error { inner: ErrorKind::HeaderValueShared(err) }
|
||||
}
|
||||
}
|
||||
|
||||
// A crate-private type until we can use !.
|
||||
//
|
||||
// Being crate-private, we should be able to swap the type out in a
|
||||
// backwards compatible way.
|
||||
pub enum Never {}
|
||||
|
||||
impl From<Never> for Error {
|
||||
fn from(never: Never) -> Error {
|
||||
match never {}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Never {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Never {
|
||||
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Never {
|
||||
fn description(&self) -> &str {
|
||||
match *self {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+88
-2
@@ -1,10 +1,11 @@
|
||||
use bytes::Bytes;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
|
||||
use std::{cmp, fmt, str};
|
||||
use std::{cmp, fmt, mem, str};
|
||||
use std::error::Error;
|
||||
use std::str::FromStr;
|
||||
|
||||
use ::convert::HttpTryFrom;
|
||||
use ::error::Never;
|
||||
use header::name::HeaderName;
|
||||
|
||||
/// Represents an HTTP header field value.
|
||||
@@ -359,6 +360,91 @@ impl From<HeaderName> for HeaderValue {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! from_integers {
|
||||
($($name:ident: $t:ident => $max_len:expr),*) => {$(
|
||||
impl From<$t> for HeaderValue {
|
||||
fn from(num: $t) -> HeaderValue {
|
||||
let mut buf = if mem::size_of::<BytesMut>() - 1 < $max_len {
|
||||
// On 32bit platforms, BytesMut max inline size
|
||||
// is 15 bytes, but the $max_len could be bigger.
|
||||
//
|
||||
// The likelihood of the number *actually* being
|
||||
// that big is very small, so only allocate
|
||||
// if the number needs that space.
|
||||
//
|
||||
// The largest decimal number in 15 digits:
|
||||
// It wold be 10.pow(15) - 1, but this is a constant
|
||||
// version.
|
||||
if num as u64 > 999_999_999_999_999_999 {
|
||||
BytesMut::with_capacity($max_len)
|
||||
} else {
|
||||
// fits inline...
|
||||
BytesMut::new()
|
||||
}
|
||||
} else {
|
||||
// full value fits inline, so don't allocate!
|
||||
BytesMut::new()
|
||||
};
|
||||
let _ = ::itoa::fmt(&mut buf, num);
|
||||
HeaderValue {
|
||||
inner: buf.freeze(),
|
||||
is_sensitive: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HttpTryFrom<$t> for HeaderValue {
|
||||
type Error = Never;
|
||||
|
||||
#[inline]
|
||||
fn try_from(num: $t) -> Result<Self, Self::Error> {
|
||||
Ok(num.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn $name() {
|
||||
let n: $t = 55;
|
||||
let val = HeaderValue::from(n);
|
||||
assert_eq!(val, &n.to_string());
|
||||
|
||||
let n = ::std::$t::MAX;
|
||||
let val = HeaderValue::from(n);
|
||||
assert_eq!(val, &n.to_string());
|
||||
}
|
||||
)*};
|
||||
}
|
||||
|
||||
from_integers! {
|
||||
// integer type => maximum decimal length
|
||||
|
||||
// u8 purposely left off... HeaderValue::from(b'3') could be confusing
|
||||
from_u16: u16 => 5,
|
||||
from_i16: i16 => 6,
|
||||
from_u32: u32 => 10,
|
||||
from_i32: i32 => 11,
|
||||
from_u64: u64 => 20,
|
||||
from_i64: i64 => 20
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
from_integers! {
|
||||
from_usize: usize => 5,
|
||||
from_isize: isize => 6
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
from_integers! {
|
||||
from_usize: usize => 10,
|
||||
from_isize: isize => 11
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
from_integers! {
|
||||
from_usize: usize => 20,
|
||||
from_isize: isize => 20
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod from_header_name_tests {
|
||||
use super::*;
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
|
||||
extern crate bytes;
|
||||
extern crate fnv;
|
||||
extern crate itoa;
|
||||
|
||||
pub mod header;
|
||||
pub mod method;
|
||||
|
||||
@@ -608,6 +608,7 @@ impl Builder {
|
||||
/// let response = Response::builder()
|
||||
/// .header("Content-Type", "text/html")
|
||||
/// .header("X-Custom-Foo", "bar")
|
||||
/// .header("content-length", 0)
|
||||
/// .body(())
|
||||
/// .unwrap();
|
||||
/// ```
|
||||
|
||||
Reference in New Issue
Block a user