axum_containerssh/types.rs
1use std::{mem, str::FromStr};
2
3use base64::{engine::general_purpose, Engine};
4use serde::{Deserialize, Deserializer, Serialize, Serializer};
5
6#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
7#[allow(dead_code)]
8pub struct Object(serde_json::Value);
9
10impl validator::Validate for Object {
11 fn validate(&self) -> Result<(), validator::ValidationErrors> {
12 Ok(())
13 }
14}
15
16impl FromStr for Object {
17 type Err = String;
18
19 fn from_str(s: &str) -> Result<Self, Self::Err> {
20 Ok(Self(serde_json::Value::String(s.to_owned())))
21 }
22}
23
24/// Serde helper function to create a default `Option<Nullable<T>>` while
25/// deserializing
26pub fn default_optional_nullable<T>() -> Option<Nullable<T>> {
27 None
28}
29
30/// Serde helper function to deserialize into an `Option<Nullable<T>>`
31pub fn deserialize_optional_nullable<'de, D, T>(
32 deserializer: D,
33) -> Result<Option<Nullable<T>>, D::Error>
34where
35 D: Deserializer<'de>,
36 T: Deserialize<'de>,
37{
38 Option::<T>::deserialize(deserializer).map(|val| match val {
39 Some(inner) => Some(Nullable::Present(inner)),
40 None => Some(Nullable::Null),
41 })
42}
43
44/// The Nullable type. Represents a value which may be specified as null on an API.
45/// Note that this is distinct from a value that is optional and not present!
46///
47/// Nullable implements many of the same methods as the Option type (map, unwrap, etc).
48#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
49pub enum Nullable<T> {
50 /// Null value
51 Null,
52 /// Value is present
53 Present(T),
54}
55
56impl<T> Nullable<T> {
57 /////////////////////////////////////////////////////////////////////////
58 // Querying the contained values
59 /////////////////////////////////////////////////////////////////////////
60
61 /// Returns `true` if the Nullable is a `Present` value.
62 ///
63 /// # Examples
64 ///
65 /// ```
66 /// # use axum_containerssh::types::Nullable;
67 ///
68 /// let x: Nullable<u32> = Nullable::Present(2);
69 /// assert_eq!(x.is_present(), true);
70 ///
71 /// let x: Nullable<u32> = Nullable::Null;
72 /// assert_eq!(x.is_present(), false);
73 /// ```
74 #[inline]
75 pub fn is_present(&self) -> bool {
76 match *self {
77 Nullable::Present(_) => true,
78 Nullable::Null => false,
79 }
80 }
81
82 /// Returns `true` if the Nullable is a `Null` value.
83 ///
84 /// # Examples
85 ///
86 /// ```
87 /// # use axum_containerssh::types::Nullable;
88 ///
89 /// let x: Nullable<u32> = Nullable::Present(2);
90 /// assert_eq!(x.is_null(), false);
91 ///
92 /// let x: Nullable<u32> = Nullable::Null;
93 /// assert_eq!(x.is_null(), true);
94 /// ```
95 #[inline]
96 pub fn is_null(&self) -> bool {
97 !self.is_present()
98 }
99
100 /////////////////////////////////////////////////////////////////////////
101 // Adapter for working with references
102 /////////////////////////////////////////////////////////////////////////
103
104 /// Converts from `Nullable<T>` to `Nullable<&T>`.
105 ///
106 /// # Examples
107 ///
108 /// Convert an `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, preserving the original.
109 /// The [`map`] method takes the `self` argument by value, consuming the original,
110 /// so this technique uses `as_ref` to first take a `Nullable` to a reference
111 /// to the value inside the original.
112 ///
113 /// [`map`]: enum.Nullable.html#method.map
114 /// [`String`]: ../../std/string/struct.String.html
115 /// [`usize`]: ../../std/primitive.usize.html
116 ///
117 /// ```
118 /// # use axum_containerssh::types::Nullable;
119 ///
120 /// let num_as_str: Nullable<String> = Nullable::Present("10".to_string());
121 /// // First, cast `Nullable<String>` to `Nullable<&String>` with `as_ref`,
122 /// // then consume *that* with `map`, leaving `num_as_str` on the stack.
123 /// let num_as_int: Nullable<usize> = num_as_str.as_ref().map(|n| n.len());
124 /// println!("still can print num_as_str: {:?}", num_as_str);
125 /// ```
126 #[inline]
127 pub fn as_ref(&self) -> Nullable<&T> {
128 match *self {
129 Nullable::Present(ref x) => Nullable::Present(x),
130 Nullable::Null => Nullable::Null,
131 }
132 }
133
134 /// Converts from `Nullable<T>` to `Nullable<&mut T>`.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// # use axum_containerssh::types::Nullable;
140 ///
141 /// let mut x = Nullable::Present(2);
142 /// match x.as_mut() {
143 /// Nullable::Present(v) => *v = 42,
144 /// Nullable::Null => {},
145 /// }
146 /// assert_eq!(x, Nullable::Present(42));
147 /// ```
148 #[inline]
149 pub fn as_mut(&mut self) -> Nullable<&mut T> {
150 match *self {
151 Nullable::Present(ref mut x) => Nullable::Present(x),
152 Nullable::Null => Nullable::Null,
153 }
154 }
155
156 /////////////////////////////////////////////////////////////////////////
157 // Getting to contained values
158 /////////////////////////////////////////////////////////////////////////
159
160 /// Unwraps a Nullable, yielding the content of a `Nullable::Present`.
161 ///
162 /// # Panics
163 ///
164 /// Panics if the value is a [`Nullable::Null`] with a custom panic message provided by
165 /// `msg`.
166 ///
167 /// [`Nullable::Null`]: #variant.Null
168 ///
169 /// # Examples
170 ///
171 /// ```
172 /// # use axum_containerssh::types::Nullable;
173 ///
174 /// let x = Nullable::Present("value");
175 /// assert_eq!(x.expect("the world is ending"), "value");
176 /// ```
177 ///
178 /// ```{.should_panic}
179 /// # use axum_containerssh::types::Nullable;
180 ///
181 /// let x: Nullable<&str> = Nullable::Null;
182 /// x.expect("the world is ending"); // panics with `the world is ending`
183 /// ```
184 #[inline]
185 pub fn expect(self, msg: &str) -> T {
186 match self {
187 Nullable::Present(val) => val,
188 Nullable::Null => expect_failed(msg),
189 }
190 }
191
192 /// Moves the value `v` out of the `Nullable<T>` if it is `Nullable::Present(v)`.
193 ///
194 /// In general, because this function may panic, its use is discouraged.
195 /// Instead, prefer to use pattern matching and handle the `Nullable::Null`
196 /// case explicitly.
197 ///
198 /// # Panics
199 ///
200 /// Panics if the self value equals [`Nullable::Null`].
201 ///
202 /// [`Nullable::Null`]: #variant.Null
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// # use axum_containerssh::types::Nullable;
208 ///
209 /// let x = Nullable::Present("air");
210 /// assert_eq!(x.unwrap(), "air");
211 /// ```
212 ///
213 /// ```{.should_panic}
214 /// # use axum_containerssh::types::Nullable;
215 ///
216 /// let x: Nullable<&str> = Nullable::Null;
217 /// assert_eq!(x.unwrap(), "air"); // fails
218 /// ```
219 #[inline]
220 pub fn unwrap(self) -> T {
221 match self {
222 Nullable::Present(val) => val,
223 Nullable::Null => panic!("called `Nullable::unwrap()` on a `Nullable::Null` value"),
224 }
225 }
226
227 /// Returns the contained value or a default.
228 ///
229 /// # Examples
230 ///
231 /// ```
232 /// # use axum_containerssh::types::Nullable;
233 ///
234 /// assert_eq!(Nullable::Present("car").unwrap_or("bike"), "car");
235 /// assert_eq!(Nullable::Null.unwrap_or("bike"), "bike");
236 /// ```
237 #[inline]
238 pub fn unwrap_or(self, def: T) -> T {
239 match self {
240 Nullable::Present(x) => x,
241 Nullable::Null => def,
242 }
243 }
244
245 /// Returns the contained value or computes it from a closure.
246 ///
247 /// # Examples
248 ///
249 /// ```
250 /// # use axum_containerssh::types::Nullable;
251 ///
252 /// let k = 10;
253 /// assert_eq!(Nullable::Present(4).unwrap_or_else(|| 2 * k), 4);
254 /// assert_eq!(Nullable::Null.unwrap_or_else(|| 2 * k), 20);
255 /// ```
256 #[inline]
257 pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T {
258 match self {
259 Nullable::Present(x) => x,
260 Nullable::Null => f(),
261 }
262 }
263
264 /////////////////////////////////////////////////////////////////////////
265 // Transforming contained values
266 /////////////////////////////////////////////////////////////////////////
267
268 /// Maps a `Nullable<T>` to `Nullable<U>` by applying a function to a contained value.
269 ///
270 /// # Examples
271 ///
272 /// Convert a `Nullable<`[`String`]`>` into a `Nullable<`[`usize`]`>`, consuming the original:
273 ///
274 /// [`String`]: ../../std/string/struct.String.html
275 /// [`usize`]: ../../std/primitive.usize.html
276 ///
277 /// ```
278 /// # use axum_containerssh::types::Nullable;
279 ///
280 /// let maybe_some_string = Nullable::Present(String::from("Hello, World!"));
281 /// // `Nullable::map` takes self *by value*, consuming `maybe_some_string`
282 /// let maybe_some_len = maybe_some_string.map(|s| s.len());
283 ///
284 /// assert_eq!(maybe_some_len, Nullable::Present(13));
285 /// ```
286 #[inline]
287 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Nullable<U> {
288 match self {
289 Nullable::Present(x) => Nullable::Present(f(x)),
290 Nullable::Null => Nullable::Null,
291 }
292 }
293
294 /// Applies a function to the contained value (if any),
295 /// or returns a `default` (if not).
296 ///
297 /// # Examples
298 ///
299 /// ```
300 /// # use axum_containerssh::types::Nullable;
301 ///
302 /// let x = Nullable::Present("foo");
303 /// assert_eq!(x.map_or(42, |v| v.len()), 3);
304 ///
305 /// let x: Nullable<&str> = Nullable::Null;
306 /// assert_eq!(x.map_or(42, |v| v.len()), 42);
307 /// ```
308 #[inline]
309 pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
310 match self {
311 Nullable::Present(t) => f(t),
312 Nullable::Null => default,
313 }
314 }
315
316 /// Applies a function to the contained value (if any),
317 /// or computes a `default` (if not).
318 ///
319 /// # Examples
320 ///
321 /// ```
322 /// # use axum_containerssh::types::Nullable;
323 ///
324 /// let k = 21;
325 ///
326 /// let x = Nullable::Present("foo");
327 /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 3);
328 ///
329 /// let x: Nullable<&str> = Nullable::Null;
330 /// assert_eq!(x.map_or_else(|| 2 * k, |v| v.len()), 42);
331 /// ```
332 #[inline]
333 pub fn map_or_else<U, D: FnOnce() -> U, F: FnOnce(T) -> U>(self, default: D, f: F) -> U {
334 match self {
335 Nullable::Present(t) => f(t),
336 Nullable::Null => default(),
337 }
338 }
339
340 /// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
341 /// [`Ok(v)`] and `Nullable::Null` to [`Err(err)`][Err].
342 ///
343 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
344 /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
345 /// [Err]: ../../std/result/enum.Result.html#variant.Err
346 ///
347 /// # Examples
348 ///
349 /// ```
350 /// # use axum_containerssh::types::Nullable;
351 ///
352 /// let x = Nullable::Present("foo");
353 /// assert_eq!(x.ok_or(0), Ok("foo"));
354 ///
355 /// let x: Nullable<&str> = Nullable::Null;
356 /// assert_eq!(x.ok_or(0), Err(0));
357 /// ```
358 #[inline]
359 pub fn ok_or<E>(self, err: E) -> Result<T, E> {
360 match self {
361 Nullable::Present(v) => Ok(v),
362 Nullable::Null => Err(err),
363 }
364 }
365
366 /// Transforms the `Nullable<T>` into a [`Result<T, E>`], mapping `Nullable::Present(v)` to
367 /// [`Ok(v)`] and `Nullable::Null` to [`Err(err())`][Err].
368 ///
369 /// [`Result<T, E>`]: ../../std/result/enum.Result.html
370 /// [`Ok(v)`]: ../../std/result/enum.Result.html#variant.Ok
371 /// [Err]: ../../std/result/enum.Result.html#variant.Err
372 ///
373 /// # Examples
374 ///
375 /// ```
376 /// # use axum_containerssh::types::Nullable;
377 ///
378 /// let x = Nullable::Present("foo");
379 /// assert_eq!(x.ok_or_else(|| 0), Ok("foo"));
380 ///
381 /// let x: Nullable<&str> = Nullable::Null;
382 /// assert_eq!(x.ok_or_else(|| 0), Err(0));
383 /// ```
384 #[inline]
385 pub fn ok_or_else<E, F: FnOnce() -> E>(self, err: F) -> Result<T, E> {
386 match self {
387 Nullable::Present(v) => Ok(v),
388 Nullable::Null => Err(err()),
389 }
390 }
391
392 /////////////////////////////////////////////////////////////////////////
393 // Boolean operations on the values, eager and lazy
394 /////////////////////////////////////////////////////////////////////////
395
396 /// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise returns `optb`.
397 ///
398 /// # Examples
399 ///
400 /// ```
401 /// # use axum_containerssh::types::Nullable;
402 ///
403 /// let x = Nullable::Present(2);
404 /// let y: Nullable<&str> = Nullable::Null;
405 /// assert_eq!(x.and(y), Nullable::Null);
406 ///
407 /// let x: Nullable<u32> = Nullable::Null;
408 /// let y = Nullable::Present("foo");
409 /// assert_eq!(x.and(y), Nullable::Null);
410 ///
411 /// let x = Nullable::Present(2);
412 /// let y = Nullable::Present("foo");
413 /// assert_eq!(x.and(y), Nullable::Present("foo"));
414 ///
415 /// let x: Nullable<u32> = Nullable::Null;
416 /// let y: Nullable<&str> = Nullable::Null;
417 /// assert_eq!(x.and(y), Nullable::Null);
418 /// ```
419 #[inline]
420 pub fn and<U>(self, optb: Nullable<U>) -> Nullable<U> {
421 match self {
422 Nullable::Present(_) => optb,
423 Nullable::Null => Nullable::Null,
424 }
425 }
426
427 /// Returns `Nullable::Null` if the Nullable is `Nullable::Null`, otherwise calls `f` with the
428 /// wrapped value and returns the result.
429 ///
430 /// Some languages call this operation flatmap.
431 ///
432 /// # Examples
433 ///
434 /// ```
435 /// # use axum_containerssh::types::Nullable;
436 ///
437 /// fn sq(x: u32) -> Nullable<u32> { Nullable::Present(x * x) }
438 /// fn nope(_: u32) -> Nullable<u32> { Nullable::Null }
439 ///
440 /// assert_eq!(Nullable::Present(2).and_then(sq).and_then(sq), Nullable::Present(16));
441 /// assert_eq!(Nullable::Present(2).and_then(sq).and_then(nope), Nullable::Null);
442 /// assert_eq!(Nullable::Present(2).and_then(nope).and_then(sq), Nullable::Null);
443 /// assert_eq!(Nullable::Null.and_then(sq).and_then(sq), Nullable::Null);
444 /// ```
445 #[inline]
446 pub fn and_then<U, F: FnOnce(T) -> Nullable<U>>(self, f: F) -> Nullable<U> {
447 match self {
448 Nullable::Present(x) => f(x),
449 Nullable::Null => Nullable::Null,
450 }
451 }
452
453 /// Returns the Nullable if it contains a value, otherwise returns `optb`.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// # use axum_containerssh::types::Nullable;
459 ///
460 /// let x = Nullable::Present(2);
461 /// let y = Nullable::Null;
462 /// assert_eq!(x.or(y), Nullable::Present(2));
463 ///
464 /// let x = Nullable::Null;
465 /// let y = Nullable::Present(100);
466 /// assert_eq!(x.or(y), Nullable::Present(100));
467 ///
468 /// let x = Nullable::Present(2);
469 /// let y = Nullable::Present(100);
470 /// assert_eq!(x.or(y), Nullable::Present(2));
471 ///
472 /// let x: Nullable<u32> = Nullable::Null;
473 /// let y = Nullable::Null;
474 /// assert_eq!(x.or(y), Nullable::Null);
475 /// ```
476 #[inline]
477 pub fn or(self, optb: Nullable<T>) -> Nullable<T> {
478 match self {
479 Nullable::Present(_) => self,
480 Nullable::Null => optb,
481 }
482 }
483
484 /// Returns the Nullable if it contains a value, otherwise calls `f` and
485 /// returns the result.
486 ///
487 /// # Examples
488 ///
489 /// ```
490 /// # use axum_containerssh::types::Nullable;
491 ///
492 /// fn nobody() -> Nullable<&'static str> { Nullable::Null }
493 /// fn vikings() -> Nullable<&'static str> { Nullable::Present("vikings") }
494 ///
495 /// assert_eq!(Nullable::Present("barbarians").or_else(vikings),
496 /// Nullable::Present("barbarians"));
497 /// assert_eq!(Nullable::Null.or_else(vikings), Nullable::Present("vikings"));
498 /// assert_eq!(Nullable::Null.or_else(nobody), Nullable::Null);
499 /// ```
500 #[inline]
501 pub fn or_else<F: FnOnce() -> Nullable<T>>(self, f: F) -> Nullable<T> {
502 match self {
503 Nullable::Present(_) => self,
504 Nullable::Null => f(),
505 }
506 }
507
508 /////////////////////////////////////////////////////////////////////////
509 // Misc
510 /////////////////////////////////////////////////////////////////////////
511
512 /// Takes the value out of the Nullable, leaving a `Nullable::Null` in its place.
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// # use axum_containerssh::types::Nullable;
518 ///
519 /// let mut x = Nullable::Present(2);
520 /// x.take();
521 /// assert_eq!(x, Nullable::Null);
522 ///
523 /// let mut x: Nullable<u32> = Nullable::Null;
524 /// x.take();
525 /// assert_eq!(x, Nullable::Null);
526 /// ```
527 #[inline]
528 pub fn take(&mut self) -> Nullable<T> {
529 mem::replace(self, Nullable::Null)
530 }
531}
532
533impl<'a, T: Clone> Nullable<&'a T> {
534 /// Maps an `Nullable<&T>` to an `Nullable<T>` by cloning the contents of the
535 /// Nullable.
536 ///
537 /// # Examples
538 ///
539 /// ```
540 /// # use axum_containerssh::types::Nullable;
541 ///
542 /// let x = 12;
543 /// let opt_x = Nullable::Present(&x);
544 /// assert_eq!(opt_x, Nullable::Present(&12));
545 /// let cloned = opt_x.cloned();
546 /// assert_eq!(cloned, Nullable::Present(12));
547 /// ```
548 pub fn cloned(self) -> Nullable<T> {
549 self.map(Clone::clone)
550 }
551}
552
553impl<T: Default> Nullable<T> {
554 /// Returns the contained value or a default
555 ///
556 /// Consumes the `self` argument then, if `Nullable::Present`, returns the contained
557 /// value, otherwise if `Nullable::Null`, returns the default value for that
558 /// type.
559 ///
560 /// # Examples
561 ///
562 /// ```
563 /// # use axum_containerssh::types::Nullable;
564 ///
565 /// let x = Nullable::Present(42);
566 /// assert_eq!(42, x.unwrap_or_default());
567 ///
568 /// let y: Nullable<i32> = Nullable::Null;
569 /// assert_eq!(0, y.unwrap_or_default());
570 /// ```
571 #[inline]
572 pub fn unwrap_or_default(self) -> T {
573 match self {
574 Nullable::Present(x) => x,
575 Nullable::Null => Default::default(),
576 }
577 }
578}
579
580impl<T> Default for Nullable<T> {
581 /// Returns None.
582 #[inline]
583 fn default() -> Nullable<T> {
584 Nullable::Null
585 }
586}
587
588impl<T> From<T> for Nullable<T> {
589 fn from(val: T) -> Nullable<T> {
590 Nullable::Present(val)
591 }
592}
593
594impl<T> Serialize for Nullable<T>
595where
596 T: Serialize,
597{
598 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
599 where
600 S: Serializer,
601 {
602 match *self {
603 Nullable::Present(ref inner) => serializer.serialize_some(&inner),
604 Nullable::Null => serializer.serialize_none(),
605 }
606 }
607}
608
609impl<'de, T> Deserialize<'de> for Nullable<T>
610where
611 T: serde::de::DeserializeOwned,
612{
613 fn deserialize<D>(deserializer: D) -> Result<Nullable<T>, D::Error>
614 where
615 D: Deserializer<'de>,
616 {
617 // In order to deserialize a required, but nullable, value, we first have to check whether
618 // the value is present at all. To do this, we deserialize to a serde_json::Value, which
619 // fails if the value is missing, or gives serde_json::Value::Null if the value is present.
620 // If that succeeds as null, we can easily return a Null.
621 // If that succeeds as some value, we deserialize that value and return a Present.
622 // If that errors, we return the error.
623 let presence: Result<::serde_json::Value, _> =
624 serde::Deserialize::deserialize(deserializer);
625 match presence {
626 Ok(serde_json::Value::Null) => Ok(Nullable::Null),
627 Ok(some_value) => serde_json::from_value(some_value)
628 .map(Nullable::Present)
629 .map_err(serde::de::Error::custom),
630 Err(x) => Err(x),
631 }
632 }
633}
634
635#[inline(never)]
636#[cold]
637fn expect_failed(msg: &str) -> ! {
638 panic!("{}", msg)
639}
640
641#[derive(Debug, Clone, PartialEq, PartialOrd)]
642/// Base64-encoded byte array
643pub struct ByteArray(pub Vec<u8>);
644
645impl Serialize for ByteArray {
646 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
647 where
648 S: Serializer,
649 {
650 serializer.serialize_str(&general_purpose::STANDARD.encode(&self.0))
651 }
652}
653
654impl<'de> Deserialize<'de> for ByteArray {
655 fn deserialize<D>(deserializer: D) -> Result<ByteArray, D::Error>
656 where
657 D: Deserializer<'de>,
658 {
659 let s = String::deserialize(deserializer)?;
660 match general_purpose::STANDARD.decode(s) {
661 Ok(bin) => Ok(ByteArray(bin)),
662 _ => Err(serde::de::Error::custom("invalid base64")),
663 }
664 }
665}