Skip to content

Instantly share code, notes, and snippets.

@Alxandr
Last active November 2, 2024 23:07
Show Gist options
  • Save Alxandr/cc67b910230ce9926b90cefde7d9f76d to your computer and use it in GitHub Desktop.
Save Alxandr/cc67b910230ce9926b90cefde7d9f76d to your computer and use it in GitHub Desktop.
headers
#[repr(C)]
#[derive(Portable)]
struct ArchivedHttpResponse {
/// The body of the response.
body: ArchivedBox<[u8]>,
/// The headers of the response.
headers: ArchivedBox<[(ArchivedHeaderName, ArchivedBox<[u8]>)]>,
/// The status code of the response.
status: u16_le,
/// The URL of the response.
url: ArchivedOptionBox<[u8]>,
/// HTTP response version
version: ArchivedHttpVersion,
}
struct HttpResponseResolver {
body: BoxResolver,
headers: BoxResolver,
url: OptionBoxResolver,
}
struct ResponseWrapper<'a>(&'a Response<Bytes>);
impl<'a> Archive for ResponseWrapper<'a> {
type Archived = ArchivedHttpResponse;
type Resolver = HttpResponseResolver;
fn resolve(&self, resolver: Self::Resolver, out: rkyv::Place<Self::Archived>) {
munge!(let ArchivedHttpResponse { body, headers, status, url, version } = out);
let len = u32::try_from(self.0.body().len()).expect("response body too large");
let len = u32_le::from_native(len);
ArchivedBox::resolve_from_raw_parts(resolver.body, len, body);
let len = u32::try_from(self.0.headers().len()).expect("response headers too large");
let len = u32_le::from_native(len);
ArchivedBox::resolve_from_raw_parts(resolver.headers, len, headers);
Archive::resolve(&self.0.status().as_u16(), (), status);
let url_value = self
.0
.extensions()
.get::<ResponseUrl>()
.map(|url| url.0.as_str().as_bytes());
ArchivedOptionBox::resolve_from_option(url_value, resolver.url, url);
ArchivedHttpVersion::resolve_from(self.0.version(), version);
}
}
impl<'a, S> Serialize<S> for ResponseWrapper<'a>
where
S: Writer + Allocator + Fallible,
S::Error: Source,
{
fn serialize(&self, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
let pos = serializer.pos();
serializer.write(self.0.body().as_ref())?;
let body = BoxResolver::from_pos(pos);
let headers = self.0.headers();
let headers =
SerVec::with_capacity(serializer, headers.len(), move |resolvers, serializer| {
for (name, value) in headers.iter() {
let name = headers::HeaderName::from(name);
let value = value.as_bytes();
let name_resolver = name.serialize(serializer)?;
let pos = serializer.pos();
serializer.write(value)?;
let value_resolver = BoxResolver::from_pos(pos);
let value_len = u32::try_from(value.len()).expect("response header value too large");
let value_len = u32_le::from_native(value_len);
resolvers.push((name, value_len, name_resolver, value_resolver));
}
let result = serializer.align_for::<(ArchivedHeaderName, ArchivedBox<[u8]>)>()?;
for (name, value_len, name_resolver, value_resolver) in resolvers.drain() {
// resolve the name
serializer.align_for::<ArchivedHeaderName>()?;
unsafe { serializer.resolve_aligned(&name, name_resolver) }?;
// resolve the value
let pos = serializer.align_for::<ArchivedBox<[u8]>>()?;
let mut resolved = mem::MaybeUninit::<ArchivedBox<[u8]>>::uninit();
// // SAFETY: `resolved` is properly aligned and valid for writes of
// // `size_of::<ArchivedBox<[u8]>>()` bytes.
unsafe {
resolved.as_mut_ptr().write_bytes(0, 1);
}
// // SAFETY: `resolved.as_mut_ptr()` points to a local zeroed
// // `MaybeUninit`, and so is properly aligned, dereferenceable, and all
// // of its bytes are initialized.
let out = unsafe { rkyv::Place::new_unchecked(pos, resolved.as_mut_ptr()) };
ArchivedBox::resolve_from_raw_parts(value_resolver, value_len, out);
serializer.write(out.as_slice())?;
}
Ok(BoxResolver::from_pos(result))
})??;
self.0.status().as_u16().serialize(serializer)?;
let url = match self
.0
.extensions()
.get::<ResponseUrl>()
.map(|url| url.0.as_str().as_bytes())
{
None => OptionBoxResolver::None,
Some(url) => {
let pos = serializer.pos();
serializer.write(url)?;
OptionBoxResolver::Some(BoxResolver::from_pos(pos))
}
};
Ok(HttpResponseResolver { body, headers, url })
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment