use alloc::boxed::Box;
use ratatui_core::{buffer::Buffer, layout::Rect};
use crate::{effect::Effect, shader::Shader, CellFilter, ColorSpace, Duration, EffectTimer};
#[derive(Clone, Debug)]
pub(crate) struct RunOnce {
effect: Effect,
has_run: bool,
}
impl RunOnce {
pub(crate) fn new(effect: Effect) -> Self {
Self { effect, has_run: false }
}
}
impl Shader for RunOnce {
fn name(&self) -> &'static str {
"run_once"
}
fn process(&mut self, duration: Duration, buf: &mut Buffer, area: Rect) -> Option<Duration> {
if !self.has_run {
self.has_run = true;
self.effect.process(duration, buf, area)
} else {
None
}
}
fn done(&self) -> bool {
self.has_run
}
fn clone_box(&self) -> Box<dyn Shader> {
Box::new(self.clone())
}
fn area(&self) -> Option<Rect> {
self.effect.area()
}
fn set_area(&mut self, area: Rect) {
self.effect.set_area(area);
}
fn filter(&mut self, strategy: CellFilter) {
self.effect.filter(strategy);
}
fn reverse(&mut self) {
self.effect.reverse();
}
fn timer_mut(&mut self) -> Option<&mut EffectTimer> {
None
}
fn cell_filter(&self) -> Option<&CellFilter> {
self.effect.cell_filter()
}
fn reset(&mut self) {
self.has_run = false;
self.effect.reset();
}
fn color_space(&self) -> ColorSpace {
self.effect.color_space()
}
fn set_color_space(&mut self, color_space: ColorSpace) {
self.effect.set_color_space(color_space);
}
#[cfg(feature = "dsl")]
fn to_dsl(&self) -> Result<crate::dsl::EffectExpression, crate::dsl::DslError> {
use crate::dsl::EffectExpression;
let nested = self.effect.to_dsl()?;
EffectExpression::parse(&format!("fx::run_once({nested})"))
}
}
#[cfg(test)]
mod tests {
use crate::fx;
#[test]
fn test_run_once_execution() {
let mut effect = fx::run_once(fx::consume_tick());
let mut buf =
ratatui_core::buffer::Buffer::empty(ratatui_core::layout::Rect::new(0, 0, 10, 10));
let area = ratatui_core::layout::Rect::new(0, 0, 10, 10);
assert!(!effect.done());
effect.process(crate::Duration::from_millis(16), &mut buf, area);
assert!(effect.done());
effect.process(crate::Duration::from_millis(16), &mut buf, area);
assert!(effect.done());
}
#[test]
fn test_run_once_reset() {
let mut effect = fx::run_once(fx::consume_tick());
let mut buf =
ratatui_core::buffer::Buffer::empty(ratatui_core::layout::Rect::new(0, 0, 10, 10));
let area = ratatui_core::layout::Rect::new(0, 0, 10, 10);
effect.process(crate::Duration::from_millis(16), &mut buf, area);
assert!(effect.done());
effect.reset();
assert!(!effect.done());
effect.process(crate::Duration::from_millis(16), &mut buf, area);
assert!(effect.done());
}
#[cfg(feature = "dsl")]
#[test]
fn test_run_once_dsl() {
let dsl = fx::run_once(fx::consume_tick())
.to_dsl()
.unwrap()
.to_string();
assert_eq!(dsl, "fx::run_once(fx::consume_tick())");
}
#[cfg(feature = "dsl")]
#[test]
fn test_run_once_dsl_roundtrip() {
use crate::dsl::EffectDsl;
let dsl = EffectDsl::new();
let result = dsl
.compiler()
.compile("fx::run_once(fx::consume_tick())");
assert!(result.is_ok());
let effect = result.unwrap();
assert_eq!(effect.name(), "run_once");
}
}