use tobari::magnetic::TiltedDipole;
use tokio::sync::mpsc;
use super::async_bindings::orts::plugin::host_env;
use super::async_bindings::orts::plugin::tick_io;
use super::async_bindings::orts::plugin::types as wit;
#[derive(Debug)]
pub(super) enum GuestResponse {
Command(Option<wit::Command>),
Done(Result<(), String>),
}
pub(super) struct AsyncHostState {
pub(super) label: String,
pub(super) field: TiltedDipole,
pub(super) wasi: wasmtime_wasi::WasiCtx,
pub(super) table: wasmtime_wasi::ResourceTable,
pub(super) input_rx: mpsc::Receiver<Option<wit::TickInput>>,
pub(super) output_tx: mpsc::Sender<GuestResponse>,
pub(super) pending_cmd: Option<wit::Command>,
pub(super) is_first_wait: bool,
}
impl wasmtime_wasi::WasiView for AsyncHostState {
fn ctx(&mut self) -> wasmtime_wasi::WasiCtxView<'_> {
wasmtime_wasi::WasiCtxView {
ctx: &mut self.wasi,
table: &mut self.table,
}
}
}
impl wasmtime::component::HasData for AsyncHostState {
type Data<'a> = &'a mut AsyncHostState;
}
impl wit::Host for AsyncHostState {}
impl host_env::Host for AsyncHostState {
async fn log(&mut self, level: host_env::LogLevel, message: String) {
match level {
host_env::LogLevel::Trace => log::trace!("[wasm:{}] {}", self.label, message),
host_env::LogLevel::Debug => log::debug!("[wasm:{}] {}", self.label, message),
host_env::LogLevel::Info => log::info!("[wasm:{}] {}", self.label, message),
host_env::LogLevel::Warn => log::warn!("[wasm:{}] {}", self.label, message),
host_env::LogLevel::Error => log::error!("[wasm:{}] {}", self.label, message),
}
}
async fn magnetic_field_eci(
&mut self,
position_eci_km: wit::Vec3,
epoch: wit::Epoch,
) -> wit::Vec3 {
let pos = arika::frame::Vec3::<arika::frame::SimpleEci>::new(
position_eci_km.x,
position_eci_km.y,
position_eci_km.z,
);
let ep = arika::epoch::Epoch::from_jd(epoch.julian_date);
let b = crate::magnetic::field_eci(&self.field, &pos, &ep);
wit::Vec3 {
x: b.x(),
y: b.y(),
z: b.z(),
}
}
}
impl tick_io::Host for AsyncHostState {
async fn wait_tick(&mut self) -> Option<wit::TickInput> {
if !self.is_first_wait {
let cmd = self.pending_cmd.take();
let _ = self.output_tx.send(GuestResponse::Command(cmd)).await;
} else {
self.is_first_wait = false;
}
self.input_rx.recv().await.flatten()
}
async fn send_command(&mut self, cmd: wit::Command) {
self.pending_cmd = Some(cmd);
}
}