sark_http/h1/head/request/route/
mod.rs1use std::{num::NonZero, str};
2
3use o3::{buffer, buffer::write};
4use write::CopyError;
5
6use crate::{
7 h1::{field::expect, head::request::pool, switch},
8 request::{self, span},
9};
10
11mod line;
12
13pub(in crate::h1::head::request) use line::Line;
14
15#[derive(PartialEq, Eq)]
17pub struct Route<S> {
18 pub(in crate::h1::head::request) source: S,
19 pub(in crate::h1::head::request) line: Line,
20 pub(in crate::h1::head::request) end: NonZero<u32>,
21 pub(in crate::h1::head::request) offers: switch::Offers,
22}
23
24impl Copy for Route<&[u8]> {}
25
26impl Clone for Route<&[u8]> {
27 fn clone(&self) -> Self {
28 *self
29 }
30}
31
32impl<S> Route<S> {
33 pub(in crate::h1::head::request) const fn new(
34 source: S,
35 line: Line,
36 end: NonZero<u32>,
37 offers: switch::Offers,
38 ) -> Self {
39 Self {
40 source,
41 line,
42 end,
43 offers,
44 }
45 }
46
47 pub fn into_source(self) -> S {
48 self.source
49 }
50
51 pub fn transition(&self) -> switch::Intent {
52 self.line.transition()
53 }
54
55 pub fn take_expect(&mut self) -> expect::Decision {
56 self.line.take_expect()
57 }
58
59 pub const fn head_end(&self) -> NonZero<u32> {
60 self.end
61 }
62}
63
64impl<'d> Route<pool::Buf<'d>> {
65 pub fn seal(self) -> pool::Meta<'d> {
66 let route = self.as_ref();
67 let target = &route.line.target;
68 let layout = pool::Layout::new(
69 [
70 route.method().len() as u16,
71 target.start() as u16,
72 target.end() as u16,
73 self.end.get() as u16,
74 ],
75 route.transition(),
76 );
77 let mut bytes = self.source.bytes;
78 unsafe {
79 bytes
80 .as_mut_slice()
81 .get_unchecked_mut(..pool::Layout::BYTES)
82 .copy_from_slice(&layout.encode());
83 }
84 pool::Meta { bytes }
85 }
86}
87
88impl<S: buffer::raw::Source> Route<S> {
89 pub fn as_ref(&self) -> Route<&[u8]> {
90 Route {
91 source: self.source.as_ref(),
92 line: self.line,
93 end: self.end,
94 offers: self.offers,
95 }
96 }
97
98 pub fn try_copy<D>(&self, target: D) -> Result<Route<D>, (D, CopyError<D::Error>)>
99 where
100 D: buffer::raw::Source + write::Sink,
101 {
102 let target = write::try_copy(target, self.source.as_ref())?;
103 Ok(Route {
104 source: target,
105 line: self.line,
106 end: self.end,
107 offers: self.offers,
108 })
109 }
110}
111
112impl<S: write::Sink> Route<S> {
113 pub fn try_extend(&mut self, bytes: &[u8]) -> Result<(), S::Error> {
114 self.source.write_slice(bytes)
115 }
116}
117
118impl<'a> Route<&'a [u8]> {
119 pub const fn bytes(self) -> &'a [u8] {
120 self.source
121 }
122
123 pub fn body(self) -> &'a [u8] {
124 unsafe { self.source.get_unchecked(self.end.get() as usize..) }
125 }
126
127 pub fn method(self) -> &'a str {
128 self.text(self.line.method())
129 }
130
131 pub fn target(self) -> &'a str {
132 self.text(span::Span::from_target(self.line.target))
133 }
134
135 pub fn authority(self) -> &'a str {
136 self.text(self.line.auth)
137 }
138
139 pub fn route_path(self) -> Option<&'a str> {
140 match self.line.target.form() {
141 request::Form::Root => Some("/"),
142 request::Form::Asterisk | request::Form::Authority => Some("*"),
143 request::Form::Path | request::Form::Extended => {
144 self.line.route.map(|path| self.text(path))
145 }
146 }
147 }
148
149 fn text(self, span: span::Span) -> &'a str {
150 unsafe { str::from_utf8_unchecked(self.source.get_unchecked(span.start()..span.end())) }
151 }
152}
153
154const _: () = assert!(size_of::<Route<&[u8]>>() == 7 * size_of::<usize>());