use core::{convert::Infallible, ops};
use state::{complete, decode, fixed};
use crate::field::{
head,
metadata::{
block,
map::record,
packed, section,
section::{state, storage},
},
};
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
#[doc(hidden)]
#[derive(Debug)]
pub enum Kind {
Request,
Response,
RequestTrailers,
ResponseTrailers,
PushPromise,
}
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
#[doc(hidden)]
pub enum Retention {
Retain,
Discard,
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[doc(hidden)]
pub enum Inspect {
Method,
}
pub trait Push {
const SCHEMES: Option<&'static [&'static [u8]]>;
const AUTHORITIES: Option<&'static [&'static [u8]]>;
fn is_scheme(value: record::Span<'_>) -> bool {
Self::SCHEMES.is_none_or(|allowed| allowed.iter().any(|expected| value.is_equal(expected)))
}
fn is_authority(value: record::Span<'_>) -> bool {
Self::AUTHORITIES
.is_none_or(|allowed| allowed.iter().any(|expected| value.is_equal(expected)))
}
}
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct RejectPush;
impl Push for RejectPush {
const SCHEMES: Option<&'static [&'static [u8]]> = Some(&[]);
const AUTHORITIES: Option<&'static [&'static [u8]]> = Some(&[]);
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Disposition<I = Infallible> {
Discard,
#[doc(hidden)]
Inspect(I),
Tagged(storage::Tag),
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[doc(hidden)]
pub enum Decision<I = Infallible> {
Discard(head::Name),
Inspect(I, head::Name),
Skip,
Scratch,
Tagged(head::Name, storage::Tag),
}
#[derive(Clone, Copy, PartialEq, Eq)]
#[doc(hidden)]
pub enum Store {
Scratch,
Tagged(storage::Tag),
}
pub struct Candidate<'a, P: ?Sized> {
policy: &'a mut P,
name: record::Span<'a>,
known: head::Name,
}
pub struct Observation<'a, P: ?Sized> {
policy: &'a mut P,
field: record::View<'a>,
retained: &'a [u8],
}
pub struct Commit<'a, P: ?Sized> {
policy: &'a mut P,
tag: storage::Tag,
range: ops::Range<usize>,
retained: &'a [u8],
}
impl<'a, P: ?Sized> Candidate<'a, P> {
pub(super) fn new(policy: &'a mut P, name: record::Span<'a>, known: head::Name) -> Self {
Self {
policy,
name,
known,
}
}
pub fn name(&self) -> record::Span<'a> {
self.name
}
pub fn identify(&self) -> (record::Span<'a>, head::Name) {
(self.name, self.known)
}
pub fn classify(self) -> (&'a mut P, record::Span<'a>, head::Name) {
(self.policy, self.name, self.known)
}
}
impl<'a, P: ?Sized> Observation<'a, P> {
pub(super) fn new(policy: &'a mut P, field: record::View<'a>, retained: &'a [u8]) -> Self {
Self {
policy,
field,
retained,
}
}
pub fn into_parts(self) -> (&'a mut P, record::View<'a>, &'a [u8]) {
(self.policy, self.field, self.retained)
}
}
impl<'a, P: ?Sized> Commit<'a, P> {
pub(super) fn new(
policy: &'a mut P,
tag: storage::Tag,
range: ops::Range<usize>,
retained: &'a [u8],
) -> Self {
Self {
policy,
tag,
range,
retained,
}
}
pub fn into_parts(self) -> (&'a mut P, storage::Tag, ops::Range<usize>, &'a [u8]) {
(self.policy, self.tag, self.range, self.retained)
}
pub fn store(self) -> (&'a mut P, storage::Tag, ops::Range<usize>) {
(self.policy, self.tag, self.range)
}
}
pub trait Policy: section::Policy {
#[doc(hidden)]
type State: decode::Sink<Self> + complete::Sink<Self>;
}
pub trait Validate {
fn value(&mut self, check: block::Validation);
}
pub trait Plan: section::Policy<Block = storage::Fields> + Default {
type Inspect: Copy;
const SKIP_DISCARDED: bool;
fn disposition(input: Candidate<'_, Self>) -> Disposition<Self::Inspect>;
fn inspect(token: Self::Inspect, input: Observation<'_, Self>) -> block::Validation;
fn commit(input: Commit<'_, Self>) -> block::Validation;
}
impl<P: Plan> Policy for P {
type State = state::Decoder<P>;
}
#[derive(Clone, Copy, Default)]
pub struct RetainRaw<const PREFIX: usize = 0>;
impl<const PREFIX: usize> section::Policy for RetainRaw<PREFIX> {
type Selection = ();
type Block = packed::Decoded<o3::buffer::pool::Span, PREFIX>;
fn finish(self) -> Self::Selection {
match self {
Self => (),
}
}
}
impl<const PREFIX: usize> Policy for RetainRaw<PREFIX> {
type State = fixed::Raw;
}
#[derive(Clone, Copy, Default)]
pub struct Discard;
impl section::Policy for Discard {
type Selection = ();
type Block = storage::Fields;
fn finish(self) -> Self::Selection {
match self {
Self => (),
}
}
}
impl Policy for Discard {
type State = fixed::Discard;
}
const _: () = {
assert!(core::mem::size_of::<RejectPush>() == 0);
assert!(core::mem::size_of::<Retention>() == 1);
assert!(core::mem::size_of::<Store>() == core::mem::size_of::<Decision>());
};