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}