#![allow(
missing_docs,
missing_debug_implementations,
missing_copy_implementations
)]
use crate::{HeaderName, HeaderValue, HeaderValues, Headers, Method, Status, Version};
use rkyv::{
Archive, Deserialize, Place, Serialize,
rancor::{Fallible, Source},
};
trait IntoPublic {
type Public;
fn into_public(self) -> Result<Self::Public, crate::Error>;
}
macro_rules! delegate_rkyv {
($public:ty => $mirror:ty) => {
impl Archive for $public {
type Archived = <$mirror as Archive>::Archived;
type Resolver = <$mirror as Archive>::Resolver;
fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
Archive::resolve(&<$mirror>::from(self), resolver, out);
}
}
impl<S: Fallible + ?Sized> Serialize<S> for $public
where
$mirror: Serialize<S>,
{
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
Serialize::serialize(&<$mirror>::from(self), serializer)
}
}
impl<D: Fallible + ?Sized> Deserialize<$public, D> for <$mirror as Archive>::Archived
where
<$mirror as Archive>::Archived: Deserialize<$mirror, D>,
D::Error: Source,
{
fn deserialize(&self, deserializer: &mut D) -> Result<$public, D::Error> {
let mirror = Deserialize::<$mirror, D>::deserialize(self, deserializer)?;
mirror.into_public().map_err(D::Error::new)
}
}
};
}
#[derive(Archive, Serialize, Deserialize)]
pub struct VersionMirror(u8);
impl From<&Version> for VersionMirror {
fn from(version: &Version) -> Self {
Self(match version {
Version::Http0_9 => 9,
Version::Http1_0 => 10,
Version::Http1_1 => 11,
Version::Http2 => 20,
Version::Http3 => 30,
})
}
}
impl IntoPublic for VersionMirror {
type Public = Version;
fn into_public(self) -> Result<Version, crate::Error> {
Ok(match self.0 {
9 => Version::Http0_9,
10 => Version::Http1_0,
11 => Version::Http1_1,
20 => Version::Http2,
30 => Version::Http3,
_ => return Err(crate::Error::InvalidVersion),
})
}
}
delegate_rkyv!(Version => VersionMirror);
#[derive(Archive, Serialize, Deserialize)]
pub struct StatusMirror(u16);
impl From<&Status> for StatusMirror {
fn from(status: &Status) -> Self {
Self((*status).into())
}
}
impl IntoPublic for StatusMirror {
type Public = Status;
fn into_public(self) -> Result<Status, crate::Error> {
Status::try_from(self.0)
}
}
delegate_rkyv!(Status => StatusMirror);
#[derive(Archive, Serialize, Deserialize)]
pub struct MethodMirror(String);
impl From<&Method> for MethodMirror {
fn from(method: &Method) -> Self {
Self(method.as_str().to_string())
}
}
impl IntoPublic for MethodMirror {
type Public = Method;
fn into_public(self) -> Result<Method, crate::Error> {
self.0.parse()
}
}
delegate_rkyv!(Method => MethodMirror);
#[derive(Archive, Serialize, Deserialize)]
pub struct HeaderNameMirror(String);
impl From<&HeaderName<'_>> for HeaderNameMirror {
fn from(name: &HeaderName<'_>) -> Self {
Self(name.as_ref().to_string())
}
}
impl IntoPublic for HeaderNameMirror {
type Public = HeaderName<'static>;
fn into_public(self) -> Result<HeaderName<'static>, crate::Error> {
Ok(HeaderName::from(self.0))
}
}
delegate_rkyv!(HeaderName<'static> => HeaderNameMirror);
#[derive(Archive, Serialize, Deserialize)]
pub enum HeaderValueRepr {
Utf8(String),
Bytes(Vec<u8>),
}
#[derive(Archive, Serialize, Deserialize)]
pub struct HeaderValueMirror {
value: HeaderValueRepr,
never_indexed: bool,
}
impl From<&HeaderValue> for HeaderValueMirror {
fn from(value: &HeaderValue) -> Self {
let repr = match value.as_str() {
Some(utf8) => HeaderValueRepr::Utf8(utf8.to_string()),
None => HeaderValueRepr::Bytes(value.as_ref().to_vec()),
};
Self {
value: repr,
never_indexed: value.is_never_indexed(),
}
}
}
impl IntoPublic for HeaderValueMirror {
type Public = HeaderValue;
fn into_public(self) -> Result<HeaderValue, crate::Error> {
let mut value = match self.value {
HeaderValueRepr::Utf8(utf8) => HeaderValue::from(utf8),
HeaderValueRepr::Bytes(bytes) => HeaderValue::from(bytes),
};
value.set_never_indexed(self.never_indexed);
Ok(value)
}
}
delegate_rkyv!(HeaderValue => HeaderValueMirror);
#[derive(Archive, Serialize, Deserialize)]
pub struct HeaderValuesMirror(Vec<HeaderValueMirror>);
impl From<&HeaderValues> for HeaderValuesMirror {
fn from(values: &HeaderValues) -> Self {
Self(values.iter().map(HeaderValueMirror::from).collect())
}
}
impl IntoPublic for HeaderValuesMirror {
type Public = HeaderValues;
fn into_public(self) -> Result<HeaderValues, crate::Error> {
let values = self
.0
.into_iter()
.map(IntoPublic::into_public)
.collect::<Result<Vec<HeaderValue>, _>>()?;
Ok(HeaderValues::from(values))
}
}
delegate_rkyv!(HeaderValues => HeaderValuesMirror);
#[derive(Archive, Serialize, Deserialize)]
pub struct HeadersMirror(Vec<(HeaderNameMirror, HeaderValuesMirror)>);
impl From<&Headers> for HeadersMirror {
fn from(headers: &Headers) -> Self {
Self(
headers
.iter()
.map(|(name, values)| {
(
HeaderNameMirror::from(&name),
HeaderValuesMirror::from(values),
)
})
.collect(),
)
}
}
impl IntoPublic for HeadersMirror {
type Public = Headers;
fn into_public(self) -> Result<Headers, crate::Error> {
let entries = self
.0
.into_iter()
.map(|(name, values)| Ok((name.into_public()?, values.into_public()?)))
.collect::<Result<Vec<(HeaderName<'static>, HeaderValues)>, crate::Error>>()?;
Ok(Headers::from_iter(entries))
}
}
delegate_rkyv!(Headers => HeadersMirror);
#[cfg(test)]
mod test {
use crate::{HeaderValue, Headers, KnownHeaderName, Method, Status, Version};
use rkyv::rancor::Error;
macro_rules! assert_roundtrips {
($value:expr, $ty:ty) => {{
let value: $ty = $value;
let bytes = rkyv::to_bytes::<Error>(&value).unwrap();
let restored = rkyv::from_bytes::<$ty, Error>(&bytes).unwrap();
assert_eq!(restored, value);
}};
}
#[test]
fn version_roundtrips() {
for version in [
Version::Http0_9,
Version::Http1_0,
Version::Http1_1,
Version::Http2,
Version::Http3,
] {
assert_roundtrips!(version, Version);
}
}
#[test]
fn status_roundtrips() {
for status in [
Status::Ok,
Status::ImATeapot,
Status::NotFound,
Status::Continue,
] {
assert_roundtrips!(status, Status);
}
}
#[test]
fn method_roundtrips() {
for method in [
Method::Get,
Method::Post,
Method::VersionControl,
Method::MkCalendar,
] {
assert_roundtrips!(method, Method);
}
}
#[test]
fn headers_roundtrip_all_variants() {
let mut headers = Headers::new();
headers.insert(KnownHeaderName::ContentType, "text/plain");
headers.insert("X-Custom-Thing", "hello");
headers.append(KnownHeaderName::SetCookie, "a=1");
headers.append(KnownHeaderName::SetCookie, "b=2");
let mut binary = HeaderValue::from(vec![0xff, 0xfe, 0x00, 0x01]);
binary.set_never_indexed(true);
headers.insert("X-Binary", binary);
assert_roundtrips!(headers.clone(), Headers);
let bytes = rkyv::to_bytes::<Error>(&headers).unwrap();
let restored = rkyv::from_bytes::<Headers, Error>(&bytes).unwrap();
assert!(restored.get("X-Binary").unwrap().is_never_indexed());
}
}