1#[cfg(test)]
9pub mod test;
10
11use crate::{HasValidate, ValidationRejection};
12use axum::extract::{FromRequest, FromRequestParts, Request};
13use axum::http::request::Parts;
14use axum::response::{IntoResponse, Response};
15use std::fmt::{Display, Formatter};
16use std::ops::{Deref, DerefMut};
17use validify::{Modify, Validate, ValidationErrors, ValidifyPayload};
18
19#[derive(Debug, Clone, Copy, Default)]
26pub struct Validated<E>(pub E);
27
28impl<E> Deref for Validated<E> {
29 type Target = E;
30
31 fn deref(&self) -> &Self::Target {
32 &self.0
33 }
34}
35
36impl<E> DerefMut for Validated<E> {
37 fn deref_mut(&mut self) -> &mut Self::Target {
38 &mut self.0
39 }
40}
41
42impl<T: Display> Display for Validated<T> {
43 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
44 self.0.fmt(f)
45 }
46}
47
48impl<E> Validated<E> {
49 pub fn into_inner(self) -> E {
54 self.0
55 }
56}
57
58#[cfg(feature = "aide")]
59impl<T> aide::OperationInput for Validated<T>
60where
61 T: aide::OperationInput,
62{
63 fn operation_input(
64 ctx: &mut aide::generate::GenContext,
65 operation: &mut aide::openapi::Operation,
66 ) {
67 T::operation_input(ctx, operation);
68 }
69}
70
71#[derive(Debug, Clone, Copy, Default)]
88pub struct Modified<E>(pub E);
89
90impl<E> Deref for Modified<E> {
91 type Target = E;
92
93 fn deref(&self) -> &Self::Target {
94 &self.0
95 }
96}
97
98impl<E> DerefMut for Modified<E> {
99 fn deref_mut(&mut self) -> &mut Self::Target {
100 &mut self.0
101 }
102}
103
104impl<T: Display> Display for Modified<T> {
105 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106 self.0.fmt(f)
107 }
108}
109
110impl<E> Modified<E> {
111 pub fn into_inner(self) -> E {
116 self.0
117 }
118}
119
120impl<E: IntoResponse + HasModify> IntoResponse for Modified<E> {
121 fn into_response(mut self) -> Response {
122 self.get_modify().modify();
123 self.0.into_response()
124 }
125}
126
127#[cfg(feature = "aide")]
128impl<T> aide::OperationInput for Modified<T>
129where
130 T: aide::OperationInput,
131{
132 fn operation_input(
133 ctx: &mut aide::generate::GenContext,
134 operation: &mut aide::openapi::Operation,
135 ) {
136 T::operation_input(ctx, operation);
137 }
138}
139
140#[cfg(feature = "aide")]
141impl<T> aide::OperationOutput for Modified<T>
142where
143 T: aide::OperationOutput,
144{
145 type Inner = T::Inner;
146
147 fn operation_response(
148 ctx: &mut aide::generate::GenContext,
149 operation: &mut aide::openapi::Operation,
150 ) -> Option<aide::openapi::Response> {
151 T::operation_response(ctx, operation)
152 }
153
154 fn inferred_responses(
155 ctx: &mut aide::generate::GenContext,
156 operation: &mut aide::openapi::Operation,
157 ) -> Vec<(Option<u16>, aide::openapi::Response)> {
158 T::inferred_responses(ctx, operation)
159 }
160}
161
162#[derive(Debug, Clone, Copy, Default)]
171pub struct Validified<E>(pub E);
172
173impl<E> Deref for Validified<E> {
174 type Target = E;
175
176 fn deref(&self) -> &Self::Target {
177 &self.0
178 }
179}
180
181impl<E> DerefMut for Validified<E> {
182 fn deref_mut(&mut self) -> &mut Self::Target {
183 &mut self.0
184 }
185}
186
187impl<T: Display> Display for Validified<T> {
188 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
189 self.0.fmt(f)
190 }
191}
192
193impl<E> Validified<E> {
194 pub fn into_inner(self) -> E {
199 self.0
200 }
201}
202
203#[cfg(feature = "aide")]
204impl<T> aide::OperationInput for Validified<T>
205where
206 T: aide::OperationInput,
207{
208 fn operation_input(
209 ctx: &mut aide::generate::GenContext,
210 operation: &mut aide::openapi::Operation,
211 ) {
212 T::operation_input(ctx, operation);
213 }
214}
215
216#[derive(Debug, Clone, Copy, Default)]
223pub struct ValidifiedByRef<E>(pub E);
224
225impl<E> Deref for ValidifiedByRef<E> {
226 type Target = E;
227
228 fn deref(&self) -> &Self::Target {
229 &self.0
230 }
231}
232
233impl<E> DerefMut for ValidifiedByRef<E> {
234 fn deref_mut(&mut self) -> &mut Self::Target {
235 &mut self.0
236 }
237}
238
239impl<T: Display> Display for ValidifiedByRef<T> {
240 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
241 self.0.fmt(f)
242 }
243}
244
245impl<E> ValidifiedByRef<E> {
246 pub fn into_inner(self) -> E {
251 self.0
252 }
253}
254
255#[cfg(feature = "aide")]
256impl<T> aide::OperationInput for ValidifiedByRef<T>
257where
258 T: aide::OperationInput,
259{
260 fn operation_input(
261 ctx: &mut aide::generate::GenContext,
262 operation: &mut aide::openapi::Operation,
263 ) {
264 T::operation_input(ctx, operation);
265 }
266}
267
268pub type ValidifyRejection<E> = ValidationRejection<ValidationErrors, E>;
271
272impl<E> From<ValidationErrors> for ValidifyRejection<E> {
273 fn from(value: ValidationErrors) -> Self {
274 Self::Valid(value)
275 }
276}
277
278pub trait HasModify {
283 type Modify: Modify;
285 fn get_modify(&mut self) -> &mut Self::Modify;
287}
288
289pub trait PayloadExtractor {
291 type Payload;
293 fn get_payload(self) -> Self::Payload;
295}
296
297pub trait HasValidify: Sized {
303 type Validify: ValidifyPayload;
305
306 type PayloadExtractor: PayloadExtractor<Payload = <Self::Validify as ValidifyPayload>::Payload>;
310
311 fn from_validify(v: Self::Validify) -> Self;
313}
314
315impl<State, Extractor> FromRequest<State> for Validated<Extractor>
316where
317 State: Send + Sync,
318 Extractor: HasValidate + FromRequest<State>,
319 Extractor::Validate: validify::Validate,
320{
321 type Rejection = ValidifyRejection<<Extractor as FromRequest<State>>::Rejection>;
322
323 async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
324 let inner = Extractor::from_request(req, state)
325 .await
326 .map_err(ValidifyRejection::Inner)?;
327 inner.get_validate().validate()?;
328 Ok(Validated(inner))
329 }
330}
331
332impl<State, Extractor> FromRequestParts<State> for Validated<Extractor>
333where
334 State: Send + Sync,
335 Extractor: HasValidate + FromRequestParts<State>,
336 Extractor::Validate: Validate,
337{
338 type Rejection = ValidifyRejection<<Extractor as FromRequestParts<State>>::Rejection>;
339
340 async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
341 let inner = Extractor::from_request_parts(parts, state)
342 .await
343 .map_err(ValidifyRejection::Inner)?;
344 inner.get_validate().validate()?;
345 Ok(Validated(inner))
346 }
347}
348
349impl<State, Extractor> FromRequest<State> for Modified<Extractor>
350where
351 State: Send + Sync,
352 Extractor: HasModify + FromRequest<State>,
353{
354 type Rejection = <Extractor as FromRequest<State>>::Rejection;
355
356 async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
357 let mut inner = Extractor::from_request(req, state).await?;
358 inner.get_modify().modify();
359 Ok(Modified(inner))
360 }
361}
362
363impl<State, Extractor> FromRequestParts<State> for Modified<Extractor>
364where
365 State: Send + Sync,
366 Extractor: HasModify + FromRequestParts<State>,
367{
368 type Rejection = <Extractor as FromRequestParts<State>>::Rejection;
369
370 async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
371 let mut inner = Extractor::from_request_parts(parts, state).await?;
372 inner.get_modify().modify();
373 Ok(Modified(inner))
374 }
375}
376
377impl<State, Extractor> FromRequest<State> for Validified<Extractor>
378where
379 State: Send + Sync,
380 Extractor: HasValidify,
381 Extractor::PayloadExtractor: FromRequest<State>,
382{
383 type Rejection =
384 ValidifyRejection<<Extractor::PayloadExtractor as FromRequest<State>>::Rejection>;
385
386 async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
387 let payload = Extractor::PayloadExtractor::from_request(req, state)
388 .await
389 .map_err(ValidifyRejection::Inner)?
390 .get_payload();
391 let validify = Extractor::Validify::validify_from(payload)?;
392 Ok(Validified(Extractor::from_validify(validify)))
393 }
394}
395
396impl<State, Extractor> FromRequestParts<State> for Validified<Extractor>
397where
398 State: Send + Sync,
399 Extractor: HasValidify,
400 Extractor::PayloadExtractor: FromRequestParts<State>,
401{
402 type Rejection =
403 ValidifyRejection<<Extractor::PayloadExtractor as FromRequestParts<State>>::Rejection>;
404
405 async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
406 let payload = Extractor::PayloadExtractor::from_request_parts(parts, state)
407 .await
408 .map_err(ValidifyRejection::Inner)?
409 .get_payload();
410 let validify = Extractor::Validify::validify_from(payload)?;
411 Ok(Validified(Extractor::from_validify(validify)))
412 }
413}
414
415impl<State, Extractor> FromRequest<State> for ValidifiedByRef<Extractor>
416where
417 State: Send + Sync,
418 Extractor: HasValidate + HasModify + FromRequest<State>,
419 Extractor::Validate: Validate,
420{
421 type Rejection = ValidifyRejection<<Extractor as FromRequest<State>>::Rejection>;
422
423 async fn from_request(req: Request, state: &State) -> Result<Self, Self::Rejection> {
424 let mut inner = Extractor::from_request(req, state)
425 .await
426 .map_err(ValidifyRejection::Inner)?;
427 inner.get_modify().modify();
428 inner.get_validate().validate()?;
429 Ok(ValidifiedByRef(inner))
430 }
431}
432
433impl<State, Extractor> FromRequestParts<State> for ValidifiedByRef<Extractor>
434where
435 State: Send + Sync,
436 Extractor: HasValidate + HasModify + FromRequestParts<State>,
437 Extractor::Validate: Validate,
438{
439 type Rejection = ValidifyRejection<<Extractor as FromRequestParts<State>>::Rejection>;
440
441 async fn from_request_parts(parts: &mut Parts, state: &State) -> Result<Self, Self::Rejection> {
442 let mut inner = Extractor::from_request_parts(parts, state)
443 .await
444 .map_err(ValidifyRejection::Inner)?;
445 inner.get_modify().modify();
446 inner.get_validate().validate()?;
447 Ok(ValidifiedByRef(inner))
448 }
449}
450
451#[cfg(test)]
452mod tests {
453 use super::*;
454 use axum::Json;
455 use serde::Serialize;
456 use std::error::Error;
457 use std::io;
458
459 const VALIDIFY: &str = "validify";
460
461 #[test]
462 fn validify_deref_deref_mut_into_inner() {
463 let mut inner = String::from(VALIDIFY);
464 let mut v = Validated(inner.clone());
465 assert_eq!(&inner, v.deref());
466 inner.push_str(VALIDIFY);
467 v.deref_mut().push_str(VALIDIFY);
468 assert_eq!(&inner, v.deref());
469 println!("{}", v);
470 assert_eq!(inner, v.into_inner());
471
472 let mut inner = String::from(VALIDIFY);
473 let mut v = Modified(inner.clone());
474 assert_eq!(&inner, v.deref());
475 inner.push_str(VALIDIFY);
476 v.deref_mut().push_str(VALIDIFY);
477 assert_eq!(&inner, v.deref());
478 println!("{}", v);
479 assert_eq!(inner, v.into_inner());
480
481 let mut inner = String::from(VALIDIFY);
482 let mut v = Validified(inner.clone());
483 assert_eq!(&inner, v.deref());
484 inner.push_str(VALIDIFY);
485 v.deref_mut().push_str(VALIDIFY);
486 assert_eq!(&inner, v.deref());
487 println!("{}", v);
488 assert_eq!(inner, v.into_inner());
489
490 let mut inner = String::from(VALIDIFY);
491 let mut v = ValidifiedByRef(inner.clone());
492 assert_eq!(&inner, v.deref());
493 inner.push_str(VALIDIFY);
494 v.deref_mut().push_str(VALIDIFY);
495 assert_eq!(&inner, v.deref());
496 println!("{}", v);
497 assert_eq!(inner, v.into_inner());
498 }
499
500 #[test]
501 fn display_error() {
502 let mut report = ValidationErrors::new();
504 report.add(validify::ValidationError::new_schema(VALIDIFY));
505 let s = report.to_string();
506 let vr = ValidifyRejection::<String>::Valid(report);
507 assert_eq!(vr.to_string(), s);
508
509 let inner = String::from(VALIDIFY);
511 let vr = ValidifyRejection::<String>::Inner(inner.clone());
512 assert_eq!(inner.to_string(), vr.to_string());
513
514 let mut report = ValidationErrors::new();
516 report.add(validify::ValidationError::new_schema(VALIDIFY));
517 let vr = ValidifyRejection::<io::Error>::Valid(report);
518 assert!(
519 matches!(vr.source(), Some(source) if source.downcast_ref::<ValidationErrors>().is_some())
520 );
521
522 let vr = ValidifyRejection::<io::Error>::Inner(io::Error::other(VALIDIFY));
524 assert!(
525 matches!(vr.source(), Some(source) if source.downcast_ref::<io::Error>().is_some())
526 );
527 }
528
529 #[test]
530 fn modified_into_response() {
531 use validify::Validify;
532 #[derive(Validify, Serialize)]
533 struct Data {
534 #[modify(trim)]
535 v: String,
536 }
537 println!(
538 "{:?}",
539 Modified(Json(Data { v: "a ".into() })).into_response()
540 );
541 }
542}