use alloc::vec::Vec;
use core::net::{Ipv4Addr, Ipv6Addr};
use crate::{
etag::EntityTag,
host::{Host, HostPort},
limits::DuplicatePolicy,
media::MediaType,
param::Params,
};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct OwnedMediaType {
buf: Vec<u8>,
type_len: usize,
subtype_len: usize,
count: u32,
policy: DuplicatePolicy,
}
impl core::fmt::Debug for OwnedMediaType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
core::fmt::Debug::fmt(&self.as_view(), f)
}
}
impl MediaType<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedMediaType {
let mut buf =
Vec::with_capacity(self.type_.len() + self.subtype.len() + self.params.text.len());
buf.extend_from_slice(self.type_);
buf.extend_from_slice(self.subtype);
buf.extend_from_slice(self.params.text);
OwnedMediaType {
buf,
type_len: self.type_.len(),
subtype_len: self.subtype.len(),
count: self.params.count,
policy: self.params.policy,
}
}
}
impl OwnedMediaType {
#[must_use]
pub fn as_view(&self) -> MediaType<'_> {
let (type_, rest) = self.buf.split_at(self.type_len.min(self.buf.len()));
let (subtype, text) = rest.split_at(self.subtype_len.min(rest.len()));
MediaType {
type_,
subtype,
params: Params {
text,
count: self.count,
policy: self.policy,
},
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedEntityTag {
weak: bool,
opaque: Vec<u8>,
}
impl EntityTag<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedEntityTag {
OwnedEntityTag {
weak: self.weak,
opaque: self.opaque.to_vec(),
}
}
}
impl OwnedEntityTag {
#[must_use]
pub fn as_view(&self) -> EntityTag<'_> {
EntityTag {
weak: self.weak,
opaque: &self.opaque,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
enum Kind {
Name,
V4(Ipv4Addr),
V6(Ipv6Addr),
Future,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedHostPort {
kind: Kind,
text: Vec<u8>,
port: Option<u16>,
empty_port: bool,
}
impl HostPort<'_> {
#[must_use]
pub fn to_owned(&self) -> OwnedHostPort {
let (kind, text) = match self.host {
Host::Name(n) => (Kind::Name, n.to_vec()),
Host::V4(a) => (Kind::V4(a), Vec::new()),
Host::V6(a) => (Kind::V6(a), Vec::new()),
Host::Future(f) => (Kind::Future, f.to_vec()),
};
OwnedHostPort {
kind,
text,
port: self.port,
empty_port: self.empty_port,
}
}
}
impl OwnedHostPort {
#[must_use]
pub fn as_view(&self) -> HostPort<'_> {
let host = match self.kind {
Kind::Name => Host::Name(&self.text),
Kind::V4(a) => Host::V4(a),
Kind::V6(a) => Host::V6(a),
Kind::Future => Host::Future(&self.text),
};
HostPort {
host,
port: self.port,
empty_port: self.empty_port,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_owned_forms_give_the_same_view() {
for v in [
&b"text/html"[..],
b"multipart/form-data; boundary=\"a b\"; x=1",
b"a/b;",
] {
let m = crate::parse_media_type(v).unwrap();
assert_eq!(m.to_owned().as_view(), m);
}
for v in [&b"\"x\""[..], b"W/\"\"", b"\"\xff\""] {
let t = EntityTag::parse(v).unwrap();
assert_eq!(t.to_owned().as_view(), t);
}
for v in [
&b"a.example:1"[..],
b"[::1]",
b"192.0.2.1",
b"[v1.x]",
b"h:",
] {
let h = crate::parse_host_port(v).unwrap();
assert_eq!(h.to_owned().as_view(), h);
}
}
#[test]
fn test_owned_outlives_the_input() {
let owned = {
let input = b"Text/Plain; Charset=\"UTF-8\"".to_vec();
crate::parse_media_type(&input).unwrap().to_owned()
};
let v = owned.as_view();
assert!(v.is("text", "plain") && v.charset().unwrap().eq_ignore_ascii_case(b"utf-8"));
assert_eq!(v.params().len(), 1);
}
}