fire_http/extractor/
mod.rs

1use std::convert::Infallible;
2use std::error::Error as StdError;
3use std::fmt;
4use std::pin::Pin;
5use std::str::FromStr;
6use std::{future::Future, ops::Deref};
7
8use types::header::RequestHeader;
9
10use crate::error::{ClientErrorKind, ErrorKind, ServerErrorKind};
11use crate::state::StateValidation;
12use crate::{
13	routes::{ParamsNames, PathParams},
14	state::State,
15	Request, Resources,
16};
17
18#[non_exhaustive]
19pub struct Validate<'a> {
20	pub name: &'a str,
21	pub params: &'a ParamsNames<'a>,
22	pub state: &'a mut StateValidation,
23	pub resources: &'a Resources,
24}
25
26#[non_exhaustive]
27pub struct Prepare<'a> {
28	pub name: &'a str,
29	pub header: &'a RequestHeader,
30	pub params: &'a PathParams,
31	pub state: &'a mut State,
32	pub resources: &'a Resources,
33}
34
35#[non_exhaustive]
36pub struct Extract<'a, 'b, P, R> {
37	pub prepared: P,
38	pub name: &'b str,
39	pub request: &'b mut Option<R>,
40	pub params: &'a PathParams,
41	pub state: &'a State,
42	pub resources: &'a Resources,
43}
44
45pub trait Extractor<'a, R> {
46	type Error: ExtractorError;
47	type Prepared;
48
49	fn validate(validate: Validate<'_>);
50
51	fn prepare(
52		prepare: Prepare<'_>,
53	) -> Pin<
54		Box<
55			dyn Future<Output = Result<Self::Prepared, Self::Error>>
56				+ Send
57				+ '_,
58		>,
59	>;
60
61	fn extract(
62		extract: Extract<'a, '_, Self::Prepared, R>,
63	) -> Result<Self, Self::Error>
64	where
65		Self: Sized;
66}
67
68pub trait ExtractorError: StdError + Send + Sync {
69	fn error_kind(&self) -> ErrorKind;
70
71	fn into_std(self) -> Box<dyn StdError + Send + Sync>;
72}
73
74impl ExtractorError for Infallible {
75	fn error_kind(&self) -> ErrorKind {
76		unreachable!()
77	}
78
79	fn into_std(self) -> Box<dyn StdError + Send + Sync> {
80		unreachable!()
81	}
82}
83
84#[derive(Debug)]
85pub struct InternalError<E>(pub E);
86
87impl<E> ExtractorError for InternalError<E>
88where
89	E: Into<Box<dyn StdError + Send + Sync>> + StdError + Send + Sync,
90{
91	fn error_kind(&self) -> ErrorKind {
92		ServerErrorKind::InternalServerError.into()
93	}
94
95	fn into_std(self) -> Box<dyn StdError + Send + Sync> {
96		self.0.into()
97	}
98}
99
100impl<E> StdError for InternalError<E> where E: StdError {}
101
102impl<E> fmt::Display for InternalError<E>
103where
104	E: fmt::Display,
105{
106	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
107		self.0.fmt(f)
108	}
109}
110
111impl<E> From<E> for InternalError<E> {
112	fn from(e: E) -> Self {
113		Self(e)
114	}
115}
116
117impl<'a> Validate<'a> {
118	pub fn new(
119		name: &'a str,
120		params: &'a ParamsNames<'a>,
121		state: &'a mut StateValidation,
122		resources: &'a Resources,
123	) -> Self {
124		Self {
125			name,
126			params,
127			state,
128			resources,
129		}
130	}
131}
132
133impl<'a> Prepare<'a> {
134	pub fn new(
135		name: &'a str,
136		header: &'a RequestHeader,
137		params: &'a PathParams,
138		state: &'a mut State,
139		resources: &'a Resources,
140	) -> Self {
141		Self {
142			name,
143			header,
144			params,
145			state,
146			resources,
147		}
148	}
149}
150
151impl<'a, 'b, P, R> Extract<'a, 'b, P, R> {
152	pub fn new(
153		prepared: P,
154		name: &'b str,
155		request: &'b mut Option<R>,
156		params: &'a PathParams,
157		state: &'a State,
158		resources: &'a Resources,
159	) -> Self {
160		Self {
161			prepared,
162			name,
163			request,
164			params,
165			state,
166			resources,
167		}
168	}
169}
170
171pub struct Res<'a, T: ?Sized>(&'a T);
172
173impl<'a, T, R> Extractor<'a, R> for Res<'a, T>
174where
175	T: Send + Sync + 'static,
176{
177	type Error = Infallible;
178	type Prepared = ();
179
180	extractor_validate!(|validate| {
181		validate.resources.get::<T>().unwrap();
182	});
183
184	extractor_prepare!();
185
186	extractor_extract!(|extract| {
187		Ok(Res(extract.resources.get::<T>().unwrap()))
188	});
189}
190
191impl<T> Deref for Res<'_, T> {
192	type Target = T;
193
194	fn deref(&self) -> &Self::Target {
195		self.0
196	}
197}
198
199impl<'a> Extractor<'a, &'a mut Request> for &'a mut Request {
200	type Error = Infallible;
201	type Prepared = ();
202
203	extractor_validate!();
204
205	extractor_prepare!();
206
207	fn extract(
208		extract: Extract<'a, '_, Self::Prepared, &'a mut Request>,
209	) -> Result<Self, Self::Error>
210	where
211		Self: Sized,
212	{
213		Ok(extract.request.take().unwrap())
214	}
215}
216
217impl<'a, R> Extractor<'a, R> for &'a RequestHeader {
218	type Error = Infallible;
219	type Prepared = ();
220
221	extractor_validate!();
222
223	extractor_prepare!(|prepare| {
224		if !prepare.state.contains::<RequestHeader>() {
225			prepare
226				.state
227				.insert::<RequestHeader>(prepare.header.clone());
228		}
229
230		Ok(())
231	});
232
233	extractor_extract!(|extract| { Ok(extract.state.get().unwrap()) });
234}
235
236pub type PathStr = PathParam<str>;
237
238#[derive(Debug, Clone, PartialEq, Eq)]
239#[repr(transparent)]
240pub struct PathParam<T: ?Sized>(T);
241
242impl<'a, T, R> Extractor<'a, R> for PathParam<T>
243where
244	T: Send + Sync + FromStr + 'a,
245	T::Err: StdError + Send + Sync + 'static,
246{
247	type Error = PathError<T::Err>;
248	type Prepared = ();
249
250	extractor_validate!(|validate| {
251		assert!(
252			validate.params.exists(validate.name),
253			"Path parameter `{}` does not exist",
254			validate.name
255		);
256	});
257
258	extractor_prepare!();
259
260	extractor_extract!(|extract| {
261		extract
262			.params
263			.parse(extract.name)
264			.map(PathParam)
265			.map_err(PathError)
266	});
267}
268
269impl<'a, R> Extractor<'a, R> for &'a PathParam<str> {
270	type Error = Infallible;
271	type Prepared = ();
272
273	extractor_validate!(|validate| {
274		assert!(
275			validate.params.exists(validate.name),
276			"Path parameter `{}` does not exist",
277			validate.name
278		);
279	});
280
281	extractor_prepare!();
282
283	extractor_extract!(|extract| {
284		let s = extract.params.get(extract.name).unwrap();
285
286		// safe because `PathParam` is `repr(transparent)`
287		let s: &'a PathParam<str> =
288			unsafe { &*(s as *const str as *const PathParam<str>) };
289
290		Ok(s)
291	});
292}
293
294impl<T> Deref for PathParam<T>
295where
296	T: ?Sized,
297{
298	type Target = T;
299
300	fn deref(&self) -> &Self::Target {
301		&self.0
302	}
303}
304
305impl<T> fmt::Display for PathParam<T>
306where
307	T: fmt::Display + ?Sized,
308{
309	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
310		self.0.fmt(f)
311	}
312}
313
314#[derive(Debug)]
315pub struct PathError<T>(pub T);
316
317impl<T> fmt::Display for PathError<T>
318where
319	T: fmt::Display,
320{
321	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322		write!(f, "Failed to parse path parameter: {}", self.0)
323	}
324}
325
326impl<T> StdError for PathError<T>
327where
328	T: StdError + 'static,
329{
330	fn source(&self) -> Option<&(dyn StdError + 'static)> {
331		Some(&self.0)
332	}
333}
334
335impl<T> ExtractorError for PathError<T>
336where
337	T: StdError + Send + Sync + 'static,
338{
339	fn error_kind(&self) -> ErrorKind {
340		ErrorKind::Client(ClientErrorKind::BadRequest)
341	}
342
343	fn into_std(self) -> Box<dyn StdError + Send + Sync> {
344		Box::new(self.0)
345	}
346}
347
348impl<'a, R: 'a> Extractor<'a, R> for &'a Resources {
349	type Error = Infallible;
350	type Prepared = ();
351
352	extractor_validate!();
353
354	extractor_prepare!();
355
356	extractor_extract!(|extract| { Ok(extract.resources) });
357}