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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use serde::{Deserialize, Serialize};
use submillisecond::http::Uri;
use thiserror::Error;

use crate::rendered::Rendered;
use crate::socket::{Event, Socket};

/// Html input checkbox value.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CheckboxValue {
    /// Checked,
    #[serde(rename = "on")]
    Checked,
    /// Unchecked.
    #[serde(rename = "off")]
    Unchecked,
}

/// Deserialize event error.
#[derive(Debug, Error)]
pub enum DeserializeEventError {
    /// Deserialize form event error.
    #[error(transparent)]
    Form(#[from] serde_qs::Error),
    /// Deserialize event error.
    #[error(transparent)]
    Json(#[from] serde_json::Error),
}

/// A live view.
pub trait LiveView: Sized {
    /// Events registered with this liveview.
    type Events: EventList<Self>;

    /// The LiveView entry-point.
    ///
    /// Mount is invoked twice: once to do the initial page load, and again to
    /// establish the live socket.
    fn mount(uri: Uri, socket: Option<Socket>) -> Self;

    /// Renders a template.
    ///
    /// This callback is invoked whenever LiveView detects new content must be
    /// rendered and sent to the client.
    fn render(&self) -> Rendered;
}

/// Live view event handler.
pub trait LiveViewEvent<E> {
    /// Handler for the live view, typically used in the router.
    fn handle(state: &mut Self, event: E);
}

/// Event list is a trait to handle an incoming live view events and route them
/// to the event handlers.
pub trait EventList<T> {
    /// Handles an event, returning a Result, with a bool indicating if the
    /// event was handled or not.
    fn handle_event(state: &mut T, event: Event) -> Result<bool, DeserializeEventError>;
}

impl<T> EventList<T> for () {
    fn handle_event(_state: &mut T, _event: Event) -> Result<bool, DeserializeEventError> {
        Ok(false)
    }
}

#[cfg(debug_assertions)]
fn check_for_unit_struct<T>()
where
    T: for<'de> Deserialize<'de>,
{
    if serde_json::from_str::<T>("null").is_ok() {
        lunatic_log::error!(
            "unit structs are not supported as events. Change your event struct to be `{} {{}}`",
            std::any::type_name::<T>()
        );
    }
}

#[cfg(not(debug_assertions))]
fn check_for_unit_struct<T>() {}

macro_rules! impl_event_list {
    ($( $t: ident ),*) => {
        impl<T, $( $t ),*> EventList<T> for ($( $t, )*)
        where
            $(
                T: LiveViewEvent<$t>,
                $t: for<'de> Deserialize<'de>,
            )*
        {
            fn handle_event(state: &mut T, event: Event) -> Result<bool, DeserializeEventError> {
                $(
                    if std::any::type_name::<$t>() == event.name {
                        let value: $t = if event.ty == "form" {
                            match event.value.as_str() {
                                Some(value) => match serde_qs::from_str(value) {
                                    Ok(value) => value,
                                    Err(err) => {
                                        check_for_unit_struct::<$t>();
                                        return Err(DeserializeEventError::Form(err));
                                    }
                                }
                                None => {
                                    return Err(DeserializeEventError::Form(serde_qs::Error::Custom(
                                        "expected value to be string in form event".to_string(),
                                    )));
                                }
                            }
                        } else {
                            match serde_json::from_value(event.value) {
                                Ok(value) => value,
                                Err(err) => {
                                    check_for_unit_struct::<$t>();
                                    return Err(DeserializeEventError::Json(err));
                                }
                            }
                        };
                        T::handle(state, value);
                        return Ok(true);
                    }
                )*

                Ok(false)
            }
        }
    };
}

impl_event_list!(A);
impl_event_list!(A, B);
impl_event_list!(A, B, C);
impl_event_list!(A, B, C, D);
impl_event_list!(A, B, C, D, E);
impl_event_list!(A, B, C, D, E, F);
impl_event_list!(A, B, C, D, E, F, G);
impl_event_list!(A, B, C, D, E, F, G, H);
impl_event_list!(A, B, C, D, E, F, G, H, I);
impl_event_list!(A, B, C, D, E, F, G, H, I, J);
impl_event_list!(A, B, C, D, E, F, G, H, I, J, K);
impl_event_list!(A, B, C, D, E, F, G, H, I, J, K, L);

impl CheckboxValue {
    /// Returns a bool indicating if checkbox is checked.
    pub fn is_checked(&self) -> bool {
        match self {
            CheckboxValue::Checked => true,
            CheckboxValue::Unchecked => false,
        }
    }
}

impl Default for CheckboxValue {
    fn default() -> Self {
        CheckboxValue::Unchecked
    }
}