added C for threading

This commit is contained in:
2024-11-16 16:38:06 +01:00
parent e1da609eb1
commit 74767cf961
13 changed files with 219 additions and 228 deletions
+39 -68
View File
@@ -1,79 +1,50 @@
use std::sync::{mpsc, Arc};
use std::thread;
use crossterm::terminal::enable_raw_mode;
use crate::{
clear, create_frame, flush, get_term_size, hide_cursor, render_to_frame, Element, State, Value,
};
use crate::{clear, create_frame, flush, get_term_size, render_to_frame, Element, State, StateChanger, Value};
use std::ffi::c_void;
/// Renders an element with a given state to the terminal.
///
/// This macro handles the process of creating a frame, rendering the element to it,
/// clearing the terminal, and then printing the rendered frame.
///
/// # Parameters
///
/// * `$element` - The element to be rendered.
/// * `$state` - The current state of the element.
///
/// # Returns
///
/// This macro does not return a value. It performs side effects by printing to the terminal.
macro_rules! render {
($element:expr, $state:expr) => {
let (width, height) = get_term_size();
let mut frame: Vec<String> = create_frame(Value::new(width), Value::new(height));
render_to_frame($state, width, &mut frame, $element);
clear();
print!("{}", frame.join(""));
flush();
};
pub struct ElementWrapper<'a> {
element: &'a mut Box<dyn Element>,
}
pub fn run(element: Arc<dyn Element>) -> bool {
hide_cursor();
crossterm::terminal::enable_raw_mode().unwrap();
clear();
impl<'a> ElementWrapper<'a> {
pub fn new(element: &'a mut Box<dyn Element>) -> *mut c_void {
Box::into_raw(Box::new(ElementWrapper { element })) as *mut c_void
}
let (tx, rx) = mpsc::channel();
pub unsafe fn from_raw(ptr: *mut c_void) -> &'a mut Box<dyn Element> {
assert!(!ptr.is_null(), "Pointer to ElementWrapper is null");
let wrapper = ptr as *mut ElementWrapper;
(*wrapper).element
}
}
let (exit_tx, exit_) = mpsc::channel::<()>();
extern "C" {
fn c_run(element: *mut c_void) -> bool;
}
thread::spawn({
let element_thread = Arc::clone(&element);
move || loop {
if exit_.try_recv().is_ok() {
break;
}
let event = crossterm::event::read().unwrap();
let e = Arc::clone(&element_thread);
let command_handler = crate::CommandHandler(tx.clone());
#[no_mangle]
pub extern "C" fn render(ptr: *mut c_void, state: u32) {
let element = unsafe { ElementWrapper::from_raw(ptr) };
let (width, height) = get_term_size();
let mut frame: Vec<String> = create_frame(Value::new(width), Value::new(height));
render_to_frame(State::from_u32(state), width, &mut frame, element);
clear();
print!("{}", frame.join(""));
flush();
}
thread::spawn(move || {
e.event(&command_handler, event);
});
}
});
#[no_mangle]
pub extern "C" fn event(ptr: *mut c_void, state: *mut u32) {
let event = crossterm::event::read().unwrap();
let element = unsafe { ElementWrapper::from_raw(ptr) };
element.event(event, &StateChanger(state));
}
let mut current_state = State::Hover;
loop {
if let Ok(command) = rx.try_recv() {
match command {
crate::Command::SetState(state) => {
current_state = state;
}
crate::Command::Exit => {
exit_tx.send(()).unwrap();
break;
}
crate::Command::Rebuild => {
exit_tx.send(()).unwrap();
return true;
}
}
} else {
render!(&element, current_state.clone());
}
thread::sleep(std::time::Duration::from_millis(20));
pub fn run(data: &mut Box<dyn Element>) -> bool {
enable_raw_mode().unwrap();
unsafe {
let element_ptr = ElementWrapper::new(data);
return c_run(element_ptr);
}
false
}