tauri runtime Mutex/RwLock, type_hint

This commit is contained in:
Martin Kavík 2024-07-08 02:08:20 +02:00
parent b32b6e4f87
commit 55f1b42ab0
4 changed files with 52 additions and 20 deletions

View file

@ -111,7 +111,9 @@ pub(super) async fn load_signal_and_get_timeline(
timeline_viewport_x, timeline_viewport_x,
block_height, block_height,
var_format, var_format,
); |value| Box::pin(async { value }),
)
.await;
timeline timeline
} }

View file

@ -1,13 +1,25 @@
use crate::*; use crate::*;
use future::BoxFuture;
use wellen::SignalValue;
pub fn signal_to_timeline( // @TODO remove once https://github.com/rust-lang/rust/issues/89976 is resolved
signal: &wellen::Signal, // (`error: implementation of `FnOnce` is not general enough`)
fn type_hint<F>(f: F) -> F
where
F: for<'a> FnMut((u32, SignalValue<'a>)) -> (f64, SignalValue<'a>),
{
f
}
pub async fn signal_to_timeline<'s>(
signal: &'s wellen::Signal,
time_table: &[wellen::Time], time_table: &[wellen::Time],
timeline_zoom: f64, timeline_zoom: f64,
timeline_viewport_width: u32, timeline_viewport_width: u32,
timeline_viewport_x: i32, timeline_viewport_x: i32,
block_height: u32, block_height: u32,
var_format: VarFormat, var_format: VarFormat,
mut format_by_decoders: impl FnMut(String) -> BoxFuture<'s, String>,
) -> Timeline { ) -> Timeline {
const MIN_BLOCK_WIDTH: u32 = 3; const MIN_BLOCK_WIDTH: u32 = 3;
// Courier New, 16px, sync with `label_style` in `pixi_canvas.rs` // Courier New, 16px, sync with `label_style` in `pixi_canvas.rs`
@ -25,12 +37,12 @@ pub fn signal_to_timeline(
let mut x_value_pairs = signal let mut x_value_pairs = signal
.iter_changes() .iter_changes()
.map(|(index, value)| { .map(type_hint(move |(index, value)| {
let index = index as usize; let index = index as usize;
let time = time_table[index] as f64; let time = time_table[index] as f64;
let x = time / last_time * timeline_width - timeline_viewport_x; let x = time / last_time * timeline_width - timeline_viewport_x;
(x, value) (x, value)
}) }))
.peekable(); .peekable();
// @TODO parallelize? // @TODO parallelize?
@ -55,7 +67,8 @@ pub fn signal_to_timeline(
} }
// @TODO cache? // @TODO cache?
let value = var_format.format(value); let mut value = var_format.format(value);
value = format_by_decoders(value).await;
let value_width = (value.chars().count() as f64 * LETTER_WIDTH) as u32; let value_width = (value.chars().count() as f64 * LETTER_WIDTH) as u32;
// @TODO Ellipsis instead of hiding? // @TODO Ellipsis instead of hiding?

View file

@ -1,14 +1,14 @@
use crate::{AddedDecodersCount, DecoderPath, RemovedDecodersCount}; use crate::{AddedDecodersCount, DecoderPath, RemovedDecodersCount};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::sync::Arc; use std::sync::Arc;
use tauri::async_runtime::Mutex; use tauri::async_runtime::{Mutex, RwLock};
use wasmtime::component::{Component as WasmtimeComponent, *}; use wasmtime::component::{Component as WasmtimeComponent, *};
use wasmtime::{AsContextMut, Engine, Store}; use wasmtime::{AsContextMut, Engine, Store};
use wasmtime_wasi::{WasiCtx, WasiView}; use wasmtime_wasi::{WasiCtx, WasiView};
bindgen!(); bindgen!();
static DECODERS: Lazy<Arc<Mutex<Vec<Component>>>> = Lazy::new(<_>::default); pub static DECODERS: Lazy<Arc<RwLock<Vec<Component>>>> = Lazy::new(<_>::default);
static ENGINE: Lazy<Engine> = Lazy::new(<_>::default); static ENGINE: Lazy<Engine> = Lazy::new(<_>::default);
static LINKER: Lazy<Linker<State>> = Lazy::new(|| { static LINKER: Lazy<Linker<State>> = Lazy::new(|| {
let mut linker = Linker::new(&ENGINE); let mut linker = Linker::new(&ENGINE);
@ -16,7 +16,7 @@ static LINKER: Lazy<Linker<State>> = Lazy::new(|| {
Component::add_to_linker(&mut linker, |state: &mut State| state).unwrap(); Component::add_to_linker(&mut linker, |state: &mut State| state).unwrap();
linker linker
}); });
static STORE: Lazy<Arc<Mutex<Store<State>>>> = Lazy::new(|| { pub static STORE: Lazy<Arc<Mutex<Store<State>>>> = Lazy::new(|| {
let store = Store::new( let store = Store::new(
&ENGINE, &ENGINE,
State { State {
@ -27,7 +27,7 @@ static STORE: Lazy<Arc<Mutex<Store<State>>>> = Lazy::new(|| {
Arc::new(Mutex::new(store)) Arc::new(Mutex::new(store))
}); });
struct State { pub struct State {
ctx: WasiCtx, ctx: WasiCtx,
table: ResourceTable, table: ResourceTable,
} }
@ -48,7 +48,7 @@ impl component::decoder::host::Host for State {
} }
pub async fn remove_all_decoders() -> RemovedDecodersCount { pub async fn remove_all_decoders() -> RemovedDecodersCount {
let mut decoders = DECODERS.lock().await; let mut decoders = DECODERS.write().await;
let decoders_count = decoders.len(); let decoders_count = decoders.len();
decoders.clear(); decoders.clear();
decoders_count decoders_count
@ -98,7 +98,7 @@ async fn add_decoder(path: &str) -> wasmtime::Result<()> {
.component_decoder_decoder() .component_decoder_decoder()
.call_init(&mut store)?; .call_init(&mut store)?;
DECODERS.lock().await.push(component); DECODERS.write().await.push(component);
Ok(()) Ok(())
} }

View file

@ -1,6 +1,7 @@
use std::fs; use std::fs;
use std::sync::Mutex; use tauri::async_runtime::RwLock;
use tauri_plugin_dialog::DialogExt; use tauri_plugin_dialog::DialogExt;
use wasmtime::AsContextMut;
use wellen::simple::Waveform; use wellen::simple::Waveform;
type Filename = String; type Filename = String;
@ -13,7 +14,7 @@ mod component_manager;
#[derive(Default)] #[derive(Default)]
struct Store { struct Store {
waveform: Mutex<Option<Waveform>>, waveform: RwLock<Option<Waveform>>,
} }
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
@ -35,7 +36,7 @@ async fn pick_and_load_waveform(
let Ok(waveform) = waveform else { let Ok(waveform) = waveform else {
panic!("Waveform file reading failed") panic!("Waveform file reading failed")
}; };
*store.waveform.lock().unwrap() = Some(waveform); *store.waveform.write().await = Some(waveform);
Ok(Some(file_response.name.unwrap())) Ok(Some(file_response.name.unwrap()))
} }
@ -53,8 +54,9 @@ async fn load_file_with_selected_vars(app: tauri::AppHandle) -> Result<Option<Ja
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
async fn get_hierarchy(store: tauri::State<'_, Store>) -> Result<serde_json::Value, ()> { async fn get_hierarchy(store: tauri::State<'_, Store>) -> Result<serde_json::Value, ()> {
let waveform = store.waveform.lock().unwrap(); let waveform_lock = store.waveform.read().await;
let hierarchy = waveform.as_ref().unwrap().hierarchy(); let waveform = waveform_lock.as_ref().unwrap();
let hierarchy = waveform.hierarchy();
Ok(serde_json::to_value(hierarchy).unwrap()) Ok(serde_json::to_value(hierarchy).unwrap())
} }
@ -70,7 +72,7 @@ async fn load_signal_and_get_timeline(
) -> Result<serde_json::Value, ()> { ) -> Result<serde_json::Value, ()> {
// @TODO run (all?) in a blocking thread? // @TODO run (all?) in a blocking thread?
let signal_ref = wellen::SignalRef::from_index(signal_ref_index).unwrap(); let signal_ref = wellen::SignalRef::from_index(signal_ref_index).unwrap();
let mut waveform_lock = store.waveform.lock().unwrap(); let mut waveform_lock = store.waveform.write().await;
let waveform = waveform_lock.as_mut().unwrap(); let waveform = waveform_lock.as_mut().unwrap();
waveform.load_signals_multi_threaded(&[signal_ref]); waveform.load_signals_multi_threaded(&[signal_ref]);
let signal = waveform.get_signal(signal_ref).unwrap(); let signal = waveform.get_signal(signal_ref).unwrap();
@ -83,14 +85,29 @@ async fn load_signal_and_get_timeline(
timeline_viewport_x, timeline_viewport_x,
block_height, block_height,
var_format, var_format,
); |mut value: String| {
Box::pin(async {
let decoders = component_manager::DECODERS.read().await;
let mut store_lock = component_manager::STORE.lock().await;
let mut store = store_lock.as_context_mut();
for decoder in decoders.iter() {
value = decoder
.component_decoder_decoder()
.call_format_signal_value(&mut store, &value)
.unwrap()
}
value
})
},
)
.await;
Ok(serde_json::to_value(timeline).unwrap()) Ok(serde_json::to_value(timeline).unwrap())
} }
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
async fn unload_signal(signal_ref_index: usize, store: tauri::State<'_, Store>) -> Result<(), ()> { async fn unload_signal(signal_ref_index: usize, store: tauri::State<'_, Store>) -> Result<(), ()> {
let signal_ref = wellen::SignalRef::from_index(signal_ref_index).unwrap(); let signal_ref = wellen::SignalRef::from_index(signal_ref_index).unwrap();
let mut waveform_lock = store.waveform.lock().unwrap(); let mut waveform_lock = store.waveform.write().await;
let waveform = waveform_lock.as_mut().unwrap(); let waveform = waveform_lock.as_mut().unwrap();
waveform.unload_signals(&[signal_ref]); waveform.unload_signals(&[signal_ref]);
Ok(()) Ok(())