From aaf9c28845b32d049b50f23f9f229f382357cf7d Mon Sep 17 00:00:00 2001 From: Ari Seyhun Date: Mon, 21 Nov 2022 16:53:41 +0800 Subject: [PATCH 1/3] Add support for anonymous events --- Cargo.toml | 13 ++- examples/clock.rs | 2 +- examples/counter.rs | 30 ++---- examples/list.rs | 2 +- examples/todos.rs | 8 +- src/event_handler.rs | 13 ++- src/handler.rs | 1 - src/live_view.rs | 19 ++-- src/manager.rs | 10 +- src/maud.rs | 7 +- src/rendered.rs | 67 ++++++++++--- src/rendered/builder.rs | 211 +++++++++++++++++++++++++++++++--------- 12 files changed, 273 insertions(+), 110 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f888534..b45d10c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,11 @@ enumflags2 = "0.7" hmac = { version = "0.12.1", features = ["std"] } itertools = "0.10" jwt = "0.16.0" -lunatic = { version = "0.12", features = ["json_serializer"] } -lunatic-log = "0.3" -maud-live-view = "0.24.2" +lunatic = { path = "../lunatic-rs", version = "0.12", features = [ + "json_serializer", +] } +lunatic-log = { path = "../logger-rs", version = "0.3" } +maud-live-view = { path = "../maud_live_view/maud_live_view" } pretty_assertions = "1.3" rand = "0.8" serde = { version = "1.0", features = ["derive"] } @@ -23,7 +25,10 @@ serde_json = "1.0" serde_qs = "0.10" sha2 = "0.10.6" slotmap = "1.0" -submillisecond = { version = "0.2.0", features = ["cookies", "websocket"] } +submillisecond = { path = "../submillisecond", version = "0.2.0", features = [ + "cookies", + "websocket", +] } thiserror = "1.0" tungstenite = "0.17" diff --git a/examples/clock.rs b/examples/clock.rs index d5ef43f..debfca9 100644 --- a/examples/clock.rs +++ b/examples/clock.rs @@ -61,7 +61,7 @@ impl LiveView for Clock { } } - fn render(&self) -> Rendered { + fn render(&self) -> Rendered { let tzs = chrono_tz::TZ_VARIANTS.iter(); html! { diff --git a/examples/counter.rs b/examples/counter.rs index 1c5f239..ade4a18 100644 --- a/examples/counter.rs +++ b/examples/counter.rs @@ -16,16 +16,20 @@ struct Counter { } impl LiveView for Counter { - type Events = (Increment, Decrement); + type Events = (); fn mount(_uri: Uri, _socket: Option) -> Self { Counter { count: 0 } } - fn render(&self) -> Rendered { + fn render(&self) -> Rendered { html! { - button @click=(Increment) { "Increment" } - button @click=(Decrement) { "Decrement" } + button @click=(|state| state.count += 1) { + "Increment" + } + button @click=(|state| state.count -= 1) { + "Decrement" + } p { "Count is " (self.count) } @if self.count >= 5 { p { "Count is high!" } @@ -39,21 +43,3 @@ impl LiveView for Counter { .with_style(Style::Link("/static/counter.css")) } } - -#[derive(Serialize, Deserialize)] -struct Increment {} - -impl LiveViewEvent for Counter { - fn handle(state: &mut Self, _event: Increment) { - state.count += 1; - } -} - -#[derive(Serialize, Deserialize)] -struct Decrement {} - -impl LiveViewEvent for Counter { - fn handle(state: &mut Self, _event: Decrement) { - state.count -= 1; - } -} diff --git a/examples/list.rs b/examples/list.rs index e3ed461..f4d2d0c 100644 --- a/examples/list.rs +++ b/examples/list.rs @@ -24,7 +24,7 @@ impl LiveView for List { } } - fn render(&self) -> Rendered { + fn render(&self) -> Rendered { html! { button @click=(Add) { "Increment" } button @click=(Remove) { "Decrement" } diff --git a/examples/todos.rs b/examples/todos.rs index 64aee21..803efa6 100644 --- a/examples/todos.rs +++ b/examples/todos.rs @@ -35,7 +35,7 @@ impl LiveView for Todos { } } - fn render(&self) -> Rendered { + fn render(&self) -> Rendered { let rendered = html! { section.todoapp { @(self.render_header()) @@ -172,7 +172,7 @@ enum Filter { } impl Todos { - fn render_header(&self) -> Rendered { + fn render_header(&self) -> Rendered { html! { header.header { h1 { "todos" } @@ -195,7 +195,7 @@ impl Todos { } } - fn render_main(&self) -> Rendered { + fn render_main(&self) -> Rendered { let visible_todos: Vec<_> = match self.filter { Filter::All => self.todos.iter().collect(), Filter::Active => self.todos.iter().filter(|todo| !todo.completed).collect(), @@ -247,7 +247,7 @@ impl Todos { } } - fn render_footer(&self) -> Rendered { + fn render_footer(&self) -> Rendered { let remaining_todos = self.todos.iter().filter(|todo| !todo.completed).count(); let filter_links = [ ("All", Filter::All), diff --git a/src/event_handler.rs b/src/event_handler.rs index acaa4b6..dfe486b 100644 --- a/src/event_handler.rs +++ b/src/event_handler.rs @@ -8,6 +8,8 @@ use crate::manager::{Join, LiveViewManager}; use crate::socket::{Event, JoinEvent, RawSocket, Socket}; use crate::{EventList, LiveView}; +pub type AnonymousEventHandler = fn(state: &mut T, event_name: &str) -> bool; + #[derive(Clone, Debug, Error, Serialize, Deserialize)] pub enum EventHandlerError { #[error("deserialize event failed")] @@ -120,7 +122,16 @@ fn event_handler( EventHandlerMessage::HandleEvent(parent, tag, event) => { let reply = match &mut state { Some((live_view, state)) => { - match >::handle_event(live_view, event.clone()) { + println!("Handling anonymous event"); + let handled = if !state.handle_anonymous_event(live_view, &event.name) { + >::handle_event(live_view, event.clone()) + } else { + Ok(true) + }; + + println!("we here now"); + + match handled { Ok(handled) => { if !handled { Err(EventHandlerError::UnknownEvent) diff --git a/src/handler.rs b/src/handler.rs index 229397f..3476aae 100644 --- a/src/handler.rs +++ b/src/handler.rs @@ -76,7 +76,6 @@ where }; ws.on_upgrade(self.live_view.clone(), |conn, live_view| { - println!("Waiting for join"); let (mut socket, mut message) = match wait_for_join(conn) { Ok((socket, message)) => (socket, message), Err(err) => { diff --git a/src/live_view.rs b/src/live_view.rs index 2344bb0..b6dd7b3 100644 --- a/src/live_view.rs +++ b/src/live_view.rs @@ -35,18 +35,20 @@ pub trait LiveView: Sized { /// The LiveView entry-point. /// - /// Mount is invoked twice: once to do the initial page load, and again to establish the live socket. + /// Mount is invoked twice: once to do the initial page load, and again to + /// establish the live socket. fn mount(uri: Uri, socket: Option) -> 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; + /// This callback is invoked whenever LiveView detects new content must be + /// rendered and sent to the client. + fn render(&self) -> Rendered; /// Html head content, including page title, meta tags, styles and scripts. /// - /// By default, the LiveView JavaScript is included when the `liveview_js` feature flag is - /// enabled. + /// By default, the LiveView JavaScript is included when the `liveview_js` + /// feature flag is enabled. /// /// # Example /// @@ -66,10 +68,11 @@ pub trait LiveViewEvent { 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. +/// Event list is a trait to handle an incoming live view events and route them +/// to the event handlers. pub trait EventList { - /// Handles an event, returning a Result, with a bool indicating if the event was handled or not. + /// 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; } diff --git a/src/manager.rs b/src/manager.rs index 9e9f6ea..0b9d8b1 100644 --- a/src/manager.rs +++ b/src/manager.rs @@ -5,6 +5,7 @@ use serde_json::Value; use submillisecond::response::Response; use submillisecond::RequestContext; +use crate::rendered::Rendered; use crate::socket::{Event, JoinEvent, Socket}; use crate::LiveView; @@ -14,7 +15,6 @@ where Self: Sized, T: LiveView, { - type State: Serialize + for<'de> Deserialize<'de>; // type Reply: Serialize; type Error: fmt::Display; @@ -26,13 +26,13 @@ where &self, socket: Socket, event: JoinEvent, - ) -> LiveViewManagerResult, Self::Error>; + ) -> LiveViewManagerResult, Self::Error>; /// Handle an event. fn handle_event( &self, event: Event, - state: &mut Self::State, + state: &mut Rendered, live_view: &T, ) -> LiveViewManagerResult, Self::Error>; } @@ -48,9 +48,9 @@ pub(crate) enum LiveViewManagerResult { FatalError(E), } -pub(crate) struct Join { +pub(crate) struct Join { pub(crate) live_view: L, - pub(crate) state: S, + pub(crate) state: Rendered, pub(crate) reply: R, } diff --git a/src/maud.rs b/src/maud.rs index 3dbced7..c3a506c 100644 --- a/src/maud.rs +++ b/src/maud.rs @@ -73,7 +73,6 @@ impl LiveViewManager for LiveViewMaud where T: LiveView, { - type State = Rendered; // type Reply = Value; type Error = LiveViewMaudError; @@ -97,7 +96,7 @@ where let head = T::head(); - let body = html! { + let body: Rendered<()> = html! { (DOCTYPE) html lang="en" { head { @@ -142,7 +141,7 @@ where &self, socket: Socket, event: JoinEvent, - ) -> LiveViewManagerResult, Self::Error> { + ) -> LiveViewManagerResult, Self::Error> { let key: Hmac = Hmac::new_from_slice(&secret()).expect("unable to encode secret"); let session: Result = event.session.verify_with_key(&key); @@ -182,7 +181,7 @@ where fn handle_event( &self, _event: Event, - state: &mut Self::State, + state: &mut Rendered, live_view: &T, ) -> LiveViewManagerResult, Self::Error> { let rendered = live_view.render(); diff --git a/src/rendered.rs b/src/rendered.rs index 0e4ed2a..b36b83c 100644 --- a/src/rendered.rs +++ b/src/rendered.rs @@ -14,24 +14,27 @@ mod dynamic; mod strip; use core::fmt; +use std::marker::PhantomData; use serde::{Deserialize, Serialize}; use serde_json::{Map, Value}; pub use self::builder::*; -use self::{ - dynamic::{Dynamic, DynamicItems, DynamicList, Dynamics}, - strip::Strip, -}; +use self::dynamic::{Dynamic, DynamicItems, DynamicList, Dynamics}; +use self::strip::Strip; +use crate::event_handler::AnonymousEventHandler; /// Rendered HTML containing statics, dynamics and templates. /// /// Rendered is typically generated by the `html!` macro. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Rendered { +#[derive(Serialize, Deserialize)] +#[serde(bound = "")] +pub struct Rendered { statics: Vec, dynamics: Dynamics, templates: Vec>, + anonymous_events: Vec, + phantom: PhantomData, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -55,14 +58,15 @@ pub trait IntoJson: Sized { } } -impl Rendered { +impl Rendered { /// Creates a RenderedBuilder. - pub fn builder() -> builder::RenderedBuilder { + pub fn builder() -> builder::RenderedBuilder { builder::RenderedBuilder::new() } - /// Diffs self with another [`Rendered`] and returns diff as [`serde_json::Value`]. - pub fn diff(self, other: Rendered) -> Option { + /// Diffs self with another [`Rendered`] and returns diff as + /// [`serde_json::Value`]. + pub fn diff(self, other: Rendered) -> Option { let a = self.into_json(); let b = other.into_json(); let diff = diff::diff(&a, &b).unwrap_or_default(); @@ -71,9 +75,39 @@ impl Rendered { _ => None, } } + + pub(crate) fn handle_anonymous_event(&self, state: &mut T, event_name: &str) -> bool { + self.anonymous_events.iter().copied().any(|handler_id| { + let handler: AnonymousEventHandler = unsafe { std::mem::transmute(handler_id) }; + handler(state, event_name) + }) + } +} + +impl Clone for Rendered { + fn clone(&self) -> Self { + Self { + statics: self.statics.clone(), + dynamics: self.dynamics.clone(), + templates: self.templates.clone(), + anonymous_events: self.anonymous_events.clone(), + phantom: PhantomData, + } + } } -impl fmt::Display for Rendered { +impl fmt::Debug for Rendered { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Rendered") + .field("statics", &self.statics) + .field("dynamics", &self.dynamics) + .field("templates", &self.templates) + .field("anonymous_events", &self.anonymous_events.len()) + .finish() + } +} + +impl fmt::Display for Rendered { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match &self.dynamics { Dynamics::Items(DynamicItems(items)) => { @@ -107,6 +141,15 @@ impl fmt::Display for Rendered { } } +impl PartialEq for Rendered { + fn eq(&self, other: &Self) -> bool { + self.statics == other.statics + && self.dynamics == other.dynamics + && self.templates == other.templates + && self.anonymous_events == other.anonymous_events + } +} + fn fmt_dynamic_list_item( templates: &Vec>, d: &Dynamic, @@ -133,7 +176,7 @@ fn fmt_dynamic_list_item( Ok(()) } -impl IntoJson for Rendered { +impl IntoJson for Rendered { fn write_json(self, map: &mut Map) { if !self.statics.is_empty() { map.insert( diff --git a/src/rendered/builder.rs b/src/rendered/builder.rs index 70a4d02..5780c2b 100644 --- a/src/rendered/builder.rs +++ b/src/rendered/builder.rs @@ -1,37 +1,42 @@ //! Builder to build [`Rendered`], used by the `html!` macro. +use std::fmt; +use std::marker::PhantomData; + use slotmap::{new_key_type, SlotMap}; use super::dynamic::DynamicList; use super::{Dynamic, DynamicItems, Dynamics, Rendered, RenderedListItem}; +use crate::event_handler::AnonymousEventHandler; new_key_type! { struct NodeId; } /// Rendered builder, used by the `html!` macro. #[derive(Debug)] -pub struct RenderedBuilder { - nodes: SlotMap, +pub struct RenderedBuilder { + nodes: SlotMap>, last_node: NodeId, } #[derive(Debug)] -struct Node { +struct Node { parent: NodeId, - value: NodeValue, + value: NodeValue, } #[derive(Debug)] -enum NodeValue { - Items(ItemsNode), +enum NodeValue { + Items(ItemsNode), List(ListNode), - Nested(Rendered), + Nested(Rendered), } -#[derive(Debug, Default)] -struct ItemsNode { +struct ItemsNode { statics: Vec, dynamics: Vec, templates: Vec>, + anonymous_events: Vec, + phantom: PhantomData, } #[derive(Debug)] @@ -47,7 +52,7 @@ enum DynamicNode { Nested(NodeId), } -impl RenderedBuilder { +impl RenderedBuilder { /// Creates a new [`RenderedBuilder`]. pub fn new() -> Self { let mut nodes = SlotMap::with_key(); @@ -59,13 +64,18 @@ impl RenderedBuilder { } /// Builds into a [`Rendered`]. - pub fn build(mut self) -> Rendered { + pub fn build(mut self) -> Rendered { let root = self.nodes.remove(self.last_node).unwrap(); root.build(&mut self) } + /// Pushes an anonymous event. + pub fn push_anonymous_event(&mut self, handler: AnonymousEventHandler) { + self.last_node_mut().push_anonymous_event(handler) + } + /// Pushes a [`Rendered`] to be nested. - pub fn push_nested(&mut self, other: Rendered) { + pub fn push_nested(&mut self, other: Rendered) { let parent = self.parent_of(self.last_node).unwrap(); let id = self .nodes @@ -132,7 +142,7 @@ impl RenderedBuilder { } } - fn last_node_mut(&mut self) -> &mut Node { + fn last_node_mut(&mut self) -> &mut Node { self.nodes.get_mut(self.last_node).unwrap() } @@ -140,7 +150,7 @@ impl RenderedBuilder { self.nodes.get(id).map(|node| node.parent) } - fn push_dynamic_node(&mut self, value: NodeValue) { + fn push_dynamic_node(&mut self, value: NodeValue) { let id = self.nodes.insert(Node::new(self.last_node, value)); let last_node = self.last_node_mut(); match &mut last_node.value { @@ -161,18 +171,18 @@ impl RenderedBuilder { } } -impl Default for RenderedBuilder { +impl Default for RenderedBuilder { fn default() -> Self { Self::new() } } -impl Node { - fn new(parent: NodeId, value: NodeValue) -> Self { +impl Node { + fn new(parent: NodeId, value: NodeValue) -> Self { Node { parent, value } } - fn build(self, tree: &mut RenderedBuilder) -> Rendered { + fn build(self, tree: &mut RenderedBuilder) -> Rendered { match self.value { NodeValue::Items(items) => items.build(tree), NodeValue::List(list) => list.build(tree), @@ -180,6 +190,14 @@ impl Node { } } + fn push_anonymous_event(&mut self, handler: AnonymousEventHandler) { + match &mut self.value { + NodeValue::Items(items) => items.push_anonymous_event(handler), + NodeValue::List(_) => todo!(), + NodeValue::Nested(_) => todo!(), + } + } + fn push_static(&mut self, s: &str) { match &mut self.value { NodeValue::Items(items) => items.push_static(s), @@ -197,8 +215,8 @@ impl Node { } } -impl ItemsNode { - fn build(mut self, tree: &mut RenderedBuilder) -> Rendered { +impl ItemsNode { + fn build(mut self, tree: &mut RenderedBuilder) -> Rendered { let dynamics: Vec<_> = self .dynamics .into_iter() @@ -211,9 +229,15 @@ impl ItemsNode { statics: self.statics, dynamics: Dynamics::Items(DynamicItems(dynamics)), templates: self.templates, + anonymous_events: self.anonymous_events, + phantom: PhantomData, } } + fn push_anonymous_event(&mut self, handler: AnonymousEventHandler) { + self.anonymous_events.push(handler as usize); + } + fn push_static(&mut self, s: &str) { push_or_extend_static_string(&mut self.statics, self.dynamics.len(), s); } @@ -227,8 +251,31 @@ impl ItemsNode { } } +impl Default for ItemsNode { + fn default() -> Self { + Self { + statics: Default::default(), + dynamics: Default::default(), + templates: Default::default(), + anonymous_events: Default::default(), + phantom: PhantomData, + } + } +} + +impl fmt::Debug for ItemsNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ItemsNode") + .field("statics", &self.statics) + .field("dynamics", &self.dynamics) + .field("templates", &self.templates) + .field("anonymous_events", &self.anonymous_events.len()) + .finish() + } +} + impl ListNode { - fn build(self, tree: &mut RenderedBuilder) -> Rendered { + fn build(self, tree: &mut RenderedBuilder) -> Rendered { let mut templates = vec![]; let dynamics: Vec> = self @@ -246,6 +293,8 @@ impl ListNode { statics: self.statics, dynamics: Dynamics::List(DynamicList(dynamics)), templates, + anonymous_events: vec![], + phantom: PhantomData, } } @@ -275,7 +324,7 @@ impl Default for ListNode { } impl DynamicNode { - fn build_items(self, tree: &mut RenderedBuilder) -> Dynamic { + fn build_items(self, tree: &mut RenderedBuilder) -> Dynamic> { match self { DynamicNode::String(s) => Dynamic::String(s), DynamicNode::Nested(id) => { @@ -300,6 +349,8 @@ impl DynamicNode { statics: nested.statics, dynamics: Dynamics::List(list), templates: nested.templates, + anonymous_events: nested.anonymous_events, + phantom: PhantomData, }) } } @@ -308,9 +359,9 @@ impl DynamicNode { } } - fn build_list( + fn build_list( self, - tree: &mut RenderedBuilder, + tree: &mut RenderedBuilder, templates: &mut Vec>, ) -> Dynamic { match self { @@ -381,6 +432,8 @@ fn vecs_match(a: &Vec, b: &Vec) -> bool { #[cfg(test)] mod tests { + use std::marker::PhantomData; + use pretty_assertions::assert_eq; use crate::maud::DOCTYPE; @@ -392,7 +445,7 @@ mod tests { #[lunatic::test] fn basic() { - let rendered = html! { + let rendered: Rendered<()> = html! { p { "Hello, world!" } }; @@ -403,7 +456,7 @@ mod tests { #[lunatic::test] fn dynamic() { - let rendered = html! { + let rendered: Rendered<()> = html! { (DOCTYPE) a href={ ("hey") "/lambda-fairy/maud" } { "Hello, world!" @@ -422,7 +475,9 @@ mod tests { Dynamic::String("".to_string()), Dynamic::String("hey".to_string()) ])), - templates: vec![] + templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -430,7 +485,7 @@ mod tests { #[lunatic::test] fn if_statement_false() { let logged_in = false; - let rendered = html! { + let rendered: Rendered<()> = html! { "Welcome " @if logged_in { "person" @@ -443,12 +498,14 @@ mod tests { Rendered { statics: vec!["Welcome ".to_string(), ".".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![Dynamic::String("".to_string())])), - templates: vec![] + templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); let logged_in = false; - let rendered = html! { + let rendered: Rendered<()> = html! { "Welcome " @if logged_in { (logged_in.to_string()) @@ -461,7 +518,9 @@ mod tests { Rendered { statics: vec!["Welcome ".to_string(), ".".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![Dynamic::String("".to_string())])), - templates: vec![] + templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -469,7 +528,7 @@ mod tests { #[lunatic::test] fn if_statement_true() { let logged_in = true; - let rendered = html! { + let rendered: Rendered<()> = html! { "Welcome " @if logged_in { "person" @@ -485,13 +544,17 @@ mod tests { statics: vec!["person".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); let logged_in = true; - let rendered = html! { + let rendered: Rendered<()> = html! { "Welcome " @if logged_in { (logged_in.to_string()) @@ -509,8 +572,12 @@ mod tests { "true".to_string() )])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -518,7 +585,7 @@ mod tests { #[lunatic::test] fn if_statement_let_some() { let user = Some("Bob"); - let rendered = html! { + let rendered: Rendered<()> = html! { "Welcome " @if let Some(user) = user { (user) @@ -537,8 +604,12 @@ mod tests { "Bob".to_string() )])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -546,7 +617,7 @@ mod tests { #[lunatic::test] fn if_statement_let_none() { let user: Option<&str> = None; - let rendered = html! { + let rendered: Rendered<()> = html! { "Welcome " @if let Some(user) = user { (user) @@ -563,15 +634,19 @@ mod tests { statics: vec!["stranger".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } #[lunatic::test] fn if_statement_nested() { - let render = |count: usize| { + let render = |count: usize| -> Rendered<()> { html! { @if count >= 1 { p { "Count is high" } @@ -590,6 +665,8 @@ mod tests { statics: vec!["".to_string(), "".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![Dynamic::String("".to_string())])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); @@ -603,8 +680,12 @@ mod tests { statics: vec!["

Count is high

".to_string(), "".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![Dynamic::String("".to_string())])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); @@ -620,10 +701,16 @@ mod tests { statics: vec!["

Count is very high!

".to_string()], dynamics: Dynamics::Items(DynamicItems(vec![])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -631,7 +718,7 @@ mod tests { #[lunatic::test] fn for_loop_empty() { #[allow(clippy::reversed_empty_ranges)] - let rendered = html! { + let rendered: Rendered<()> = html! { span { "Hello" } @for _ in 0..0 { span { "Hi!" } @@ -648,13 +735,15 @@ mod tests { ], dynamics: Dynamics::Items(DynamicItems(vec![Dynamic::String("".to_string())])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } #[lunatic::test] fn for_loop_statics() { - let rendered = html! { + let rendered: Rendered<()> = html! { @for _ in 0..3 { span { "Hi!" } } @@ -668,8 +757,12 @@ mod tests { statics: vec!["Hi!".to_string()], dynamics: Dynamics::List(DynamicList(vec![vec![], vec![], vec![]])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -677,7 +770,7 @@ mod tests { #[lunatic::test] fn for_loop_dynamics() { let names = ["John", "Joe", "Jim"]; - let rendered = html! { + let rendered: Rendered<()> = html! { @for name in names { span { (name) } } @@ -695,13 +788,17 @@ mod tests { vec![Dynamic::String("Jim".to_string())], ])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); let names = ["John", "Joe", "Jim"]; - let rendered = html! { + let rendered: Rendered<()> = html! { @for name in names { span class=(name) { (name) } } @@ -732,8 +829,12 @@ mod tests { ], ])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -741,7 +842,7 @@ mod tests { #[lunatic::test] fn for_loop_multiple() { #[allow(clippy::reversed_empty_ranges)] - let rendered = html! { + let rendered: Rendered<()> = html! { span { "Hello" } @for _ in 0..2 { span { "A" } @@ -766,11 +867,15 @@ mod tests { Dynamic::Nested(Rendered { statics: vec!["A".to_string()], dynamics: Dynamics::List(DynamicList(vec![vec![], vec![]])), - templates: vec![] + templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, }), Dynamic::String("".to_string()), ])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -778,7 +883,7 @@ mod tests { #[lunatic::test] fn for_loop_with_if() { let names = ["John", "Joe", "Jim"]; - let rendered = html! { + let rendered: Rendered<()> = html! { @for name in names { span { "Welcome, " (name) "." } @if name == "Jim" { @@ -818,8 +923,12 @@ mod tests { "You are a VIP, ".to_string(), "".to_string() ]], + anonymous_events: vec![], + phantom: PhantomData, })])), - templates: vec![] + templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -827,7 +936,7 @@ mod tests { #[lunatic::test] fn for_loop_with_multiple_ifs() { let names = ["John", "Joe", "Jim"]; - let rendered = html! { + let rendered: Rendered<()> = html! { @for name in names { span { "Welcome, " (name) "." } @if name == "Jim" { @@ -880,8 +989,12 @@ mod tests { "".to_string() ], ], + anonymous_events: vec![], + phantom: PhantomData, })])), templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } @@ -889,7 +1002,7 @@ mod tests { #[lunatic::test] fn for_loop_with_many_ifs() { let names = ["John", "Joe", "Jim"]; - let rendered = html! { + let rendered: Rendered<()> = html! { @for name in names { span { "Welcome, " (name) "." } @if name == "Jim" || name == "Joe" { @@ -951,8 +1064,12 @@ mod tests { "".to_string() ], ], + anonymous_events: vec![], + phantom: PhantomData, })])), - templates: vec![] + templates: vec![], + anonymous_events: vec![], + phantom: PhantomData, } ); } From a141e595fad30ca8deeeff8a332bdda39da16804 Mon Sep 17 00:00:00 2001 From: Ari Seyhun Date: Mon, 21 Nov 2022 17:47:54 +0800 Subject: [PATCH 2/3] Remove path dependencies --- Cargo.toml | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b45d10c..f888534 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,9 @@ enumflags2 = "0.7" hmac = { version = "0.12.1", features = ["std"] } itertools = "0.10" jwt = "0.16.0" -lunatic = { path = "../lunatic-rs", version = "0.12", features = [ - "json_serializer", -] } -lunatic-log = { path = "../logger-rs", version = "0.3" } -maud-live-view = { path = "../maud_live_view/maud_live_view" } +lunatic = { version = "0.12", features = ["json_serializer"] } +lunatic-log = "0.3" +maud-live-view = "0.24.2" pretty_assertions = "1.3" rand = "0.8" serde = { version = "1.0", features = ["derive"] } @@ -25,10 +23,7 @@ serde_json = "1.0" serde_qs = "0.10" sha2 = "0.10.6" slotmap = "1.0" -submillisecond = { path = "../submillisecond", version = "0.2.0", features = [ - "cookies", - "websocket", -] } +submillisecond = { version = "0.2.0", features = ["cookies", "websocket"] } thiserror = "1.0" tungstenite = "0.17" From 2059e3290f6a8ecb98aca451c72e075c762b8494 Mon Sep 17 00:00:00 2001 From: Ari Seyhun Date: Mon, 21 Nov 2022 17:49:56 +0800 Subject: [PATCH 3/3] Fix diff tests --- tests/diff.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/diff.rs b/tests/diff.rs index 33f15e8..8ba55e3 100644 --- a/tests/diff.rs +++ b/tests/diff.rs @@ -11,7 +11,7 @@ fn dynamic_diff() { } }; - let diff = render("hey").diff(render("there")); + let diff = render("hey").diff::<()>(render("there")); assert_eq!( diff, Some(json!({ @@ -32,7 +32,7 @@ fn if_statement_false_to_true_diff() { } }; - let diff = render(false).diff(render(true)); + let diff = render(false).diff::<()>(render(true)); assert_eq!( diff, Some(json!({ @@ -54,7 +54,7 @@ fn if_statement_false_to_true_diff() { } }; - let diff = render(false).diff(render(true)); + let diff = render(false).diff::<()>(render(true)); assert_eq!( diff, Some(json!({ @@ -81,7 +81,7 @@ fn if_statement_true_to_false_diff() { } }; - let diff = render(true).diff(render(false)); + let diff = render(true).diff::<()>(render(false)); assert_eq!( diff, Some(json!({ @@ -99,7 +99,7 @@ fn if_statement_true_to_false_diff() { } }; - let diff = render(true).diff(render(false)); + let diff = render(true).diff::<()>(render(false)); assert_eq!( diff, Some(json!({ @@ -121,7 +121,7 @@ fn if_statement_let_none_to_some_diff() { } }; - let diff = render(None).diff(render(Some("Bob"))); + let diff = render(None).diff::<()>(render(Some("Bob"))); assert_eq!( diff, Some(json!({ @@ -149,7 +149,7 @@ fn if_statement_let_some_to_none_diff() { } }; - let diff = render(Some("Bob")).diff(render(None)); + let diff = render(Some("Bob")).diff::<()>(render(None)); assert_eq!( diff, Some(json!({ @@ -175,7 +175,7 @@ fn if_statement_nested_diff() { } }; - let diff = render(0).diff(render(1)); + let diff = render(0).diff::<()>(render(1)); assert_eq!( diff, Some(json!({ @@ -189,7 +189,7 @@ fn if_statement_nested_diff() { })) ); - let diff = render(1).diff(render(2)); + let diff = render(1).diff::<()>(render(2)); assert_eq!( diff, Some(json!({ @@ -203,7 +203,7 @@ fn if_statement_nested_diff() { })) ); - let diff = render(2).diff(render(3)); + let diff = render(2).diff::<()>(render(3)); assert_eq!(diff, None); } @@ -217,7 +217,7 @@ fn for_loop_statics() { } }; - let diff = render(&[]).diff(render(&["John"])); + let diff = render(&[]).diff::<()>(render(&["John"])); assert_eq!( diff, Some(json!({ @@ -232,7 +232,7 @@ fn for_loop_statics() { })) ); - let diff = render(&["John"]).diff(render(&["John", "Jim"])); + let diff = render(&["John"]).diff::<()>(render(&["John", "Jim"])); assert_eq!( diff, Some(json!({ @@ -245,7 +245,7 @@ fn for_loop_statics() { })) ); - let diff = render(&["John", "Jim"]).diff(render(&["John"])); + let diff = render(&["John", "Jim"]).diff::<()>(render(&["John"])); assert_eq!( diff, Some(json!({ @@ -257,7 +257,7 @@ fn for_loop_statics() { })) ); - let diff = render(&["John"]).diff(render(&[])); + let diff = render(&["John"]).diff::<()>(render(&[])); assert_eq!( diff, Some(json!({ @@ -278,7 +278,7 @@ fn for_loop_dynamics() { } }; - let diff = render(&[]).diff(render(&["John"])); + let diff = render(&[]).diff::<()>(render(&["John"])); assert_eq!( diff, Some(json!({ @@ -296,7 +296,7 @@ fn for_loop_dynamics() { })) ); - let diff = render(&["John"]).diff(render(&["John", "Joe"])); + let diff = render(&["John"]).diff::<()>(render(&["John", "Joe"])); assert_eq!( diff, Some(json!({ @@ -313,7 +313,7 @@ fn for_loop_dynamics() { })) ); - let diff = render(&["John", "Joe"]).diff(render(&["John", "Joe", "Jim"])); + let diff = render(&["John", "Joe"]).diff::<()>(render(&["John", "Joe", "Jim"])); assert_eq!( diff, Some(json!({ @@ -333,7 +333,7 @@ fn for_loop_dynamics() { })) ); - let diff = render(&["John", "Joe"]).diff(render(&["John"])); + let diff = render(&["John", "Joe"]).diff::<()>(render(&["John"])); assert_eq!( diff, Some(json!({ @@ -347,7 +347,7 @@ fn for_loop_dynamics() { })) ); - let diff = render(&["John"]).diff(render(&[])); + let diff = render(&["John"]).diff::<()>(render(&[])); assert_eq!( diff, Some(json!({