diff --git a/crates/tek_core/src/render_collect.rs b/crates/tek_core/src/collect.rs similarity index 54% rename from crates/tek_core/src/render_collect.rs rename to crates/tek_core/src/collect.rs index af37753f..e89e5b6f 100644 --- a/crates/tek_core/src/render_collect.rs +++ b/crates/tek_core/src/collect.rs @@ -1,11 +1,11 @@ use crate::*; pub enum Collected<'a, T, U> { - Box(Box + 'a>), - Ref(&'a (dyn Render<'a, T, U> + 'a)), + Box(Box + 'a>), + Ref(&'a (dyn Render + 'a)), } -impl<'a, T, U> Render<'a, T, U> for Collected<'a, T, U> { - fn render (&self, to: &'a mut T) -> Perhaps { +impl<'a, T, U> Render for Collected<'a, T, U> { + fn render (&self, to: &mut T) -> Perhaps { match self { Self::Box(item) => (*item).render(to), Self::Ref(item) => (*item).render(to), @@ -21,20 +21,20 @@ impl<'a, T, U> Collection<'a, T, U> { } } pub trait Collect<'a, T, U> { - fn add_box (self, item: Box + 'a>) -> Self; - fn add_ref (self, item: &'a dyn Render<'a, T, U>) -> Self; - fn add + Sized + 'a> (self, item: R) -> Self + fn add_box (self, item: Box + 'a>) -> Self; + fn add_ref (self, item: &'a dyn Render) -> Self; + fn add + Sized + 'a> (self, item: R) -> Self where Self: Sized { self.add_box(Box::new(item)) } } impl<'a, T, U> Collect<'a, T, U> for Collection<'a, T, U> { - fn add_box (mut self, item: Box + 'a>) -> Self { + fn add_box (mut self, item: Box + 'a>) -> Self { self.0.push(Collected::Box(item)); self } - fn add_ref (mut self, item: &'a dyn Render<'a, T, U>) -> Self { + fn add_ref (mut self, item: &'a dyn Render) -> Self { self.0.push(Collected::Ref(item)); self } diff --git a/crates/tek_core/src/handle.rs b/crates/tek_core/src/handle.rs index 72ea71f6..bcbf14ca 100644 --- a/crates/tek_core/src/handle.rs +++ b/crates/tek_core/src/handle.rs @@ -2,17 +2,17 @@ use crate::*; /// Handle input pub trait Handle: Send + Sync { - fn handle (&mut self, context: &mut T) -> Perhaps; + fn handle (&mut self, context: &T) -> Perhaps; } impl Handle for &mut H where H: Handle { - fn handle (&mut self, context: &mut T) -> Perhaps { + fn handle (&mut self, context: &T) -> Perhaps { (*self).handle(context) } } impl Handle for Option where H: Handle { - fn handle (&mut self, context: &mut T) -> Perhaps { + fn handle (&mut self, context: &T) -> Perhaps { if let Some(ref mut handle) = self { handle.handle(context) } else { @@ -22,25 +22,25 @@ impl Handle for Option where H: Handle { } impl Handle for Mutex where H: Handle { - fn handle (&mut self, context: &mut T) -> Perhaps { + fn handle (&mut self, context: &T) -> Perhaps { self.lock().unwrap().handle(context) } } impl Handle for Arc> where H: Handle { - fn handle (&mut self, context: &mut T) -> Perhaps { + fn handle (&mut self, context: &T) -> Perhaps { self.lock().unwrap().handle(context) } } impl Handle for RwLock where H: Handle { - fn handle (&mut self, context: &mut T) -> Perhaps { + fn handle (&mut self, context: &T) -> Perhaps { self.write().unwrap().handle(context) } } impl Handle for Arc> where H: Handle { - fn handle (&mut self, context: &mut T) -> Perhaps { + fn handle (&mut self, context: &T) -> Perhaps { self.write().unwrap().handle(context) } } diff --git a/crates/tek_core/src/jack_core.rs b/crates/tek_core/src/jack_core.rs index b085fbbd..1f7823ff 100644 --- a/crates/tek_core/src/jack_core.rs +++ b/crates/tek_core/src/jack_core.rs @@ -1,18 +1,18 @@ use crate::{*, jack::*}; /// A UI component that may be associated with a JACK client by the `Jack` factory. -pub trait Device<'a, T, U>: Render<'a, T, U> + Handle + Process + Send + Sync { +pub trait Device: Component + Process { /// Perform type erasure for collecting heterogeneous devices. - fn boxed (self) -> Box> where Self: Sized + 'static { + fn boxed (self) -> Box> where Self: Sized + 'static { Box::new(self) } } /// All things that implement the required traits can be treated as `Device`. -impl<'a, D, T, U> Device<'a, T, U> for D where D: Render<'a, T, U> + Handle + Process {} +impl Device for D where D: Component + Process {} -impl<'a, T, U> Render<'a, T, U> for Box> { - fn render (&self, to: &'a mut T) -> Result, Box> { +impl Render for Box> { + fn render (&self, to: &mut E) -> Perhaps { (**self).render(to) } } @@ -98,8 +98,8 @@ pub trait Process { } /// Just run thing with JACK. Returns the activated client. -pub fn jack_run (name: &str, app: &Arc>) -> Usually - where T: Handle + Process + Send + Sync + 'static +pub fn jack_run (name: &str, app: &Arc>) -> Usually + where T: Handle + Process + Send + Sync + 'static { let options = ClientOptions::NO_START_SERVER; let (client, _status) = Client::new(name, options)?; @@ -143,12 +143,11 @@ impl Jack { )?.0, }) } - pub fn run <'a: 'static, D, T, U> ( + pub fn run <'a: 'static, D, E> ( self, state: impl FnOnce(JackPorts)->Box - ) -> Usually> - where D: Device<'a, T, U> + Process + Sized + 'static, - T: 'static, - U: 'static + ) -> Usually> + where D: Device + Sized + 'static, + E: Engine + 'static, { let owned_ports = JackPorts { audio_ins: register_ports(&self.client, self.audio_ins, AudioIn)?, @@ -164,7 +163,7 @@ impl Jack { .map(|p|Ok(p.name()?)).collect::>>()?; let audio_ins = owned_ports.audio_ins.values() .map(|p|Ok(p.name()?)).collect::>>()?; - let state = Arc::new(RwLock::new(state(owned_ports) as Box>)); + let state = Arc::new(RwLock::new(state(owned_ports) as Box>)); let client = self.client.activate_async( Notifications(Box::new({ let _state = state.clone(); diff --git a/crates/tek_core/src/jack_device.rs b/crates/tek_core/src/jack_device.rs index 4eb5873c..d4984f30 100644 --- a/crates/tek_core/src/jack_device.rs +++ b/crates/tek_core/src/jack_device.rs @@ -1,31 +1,31 @@ use crate::{*, jack::*}; /// A [Device] bound to a JACK client and a set of ports. -pub struct JackDevice<'a, T, U> { +pub struct JackDevice { /// The active JACK client of this device. pub client: DynamicAsyncClient, /// The device state, encapsulated for sharing between threads. - pub state: Arc>>>, + pub state: Arc>>>, /// Unowned copies of the device's JACK ports, for connecting to the device. /// The "real" readable/writable `Port`s are owned by the `state`. pub ports: UnownedJackPorts, } -impl<'a, T, U> std::fmt::Debug for JackDevice<'a, T, U> { +impl std::fmt::Debug for JackDevice { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("JackDevice").field("ports", &self.ports).finish() } } -impl<'a, T, U> Render<'a, T, U> for JackDevice<'a, T, U> { - fn render (&self, to: &'a mut T) -> Perhaps { +impl Render for JackDevice { + fn render (&self, to: &mut E) -> Perhaps { self.state.read().unwrap().render(to) } } -impl<'a, T, U> Handle for JackDevice<'a, T, U> { - fn handle (&mut self, event: &AppEvent) -> Usually { - self.state.write().unwrap().handle(event) +impl Handle for JackDevice { + fn handle (&mut self, from: &E) -> Perhaps { + self.state.write().unwrap().handle(from) } } -impl<'a, T, U> Ports for JackDevice<'a, T, U> { +impl Ports for JackDevice { fn audio_ins (&self) -> Usually>> { Ok(self.ports.audio_ins.values().collect()) } @@ -39,13 +39,13 @@ impl<'a, T, U> Ports for JackDevice<'a, T, U> { Ok(self.ports.midi_outs.values().collect()) } } -impl<'a, T, U> JackDevice<'a, T, U> { +impl JackDevice { /// Returns a locked mutex of the state's contents. - pub fn state (&self) -> LockResult>>> { + pub fn state (&self) -> LockResult>>> { self.state.read() } /// Returns a locked mutex of the state's contents. - pub fn state_mut (&self) -> LockResult>>> { + pub fn state_mut (&self) -> LockResult>>> { self.state.write() } pub fn connect_midi_in (&self, index: usize, port: &Port) -> Usually<()> { diff --git a/crates/tek_core/src/lib.rs b/crates/tek_core/src/lib.rs index 3bd674c4..83f73d12 100644 --- a/crates/tek_core/src/lib.rs +++ b/crates/tek_core/src/lib.rs @@ -27,6 +27,7 @@ use better_panic::{Settings, Verbosity}; } submod! { + collect component edn engine @@ -42,7 +43,6 @@ submod! { render render_axis render_buffer - render_collect render_layered render_split time diff --git a/crates/tek_core/src/render.rs b/crates/tek_core/src/render.rs index 1cef9691..0a61678a 100644 --- a/crates/tek_core/src/render.rs +++ b/crates/tek_core/src/render.rs @@ -2,7 +2,7 @@ use crate::*; /// Render to output. pub trait Render: Send + Sync { - fn render (&self, context: &mut T) -> Perhaps; + fn render (&self, to: &mut T) -> Perhaps; } /// Options can be rendered optionally. diff --git a/crates/tek_core/src/render_layered.rs b/crates/tek_core/src/render_layered.rs index ad4abc17..c3ef8236 100644 --- a/crates/tek_core/src/render_layered.rs +++ b/crates/tek_core/src/render_layered.rs @@ -20,7 +20,7 @@ impl<'a, T, U> Collect<'a, T, U> for Layered<'a, T, U> { } impl<'a> Render for Layered<'a, TuiContext, Rect> { - fn render (&self, to: &mut impl TuiTarget) -> Perhaps { + fn render (&self, to: &mut TuiContext) -> Perhaps { let area = to.area(); for layer in self.0.0.iter() { layer.render(to)?; diff --git a/crates/tek_core/src/render_split.rs b/crates/tek_core/src/render_split.rs index dc107c8c..f857929a 100644 --- a/crates/tek_core/src/render_split.rs +++ b/crates/tek_core/src/render_split.rs @@ -44,24 +44,24 @@ impl<'a, T, U> Split<'a, T, U> { } impl<'a, T, U> Collect<'a, T, U> for Split<'a, T, U> { - fn add_box (mut self, item: Box + 'a>) -> Self { + fn add_box (mut self, item: Box + 'a>) -> Self { self.items = self.items.add_box(item); self } - fn add_ref (mut self, item: &'a dyn Render<'a, T, U>) -> Self { + fn add_ref (mut self, item: &'a dyn Render) -> Self { self.items = self.items.add_ref(item); self } } -impl<'a> Render<'a, TuiOutput<'a>, Rect> for Split<'a, TuiOutput<'a>, Rect> { - fn render (&self, to: &mut TuiOutput<'a>) -> Perhaps { +impl<'a> Render for Split<'a, TuiContext, Rect> { + fn render (&self, to: &mut TuiContext) -> Perhaps { Ok(None)//Rect::default())//Some(self.render_areas(to)?.0)) } } -impl<'a, 'b: 'a> Split<'a, TuiOutput<'a>, Rect> { - pub fn render_areas (&'a self, to: &mut TuiOutput<'a>) -> Usually<(Rect, Vec)> { +impl<'a> Split<'a, TuiContext, Rect> { + pub fn render_areas (&self, to: &mut TuiContext) -> Usually<(Rect, Vec)> { Ok((Rect::default(), vec![])) //let Rect { mut x, mut y, mut width, mut height } = to.area; //let TuiOutput { buffer, area } = to; diff --git a/crates/tek_core/src/tui.rs b/crates/tek_core/src/tui.rs index 32607bf3..4681164e 100644 --- a/crates/tek_core/src/tui.rs +++ b/crates/tek_core/src/tui.rs @@ -34,24 +34,22 @@ impl Engine for TuiContext { fn teardown (&mut self) -> Usually<()> { terminal_teardown() } - fn handle (&mut self, state: &mut impl Handle) -> Usually<()> { + fn handle (&self, state: &mut impl Handle) -> Usually<()> { if ::crossterm::event::poll(self.poll).is_ok() { let event = ::crossterm::event::read().unwrap(); if let Event::Key(KeyEvent { code: KeyCode::Char('c'), modifiers: KeyModifiers::CONTROL, .. }) = event { self.exited.store(true, Ordering::Relaxed); - } else if let Err(e) = state.handle(&mut self) { + } else if let Err(e) = state.handle(self) { panic!("{e}") } } Ok(()) } fn render (&mut self, state: &impl Render) -> Usually<()> { - if let Ok(state) = state.try_read() { - state.render(&mut self).expect("render failed"); - } - std::thread::sleep(self.sleep) + state.render(self).expect("render failed"); + Ok(()) } } impl TuiContext { @@ -61,7 +59,7 @@ impl TuiContext { ) -> Usually>> { let backend = CrosstermBackend::new(stdout()); let area = backend.size()?; - let engine = Arc::new(Self { + let engine = Arc::new(RwLock::new(Self { sleep: Duration::from_millis(20), poll: Duration::from_millis(100), exited: Arc::new(AtomicBool::new(false)), @@ -69,25 +67,30 @@ impl TuiContext { buffers: [Buffer::empty(area), Buffer::empty(area)], backend, area, - }); + })); let _input_thread = { let engine = engine.clone(); let state = state.clone(); spawn(move || loop { + let engine = engine.read().unwrap(); if engine.exited() { break } - engine.handle(&mut state).expect("handle failed"); + engine.handle(&mut *state.write().unwrap()).expect("handle failed"); }) }; let main_thread = { let engine = engine.clone(); let state = state.clone(); spawn(move || loop { + let mut engine = engine.write().unwrap(); if engine.exited() { break } - engine.render(&mut state).expect("render failed"); + if let Ok(state) = state.try_read() { + engine.render(&*state).expect("render failed"); + } + std::thread::sleep(engine.sleep); }) }; main_thread.join().expect("main thread failed"); @@ -248,15 +251,17 @@ pub trait BorderStyle { const W: &'static str = ""; #[inline] - fn draw <'a> (&self, to: &mut TuiOutput<'a>) -> Perhaps { - self.draw_horizontal(to.buffer, to.area, None)?; - self.draw_vertical(to.buffer, to.area, None)?; - self.draw_corners(to.buffer, to.area, None)?; + fn draw <'a> (&self, to: &mut TuiContext) -> Perhaps { + self.draw_horizontal(to, None)?; + self.draw_vertical(to, None)?; + self.draw_corners(to, None)?; Ok(Some(to.area)) } #[inline] - fn draw_horizontal (&self, buf: &mut Buffer, area: Rect, style: Option