#[cfg(any(feature = "iracing", feature = "ac-evo", feature = "lmu"))]
use crate::error::SimError;
pub fn decode_cp1252(bytes: &[u8]) -> String {
if bytes.iter().all(|&b| b < 0x80) {
return unsafe { String::from_utf8_unchecked(bytes.to_vec()) };
}
let (decoded, _, _) = encoding_rs::WINDOWS_1252.decode(bytes);
decoded.into_owned()
}
#[cfg(any(feature = "iracing", feature = "ac-evo", feature = "lmu"))]
pub trait HasSnapshot {
fn telemetry_snapshot(&self)
-> std::collections::HashMap<String, crate::types::TelemetryValue>;
fn var_list_snapshot(&self) -> Vec<crate::types::VarMeta>;
}
macro_rules! impl_has_snapshot {
($feature:literal, $ty:path, $var_list_fn:expr) => {
#[cfg(feature = $feature)]
impl HasSnapshot for $ty {
fn telemetry_snapshot(
&self,
) -> std::collections::HashMap<String, crate::types::TelemetryValue> {
self.telemetry_snapshot()
}
fn var_list_snapshot(&self) -> Vec<crate::types::VarMeta> {
$var_list_fn(self)
}
}
};
}
impl_has_snapshot!(
"iracing",
crate::iracing::connection::IRsdkConnection,
|s: &crate::iracing::connection::IRsdkConnection| s.var_list_snapshot()
);
impl_has_snapshot!(
"ac-evo",
crate::ac_evo::connection::AcEvoConnection,
|_s: &crate::ac_evo::connection::AcEvoConnection| crate::ac_evo::snapshot::var_list_snapshot()
);
impl_has_snapshot!(
"lmu",
crate::lmu::connection::LmuConnection,
|_s: &crate::lmu::connection::LmuConnection| crate::lmu::snapshot::var_list_snapshot()
);
#[cfg(any(feature = "iracing", feature = "ac-evo", feature = "lmu"))]
impl<T: HasSnapshot> HasSnapshot for Box<T> {
fn telemetry_snapshot(
&self,
) -> std::collections::HashMap<String, crate::types::TelemetryValue> {
(**self).telemetry_snapshot()
}
fn var_list_snapshot(&self) -> Vec<crate::types::VarMeta> {
(**self).var_list_snapshot()
}
}
#[cfg(any(feature = "iracing", feature = "ac-evo", feature = "lmu"))]
impl HasSnapshot for crate::connection::Connection {
fn telemetry_snapshot(
&self,
) -> std::collections::HashMap<String, crate::types::TelemetryValue> {
use crate::connection::Connection;
match self {
#[cfg(feature = "iracing")]
Connection::IRacing(c) => c.telemetry_snapshot(),
#[cfg(feature = "ac-evo")]
Connection::AcEvo(c) => c.telemetry_snapshot(),
#[cfg(feature = "lmu")]
Connection::Lmu(c) => c.telemetry_snapshot(),
}
}
fn var_list_snapshot(&self) -> Vec<crate::types::VarMeta> {
use crate::connection::Connection;
match self {
#[cfg(feature = "iracing")]
Connection::IRacing(c) => c.var_list_snapshot(),
#[cfg(feature = "ac-evo")]
Connection::AcEvo(c) => c.var_list_snapshot(),
#[cfg(feature = "lmu")]
Connection::Lmu(c) => c.var_list_snapshot(),
}
}
}
#[cfg(any(feature = "iracing", feature = "ac-evo", feature = "lmu"))]
pub fn save_telemetry_snapshot(conn: &impl HasSnapshot, path: &str) -> Result<(), SimError> {
let snap = conn.telemetry_snapshot();
let mut entries: Vec<_> = snap.iter().collect();
entries.sort_by_key(|(k, _)| k.as_str());
use std::fmt::Write as _;
let mut out = String::with_capacity(entries.len() * 48);
for (k, v) in entries {
writeln!(out, "{:<32} {}", k, v).ok();
}
std::fs::write(path, out)?;
Ok(())
}
#[cfg(any(feature = "iracing", feature = "ac-evo", feature = "lmu"))]
pub fn save_var_list_snapshot(conn: &impl HasSnapshot, path: &str) -> Result<(), SimError> {
let mut vars = conn.var_list_snapshot();
vars.sort_by(|a, b| a.name.cmp(&b.name));
use std::fmt::Write as _;
let mut out = String::with_capacity(vars.len() * 80);
for v in vars {
let count_str = if v.count > 1 {
format!("[{}]", v.count)
} else {
String::new()
};
writeln!(
out,
"{:<32} {}{:<12} {:<16} {}",
v.name, v.type_name, count_str, v.unit, v.desc
)
.ok();
}
std::fs::write(path, out)?;
Ok(())
}
#[cfg(feature = "iracing")]
pub fn save_session(
conn: &crate::iracing::connection::IRsdkConnection,
path: &str,
) -> Result<(), SimError> {
let yaml = conn.session_yaml().unwrap_or_default();
std::fs::write(path, yaml)?;
Ok(())
}