use core::time::Duration;
use alloc::boxed::Box;
use crate::{color::ColorType, time::Instant, Led, Sled, SledError, Vec2};
#[cfg(feature = "std")]
pub type Driver<COLOR> = CustomDriver<std::time::Instant, COLOR>;
mod data;
pub use data::Data;
#[derive(Clone, Debug)]
pub struct Time {
pub elapsed: Duration,
pub delta: Duration,
}
type SledResult = Result<(), SledError>;
pub struct CustomDriver<INSTANT, COLOR>
where
INSTANT: Instant,
COLOR: ColorType,
{
sled: Option<Sled<COLOR>>,
startup_commands: Box<dyn Fn(&mut Sled<COLOR>, &mut Data) -> SledResult>,
compute_commands: Box<dyn Fn(&Sled<COLOR>, &mut Data, &Time) -> SledResult>,
draw_commands: Box<dyn Fn(&mut Sled<COLOR>, &Data, &Time) -> SledResult>,
startup: INSTANT,
last_update: INSTANT,
data: Data,
}
impl<INSTANT, COLOR> CustomDriver<INSTANT, COLOR>
where
INSTANT: Instant,
COLOR: ColorType,
{
pub fn new() -> Self {
CustomDriver {
sled: None,
startup_commands: Box::new(|_, _| Ok(())),
compute_commands: Box::new(|_, _, _| Ok(())),
draw_commands: Box::new(|_, _, _| Ok(())),
startup: INSTANT::now(),
last_update: INSTANT::now(),
data: Data::new(),
}
}
pub fn sled(&self) -> Option<&Sled<COLOR>> {
self.sled.as_ref()
}
pub fn elapsed(&self) -> Duration {
self.startup.elapsed()
}
pub fn set_startup_commands<F: Fn(&mut Sled<COLOR>, &mut Data) -> SledResult + 'static>(
&mut self,
startup_commands: F,
) {
self.startup_commands = Box::new(startup_commands);
}
pub fn set_compute_commands<F: Fn(&Sled<COLOR>, &mut Data, &Time) -> SledResult + 'static>(
&mut self,
compute_commands: F,
) {
self.compute_commands = Box::new(compute_commands);
}
pub fn set_draw_commands<F: Fn(&mut Sled<COLOR>, &Data, &Time) -> SledResult + 'static>(
&mut self,
draw_commands: F,
) {
self.draw_commands = Box::new(draw_commands);
}
pub fn mount(&mut self, mut sled: Sled<COLOR>) {
(self.startup_commands)(&mut sled, &mut self.data).unwrap();
self.startup = INSTANT::now();
self.last_update = self.startup;
self.sled = Some(sled);
}
pub fn step(&mut self) {
if let Some(sled) = &mut self.sled {
let time = Time {
elapsed: self.startup.elapsed(),
delta: self.last_update.elapsed(),
};
self.last_update = INSTANT::now();
(self.compute_commands)(sled, &mut self.data, &time).unwrap();
(self.draw_commands)(sled, &self.data, &time).unwrap();
}
}
pub fn step_by(&mut self, delta: Duration) {
self.startup -= delta;
self.step();
}
pub fn dismount(&mut self) -> Sled<COLOR> {
self.sled.take().unwrap()
}
pub fn leds(&self) -> impl Iterator<Item = &Led<COLOR>> {
if let Some(sled) = &self.sled {
sled.leds()
} else {
panic!("Driver has no Sled assigned!")
}
}
pub fn colors(&self) -> impl Iterator<Item = &COLOR> + '_ {
if let Some(sled) = &self.sled {
sled.colors()
} else {
panic!("Driver has no Sled assigned!")
}
}
pub fn positions(&self) -> impl Iterator<Item = Vec2> + '_ {
if let Some(sled) = &self.sled {
sled.positions()
} else {
panic!("Driver has no Sled assigned!")
}
}
pub fn colors_and_positions(&self) -> impl Iterator<Item = (COLOR, Vec2)> + '_ {
if let Some(sled) = &self.sled {
sled.colors_and_positions()
} else {
panic!("Driver has no Sled assigned!")
}
}
pub fn data(&self) -> &Data {
&self.data
}
pub fn data_mut(&mut self) -> &mut Data {
&mut self.data
}
}
impl<INSTANT, COLOR> Default for CustomDriver<INSTANT, COLOR>
where
INSTANT: Instant,
COLOR: ColorType,
{
fn default() -> Self {
Self::new()
}
}