1use core::convert::Infallible;
3type Opened<S, B, E> = Result<(S, B), (OpenError<E>, B)>;
4use sark_http::{field::metadata::block, payload::owned};
5
6pub mod admit;
7pub mod input;
8pub mod machine;
9
10use crate::{
11 decode,
12 decode::{exec, request::Admitted},
13 request, route,
14};
15
16pub enum Shape {}
18
19#[repr(u8)]
21pub enum OpenError<E> {
22 InvalidRequest(E),
23 Length,
24 Unsupported,
25}
26
27#[derive(Clone, Copy, PartialEq, Eq)]
29#[repr(u8)]
30pub enum Directive {
31 Wait,
32 Activate,
33 FinishOutput,
34 FinishSession,
35}
36
37#[must_use = "return this output action to the duplex machine"]
38pub struct Action<'d> {
39 output: Option<owned::Segments<'d>>,
40 directive: Directive,
41}
42
43impl<'d> Action<'d> {
44 pub const fn idle() -> Self {
45 Self {
46 output: None,
47 directive: Directive::Wait,
48 }
49 }
50
51 pub fn send(output: impl Into<owned::Segments<'d>>) -> Self {
52 Self {
53 output: Some(output.into()),
54 directive: Directive::Wait,
55 }
56 }
57
58 pub const fn end() -> Self {
59 Self {
60 output: None,
61 directive: Directive::FinishOutput,
62 }
63 }
64
65 pub fn send_end(output: impl Into<owned::Segments<'d>>) -> Self {
66 Self {
67 output: Some(output.into()),
68 directive: Directive::FinishOutput,
69 }
70 }
71
72 pub const fn close() -> Self {
73 Self {
74 output: None,
75 directive: Directive::FinishSession,
76 }
77 }
78
79 pub fn send_close(output: impl Into<owned::Segments<'d>>) -> Self {
80 Self {
81 output: Some(output.into()),
82 directive: Directive::FinishSession,
83 }
84 }
85
86 pub const fn activate(mut self) -> Self {
87 if matches!(self.directive, Directive::Wait | Directive::Activate) {
88 self.directive = Directive::Activate;
89 }
90 self
91 }
92
93 fn into_parts(self) -> (Option<owned::Segments<'d>>, Directive) {
94 (self.output, self.directive)
95 }
96}
97
98pub trait Session<'d> {
100 fn receive(
101 &mut self,
102 input: owned::Segments<'d>,
103 output: &mut [u8],
104 scratch: &mut Vec<u8>,
105 ) -> (usize, Action<'d>);
106
107 fn finish(&mut self, output: &mut [u8], scratch: &mut Vec<u8>) -> (usize, Action<'d>);
109
110 fn activate(&mut self, output: &mut [u8], scratch: &mut Vec<u8>) -> (usize, Action<'d>);
111}
112
113pub enum Never {}
115
116impl<'d> Session<'d> for Never {
117 fn receive(
118 &mut self,
119 _: owned::Segments<'d>,
120 _: &mut [u8],
121 _: &mut Vec<u8>,
122 ) -> (usize, Action<'d>) {
123 match *self {}
124 }
125
126 fn finish(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, Action<'d>) {
127 match *self {}
128 }
129
130 fn activate(&mut self, _: &mut [u8], _: &mut Vec<u8>) -> (usize, Action<'d>) {
131 match *self {}
132 }
133}
134
135pub trait Application<'d>: decode::Decode {
137 type Duplex: Session<'d>;
138
139 const CONNECT: block::Connect = block::Connect::Disabled;
141
142 fn try_open<B>(
143 &self,
144 req: Admitted<exec::Duplex, Self::Prepared, B>,
145 ) -> Opened<Self::Duplex, B, Self::Error<'d>>;
146}
147
148pub trait Route<'state, State>: route::Spec<Kind = Shape> {
150 type Session: 'state;
151
152 fn open<'req, 'd>(
153 params: <Self::Request as route::Project>::Params<'req>,
154 req: &request::View<'req, 'd, <Self::Request as route::Schema>::Frame>,
155 head: <Self::Request as route::Project>::Headers<'req>,
156 body: <Self::Request as route::Project>::ParsedBody<'req, 'd>,
157 state: &'state State,
158 ) -> Self::Session
159 where
160 'd: 'req + 'state,
161 Self::Session: Session<'d>;
162}
163
164const _: () = {
165 assert!(core::mem::size_of::<OpenError<Infallible>>() == core::mem::size_of::<u8>());
166 assert!(
167 core::mem::size_of::<Action<'static>>()
168 <= core::mem::size_of::<Option<owned::Segments<'static>>>()
169 + core::mem::size_of::<usize>()
170 );
171};