aide/impls/
mod.rs

1use std::{borrow::Cow, convert::Infallible, rc::Rc, sync::Arc};
2
3use crate::{
4    openapi::{MediaType, Operation, RequestBody, Response},
5    operation::set_body,
6    util::no_content_response,
7    OperationInput,
8};
9use indexmap::IndexMap;
10
11use crate::operation::OperationOutput;
12
13#[cfg(feature = "bytes")]
14mod bytes;
15
16#[cfg(feature = "http")]
17mod http;
18
19#[cfg(feature = "serde_qs")]
20mod serde_qs;
21
22impl<T, E> OperationInput for Result<T, E>
23where
24    T: OperationInput,
25{
26    fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
27        T::operation_input(ctx, operation);
28    }
29
30    fn inferred_early_responses(
31        ctx: &mut crate::generate::GenContext,
32        operation: &mut Operation,
33    ) -> Vec<(Option<u16>, Response)> {
34        T::inferred_early_responses(ctx, operation)
35    }
36}
37
38impl<T, E> OperationOutput for Result<T, E>
39where
40    T: OperationOutput,
41    E: OperationOutput,
42{
43    type Inner = T;
44
45    fn operation_response(
46        ctx: &mut crate::generate::GenContext,
47        operation: &mut Operation,
48    ) -> Option<Response> {
49        T::operation_response(ctx, operation)
50    }
51
52    fn inferred_responses(
53        ctx: &mut crate::generate::GenContext,
54        operation: &mut Operation,
55    ) -> Vec<(Option<u16>, Response)> {
56        let mut responses = T::inferred_responses(ctx, operation);
57        responses.extend(E::inferred_responses(ctx, operation));
58        responses
59    }
60}
61
62impl<T> OperationInput for Option<T>
63where
64    T: OperationInput,
65{
66    fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
67        // Make parameters proudced by T optional if T is wrapped in an Option.
68        // TODO: we should probably do this for the body as well.
69        let mut temp_op = Operation::default();
70        T::operation_input(ctx, &mut temp_op);
71        T::operation_input(ctx, operation);
72
73        if temp_op.parameters.is_empty() {
74            return;
75        }
76
77        for param in &mut operation.parameters {
78            if let Some(param) = param.as_item_mut() {
79                let new_param = temp_op.parameters.iter().any(|p| {
80                    let p = match p.as_item() {
81                        Some(p) => p,
82                        None => return false,
83                    };
84
85                    p.parameter_data_ref().name == param.parameter_data_ref().name
86                });
87
88                if new_param {
89                    param.parameter_data_mut().required = false;
90                }
91            }
92        }
93    }
94}
95
96impl<T> OperationOutput for Option<T>
97where
98    T: OperationOutput,
99{
100    type Inner = <T as OperationOutput>::Inner;
101
102    fn operation_response(
103        ctx: &mut crate::generate::GenContext,
104        operation: &mut Operation,
105    ) -> Option<Response> {
106        T::operation_response(ctx, operation)
107    }
108
109    fn inferred_responses(
110        ctx: &mut crate::generate::GenContext,
111        operation: &mut Operation,
112    ) -> Vec<(Option<u16>, Response)> {
113        T::inferred_responses(ctx, operation)
114    }
115}
116
117impl<T> OperationInput for Box<T>
118where
119    T: OperationInput,
120{
121    fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
122        T::operation_input(ctx, operation);
123    }
124}
125
126impl<T> OperationOutput for Box<T>
127where
128    T: OperationOutput,
129{
130    type Inner = <T as OperationOutput>::Inner;
131
132    fn operation_response(
133        ctx: &mut crate::generate::GenContext,
134        operation: &mut Operation,
135    ) -> Option<Response> {
136        T::operation_response(ctx, operation)
137    }
138
139    fn inferred_responses(
140        ctx: &mut crate::generate::GenContext,
141        operation: &mut Operation,
142    ) -> Vec<(Option<u16>, Response)> {
143        T::inferred_responses(ctx, operation)
144    }
145}
146
147impl<T> OperationInput for Rc<T>
148where
149    T: OperationInput,
150{
151    fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
152        T::operation_input(ctx, operation);
153    }
154}
155
156impl<T> OperationOutput for Rc<T>
157where
158    T: OperationOutput,
159{
160    type Inner = <T as OperationOutput>::Inner;
161
162    fn operation_response(
163        ctx: &mut crate::generate::GenContext,
164        operation: &mut Operation,
165    ) -> Option<Response> {
166        T::operation_response(ctx, operation)
167    }
168
169    fn inferred_responses(
170        ctx: &mut crate::generate::GenContext,
171        operation: &mut Operation,
172    ) -> Vec<(Option<u16>, Response)> {
173        T::inferred_responses(ctx, operation)
174    }
175}
176
177impl<T> OperationInput for Arc<T>
178where
179    T: OperationInput,
180{
181    fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
182        T::operation_input(ctx, operation);
183    }
184}
185
186impl<T> OperationOutput for Arc<T>
187where
188    T: OperationOutput,
189{
190    type Inner = <T as OperationOutput>::Inner;
191
192    fn operation_response(
193        ctx: &mut crate::generate::GenContext,
194        operation: &mut Operation,
195    ) -> Option<Response> {
196        T::operation_response(ctx, operation)
197    }
198
199    fn inferred_responses(
200        ctx: &mut crate::generate::GenContext,
201        operation: &mut Operation,
202    ) -> Vec<(Option<u16>, Response)> {
203        T::inferred_responses(ctx, operation)
204    }
205}
206
207impl OperationInput for String {
208    fn operation_input(ctx: &mut crate::generate::GenContext, operation: &mut Operation) {
209        set_body(
210            ctx,
211            operation,
212            RequestBody {
213                description: None,
214                content: IndexMap::from_iter([(
215                    "text/plain; charset=utf-8".into(),
216                    MediaType::default(),
217                )]),
218                required: true,
219                extensions: IndexMap::default(),
220            },
221        );
222    }
223}
224
225impl OperationOutput for String {
226    type Inner = Self;
227
228    fn operation_response(
229        _ctx: &mut crate::generate::GenContext,
230        _operation: &mut Operation,
231    ) -> Option<crate::openapi::Response> {
232        Some(Response {
233            description: "plain text".into(),
234            content: IndexMap::from_iter([(
235                "text/plain; charset=utf-8".into(),
236                MediaType::default(),
237            )]),
238            ..Default::default()
239        })
240    }
241
242    fn inferred_responses(
243        ctx: &mut crate::generate::GenContext,
244        operation: &mut Operation,
245    ) -> Vec<(Option<u16>, Response)> {
246        if let Some(res) = Self::operation_response(ctx, operation) {
247            Vec::from([(Some(200), res)])
248        } else {
249            Vec::new()
250        }
251    }
252}
253
254impl OperationOutput for &str {
255    type Inner = Self;
256
257    fn operation_response(
258        ctx: &mut crate::generate::GenContext,
259        operation: &mut Operation,
260    ) -> Option<crate::openapi::Response> {
261        String::operation_response(ctx, operation)
262    }
263
264    fn inferred_responses(
265        ctx: &mut crate::generate::GenContext,
266        operation: &mut Operation,
267    ) -> Vec<(Option<u16>, Response)> {
268        String::inferred_responses(ctx, operation)
269    }
270}
271
272impl OperationOutput for Cow<'_, str> {
273    type Inner = Self;
274
275    fn operation_response(
276        ctx: &mut crate::generate::GenContext,
277        operation: &mut Operation,
278    ) -> Option<crate::openapi::Response> {
279        String::operation_response(ctx, operation)
280    }
281
282    fn inferred_responses(
283        ctx: &mut crate::generate::GenContext,
284        operation: &mut Operation,
285    ) -> Vec<(Option<u16>, Response)> {
286        String::inferred_responses(ctx, operation)
287    }
288}
289
290impl OperationOutput for () {
291    type Inner = Self;
292
293    fn operation_response(
294        _ctx: &mut crate::generate::GenContext,
295        _operation: &mut Operation,
296    ) -> Option<crate::openapi::Response> {
297        Some(no_content_response())
298    }
299
300    fn inferred_responses(
301        ctx: &mut crate::generate::GenContext,
302        operation: &mut Operation,
303    ) -> Vec<(Option<u16>, Response)> {
304        if let Some(res) = Self::operation_response(ctx, operation) {
305            Vec::from([(Some(ctx.no_content_status), res)])
306        } else {
307            Vec::new()
308        }
309    }
310}
311
312impl OperationInput for Vec<u8> {
313    fn operation_input(
314        ctx: &mut crate::generate::GenContext,
315        operation: &mut crate::openapi::Operation,
316    ) {
317        set_body(
318            ctx,
319            operation,
320            RequestBody {
321                description: None,
322                content: IndexMap::from_iter([(
323                    "application/octet-stream".into(),
324                    MediaType::default(),
325                )]),
326                required: true,
327                extensions: IndexMap::default(),
328            },
329        );
330    }
331}
332
333impl OperationOutput for Vec<u8> {
334    type Inner = Self;
335
336    fn operation_response(
337        _ctx: &mut crate::generate::GenContext,
338        _operation: &mut Operation,
339    ) -> Option<crate::openapi::Response> {
340        Some(Response {
341            description: "byte stream".into(),
342            content: IndexMap::from_iter([(
343                "application/octet-stream".into(),
344                MediaType::default(),
345            )]),
346            ..Default::default()
347        })
348    }
349
350    fn inferred_responses(
351        ctx: &mut crate::generate::GenContext,
352        operation: &mut Operation,
353    ) -> Vec<(Option<u16>, Response)> {
354        if let Some(res) = Self::operation_response(ctx, operation) {
355            Vec::from([(Some(200), res)])
356        } else {
357            Vec::new()
358        }
359    }
360}
361
362impl OperationInput for &[u8] {
363    fn operation_input(
364        ctx: &mut crate::generate::GenContext,
365        operation: &mut crate::openapi::Operation,
366    ) {
367        Vec::<u8>::operation_input(ctx, operation);
368    }
369}
370
371impl OperationOutput for &[u8] {
372    type Inner = Self;
373
374    fn operation_response(
375        ctx: &mut crate::generate::GenContext,
376        operation: &mut Operation,
377    ) -> Option<crate::openapi::Response> {
378        Vec::<u8>::operation_response(ctx, operation)
379    }
380
381    fn inferred_responses(
382        ctx: &mut crate::generate::GenContext,
383        operation: &mut Operation,
384    ) -> Vec<(Option<u16>, Response)> {
385        Vec::<u8>::inferred_responses(ctx, operation)
386    }
387}
388
389impl OperationInput for Cow<'_, [u8]> {
390    fn operation_input(
391        ctx: &mut crate::generate::GenContext,
392        operation: &mut crate::openapi::Operation,
393    ) {
394        Vec::<u8>::operation_input(ctx, operation);
395    }
396}
397
398impl OperationOutput for Cow<'_, [u8]> {
399    type Inner = Self;
400
401    fn operation_response(
402        ctx: &mut crate::generate::GenContext,
403        operation: &mut Operation,
404    ) -> Option<crate::openapi::Response> {
405        Vec::<u8>::operation_response(ctx, operation)
406    }
407
408    fn inferred_responses(
409        ctx: &mut crate::generate::GenContext,
410        operation: &mut Operation,
411    ) -> Vec<(Option<u16>, Response)> {
412        Vec::<u8>::inferred_responses(ctx, operation)
413    }
414}
415
416// Empty blanket impls for tuples.
417//
418// In axum these are commonly (StatusCode, Value),
419// we keep it more broad as other frameworks
420// could implement (u16, Value) instead for example,
421// or any combination that is compatible, like:
422// - `(StatusCode, impl IntoResponse)`
423// - `(Parts, impl IntoResponse)`
424// - `(Response<()>, impl IntoResponse)`
425// - `(T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement `IntoResponseParts`.
426// - `(StatusCode, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement `IntoResponseParts`.
427// - `(Parts, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement `IntoResponseParts`.
428// - `(Response<()>, T1, .., Tn, impl IntoResponse)` where `T1` to `Tn` all implement `IntoResponseParts`.
429
430impl<T1, T2> OperationOutput for (T1, T2) {
431    type Inner = Infallible;
432}
433impl<T1, T2, T3> OperationOutput for (T1, T2, T3) {
434    type Inner = Infallible;
435}
436impl<T1, T2, T3, T4> OperationOutput for (T1, T2, T3, T4) {
437    type Inner = Infallible;
438}
439impl<T1, T2, T3, T4, T5> OperationOutput for (T1, T2, T3, T4, T5) {
440    type Inner = Infallible;
441}
442impl<T1, T2, T3, T4, T5, T6> OperationOutput for (T1, T2, T3, T4, T5, T6) {
443    type Inner = Infallible;
444}
445impl<T1, T2, T3, T4, T5, T6, T7> OperationOutput for (T1, T2, T3, T4, T5, T6, T7) {
446    type Inner = Infallible;
447}
448impl<T1, T2, T3, T4, T5, T6, T7, T8> OperationOutput for (T1, T2, T3, T4, T5, T6, T7, T8) {
449    type Inner = Infallible;
450}
451impl<T1, T2, T3, T4, T5, T6, T7, T8, T9> OperationOutput for (T1, T2, T3, T4, T5, T6, T7, T8, T9) {
452    type Inner = Infallible;
453}
454impl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> OperationOutput
455    for (T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
456{
457    type Inner = Infallible;
458}