use async_trait::async_trait;
use flume::{Receiver, Sender};
use hyperchad_renderer::{
RendererEvent, View,
canvas::{self},
};
use thiserror::Error;
#[derive(Clone)]
pub struct HtmlRendererEventPub {
sender: Sender<RendererEvent>,
}
#[derive(Debug, Error)]
pub enum HtmlRendererEventPubError {
#[error(transparent)]
Sender(#[from] Box<flume::SendError<RendererEvent>>),
}
impl HtmlRendererEventPub {
#[must_use]
pub fn new() -> (Self, Receiver<RendererEvent>) {
let (tx, rx) = flume::unbounded();
(Self { sender: tx }, rx)
}
pub fn publish(&self, event: RendererEvent) -> Result<(), HtmlRendererEventPubError> {
Ok(self.sender.send(event).map_err(Box::new)?)
}
}
#[async_trait]
pub trait ExtendHtmlRenderer {
async fn emit_event(
&self,
_pub: HtmlRendererEventPub,
_event_name: String,
_event_value: Option<String>,
) -> Result<(), Box<dyn std::error::Error + Send + 'static>> {
Ok(())
}
async fn render(
&self,
_pub: HtmlRendererEventPub,
_view: View,
) -> Result<(), Box<dyn std::error::Error + Send + 'static>> {
Ok(())
}
async fn render_canvas(
&self,
_pub: HtmlRendererEventPub,
_update: canvas::CanvasUpdate,
) -> Result<(), Box<dyn std::error::Error + Send + 'static>> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test_log::test]
fn test_html_renderer_event_pub_new() {
let (pub_handle, rx) = HtmlRendererEventPub::new();
assert!(!rx.is_disconnected());
drop(pub_handle);
assert!(rx.is_disconnected());
}
#[test_log::test]
fn test_html_renderer_event_pub_publish() {
let (pub_handle, rx) = HtmlRendererEventPub::new();
let event = RendererEvent::Event {
name: "test".to_string(),
value: None,
};
pub_handle.publish(event).unwrap();
let received = rx.recv().unwrap();
assert!(matches!(received, RendererEvent::Event { .. }));
}
#[test_log::test]
fn test_html_renderer_event_pub_publish_disconnected() {
let (pub_handle, rx) = HtmlRendererEventPub::new();
drop(rx);
let event = RendererEvent::Event {
name: "test".to_string(),
value: None,
};
let result = pub_handle.publish(event);
assert!(result.is_err());
}
#[test_log::test]
fn test_html_renderer_event_pub_clone() {
let (pub_handle, rx) = HtmlRendererEventPub::new();
let pub_handle_clone = pub_handle.clone();
let event1 = RendererEvent::Event {
name: "event1".to_string(),
value: Some("value1".to_string()),
};
let event2 = RendererEvent::Event {
name: "event2".to_string(),
value: Some("value2".to_string()),
};
pub_handle.publish(event1).unwrap();
pub_handle_clone.publish(event2).unwrap();
assert!(rx.recv().is_ok());
assert!(rx.recv().is_ok());
}
}