tag2upload_service_manager/
ui_abstract.rs

1
2use crate::prelude::*;
3
4/// Individual values that can be displayed in HTML pages
5pub trait UiDisplay {
6    fn ui_display(&self) -> Cow<str>;
7}
8
9/// Collections of name - value pairs, for HTML pages
10pub trait UiMap {
11    fn ui_serialize(&self) -> HashMap<&str, Cow<str>> {
12        let mut map = HashMap::new();
13        map.extend(self.ui_fields());
14        map
15    }
16
17    fn ui_fields(&self) -> impl Iterator<Item = (&str, Cow<str>)>;
18}
19
20pub struct UiSerializeMap<T>(pub T);
21
22impl<T: UiMap> Serialize for UiSerializeMap<T> {
23    fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
24        self.0
25            .ui_serialize()
26            .serialize(ser)
27    }
28}
29
30pub struct UiSerializeRows<R>(pub Vec<R>);
31
32impl<R: UiMap> Serialize for UiSerializeRows<R> {
33    fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
34        self.0.iter().map(|row| row.ui_serialize())
35            .collect_vec()
36            .serialize(ser)
37    }
38}
39
40define_derive_deftly! {
41    /// Implement `UiMap`
42    ///
43    /// Attributess:
44    ///  * **`#[deftly(ui(flatten))]`**
45    ///  * **`#[deftly(ui(skip))]`**
46    UiMap expect items:
47
48    impl $crate::ui_abstract::UiMap for $ttype {
49        fn ui_fields(&self) -> impl Iterator<Item = (&str, Cow<str>)> {
50            use $crate::ui_abstract::*;
51
52            chain!(
53                $(
54                    ${select1
55                      fmeta(ui(flatten)) {
56                          <$ftype as UiMap>::ui_fields(&self.$fname),
57                      }
58                      fmeta(ui(skip)) {
59                      }
60                      else {
61                          [(
62                              stringify!($fname),
63                              <$ftype as UiDisplay>::ui_display(&self.$fname),
64                          )],
65                      }
66                    }
67                )
68            )
69        }
70    }
71}
72
73define_derive_deftly! {
74    /// Implement `UiDisplay` for an enum of unit variants
75    UiDisplayEnum for enum, expect items:
76
77    impl $crate::ui_abstract::UiDisplay for $ttype {
78        fn ui_display(&self) -> Cow<str> {
79            match self {
80                $(
81                  ${if v_is_unit {
82                    $tname::$vname {} => Cow::Borrowed(stringify!($vname))
83                  } else {
84                    $tname::$vname(inner) => {
85                        $crate::ui_abstract::UiDisplay::ui_display(inner)
86                    }
87                  }},
88                )
89            }
90        }
91    }
92}
93
94impl UiDisplay for String {
95    fn ui_display(&self) -> Cow<str> { Cow::Borrowed(self) }
96}
97
98impl<T: UiDisplay + SuitableForNoneIsEmpty> UiDisplay for NoneIsEmpty<T> {
99    fn ui_display(&self) -> Cow<str> {
100        self.as_ref().map(|v| v.ui_display()).unwrap_or_default()
101    }
102}
103
104impl<T: UiDisplay> UiDisplay for Option<T> {
105    fn ui_display(&self) -> Cow<str> {
106        self.as_ref().map(|v| v.ui_display()).unwrap_or_default()
107    }
108}
109
110/// Implement `UiDisplay` in terms of `ToString`
111#[macro_export]
112macro_rules! ui_display_via_to_string { { $( $ty:ty )* } => { $(
113    impl $crate::ui_abstract::UiDisplay for $ty {
114        fn ui_display(&self) -> Cow<str> { Cow::Owned(self.to_string()) }
115    }
116)* } }
117
118ui_display_via_to_string! { i64 }