1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//! Content loaders for strings and bytes.

use axum::body::Body;
use std::path::Path;
use crate::Result;
use core::fmt;
use utils::*;

macro_rules! loader {
    ($(
        $(#[$attr:meta])*
        $name:ident -> $inner:ident(
            $(#[$alloc_attr:meta])*;$(#[$alloc_fn_attr:meta])*$alloc:ty;
            $(#[$static_attr:meta])*;$(#[$static_fn_attr:meta])*$static:ty;
        )
    )+) => ($(
        $(#[$attr])*
        #[repr(transparent)]
        #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
        pub struct $name($inner::$name);
        impl fmt::Debug for $name {
            #[inline]
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                self.0.fmt(f)
            }
        }
        impl From<$alloc> for $name {
            #[inline]
            fn from(s: $alloc) -> Self {
                Self($inner::$name::Alloc(s))
            }
        }
        impl From<$static> for $name {
            #[inline]
            fn from(s: $static) -> Self {
                Self($inner::$name::Static(s))
            }
        }
        impl From<$name> for Body {
            #[inline]
            fn from(this: $name) -> Self {
                Body::from(this.0)
            }
        }
        impl $name {
            $(#[$alloc_fn_attr])*
            #[inline]
            pub const fn new_static(s: $static) -> Self {
                Self($inner::$name::Static(s))
            }
            $(#[$static_fn_attr])*
            #[inline]
            pub fn new_alloc(s: $alloc) -> Self {
                Self($inner::$name::Alloc(s))
            }
        }
        mod $inner {
            use super::*;
            #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
            pub(crate) enum $name {
                $(#[$alloc_attr])*
                Alloc($alloc),
                $(#[$static_attr])*
                Static($static),
            }
            impl From<$name> for Body {
                #[inline]
                fn from(this: $name) -> Self {
                    match this {
                        $name::Alloc(s) => Body::from(s),
                        $name::Static(s) => Body::from(s),
                    }
                }
            }
        }
    )+);
}

loader!(
    /// A content loader for valid UTF-8 strings.
    StringContentLoader -> string_inner(/// An allocated String.
        ;/// Creates a new `StringContentLoader` from an allocated `String`.
        String;
        /// A static string.
        ;/// Creates a new `StringContentLoader` from a static string.
        &'static str;
    )
    /// A content loader for bytes.
    BytesContentLoader -> bytes_inner(/// An allocated Vec<u8>.
        ;/// Creates a new `BytesContentLoader` from an allocated `Vec<u8>`.
        Vec<u8>;
        /// A static byte slice.
        ;/// Creates a new `BytesContentLoader` from a static byte slice.
        &'static [u8];
    )
);

impl StringContentLoader {
    /// Creates a new `StringContentLoader` from a file.
    pub async fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
        tokio::fs::read_to_string(path).await.map_auto()
    }
}

impl BytesContentLoader {
    /// Creates a new `BytesContentLoader` from a file.
    pub async fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
        tokio::fs::read(path).await.map_auto()
    }
}

impl fmt::Display for StringContentLoader {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match &self.0 {
            string_inner::StringContentLoader::Alloc(s) => s.fmt(f),
            string_inner::StringContentLoader::Static(s) => s.fmt(f),
        }
    }
}

impl fmt::Display for BytesContentLoader {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match &self.0 {
            bytes_inner::BytesContentLoader::Alloc(s) => String::from_utf8_lossy(s).fmt(f),
            bytes_inner::BytesContentLoader::Static(s) => String::from_utf8_lossy(s).fmt(f),
        }
    }
}