use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::{Mutex, OnceLock};
use deq_decoder_abi::host::{DecoderLibrary, LoadedDecoder};
use serde::{Deserialize, Serialize};
#[cfg(feature = "cli")]
use structdoc::StructDoc;
use crate::decoder::blackbox_decoder::{DecodingHypergraph, ParityFactor};
use crate::decoder::thread_pooling::{DecoderInstance, ThreadPoolingConfig, ThreadPoolingDecoder};
use crate::util::BitVector;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "cli", derive(StructDoc))]
#[serde(deny_unknown_fields)]
pub struct DynLibDecoderConfig {
#[serde(flatten)]
pub thread_pooling_config: ThreadPoolingConfig,
pub library: PathBuf,
#[cfg_attr(feature = "cli", structdoc(skip))]
#[serde(default)]
pub decoder_config: serde_json::Value,
}
fn library_cache() -> &'static Mutex<HashMap<PathBuf, &'static DecoderLibrary>> {
static CACHE: OnceLock<Mutex<HashMap<PathBuf, &'static DecoderLibrary>>> = OnceLock::new();
CACHE.get_or_init(|| Mutex::new(HashMap::new()))
}
fn get_or_load_library(path: &Path) -> &'static DecoderLibrary {
let mut cache = library_cache().lock().unwrap();
if let Some(library) = cache.get(path) {
return library;
}
let library = unsafe { DecoderLibrary::load(path) }
.unwrap_or_else(|e| panic!("failed to load decoder plugin {}: {e}", path.display()));
cache.insert(path.to_path_buf(), library);
library
}
pub struct DynLibInstance {
loaded: LoadedDecoder,
}
impl DecoderInstance for DynLibInstance {
fn new(hypergraph: &DecodingHypergraph, config: &serde_json::Value) -> Self {
let config: DynLibDecoderConfig = serde_json::from_value(config.clone()).expect("invalid DynLibDecoderConfig");
let library = get_or_load_library(&config.library);
let mut edge_probs = Vec::with_capacity(hypergraph.hyperedges.len());
let mut edge_offsets = Vec::with_capacity(hypergraph.hyperedges.len() + 1);
edge_offsets.push(0u64);
let mut edge_vertices = Vec::new();
for hyperedge in &hypergraph.hyperedges {
edge_probs.push(hyperedge.probability);
edge_vertices.extend_from_slice(&hyperedge.vertices);
edge_offsets.push(edge_vertices.len() as u64);
}
let decoder_config = serde_json::to_string(&config.decoder_config).expect("serialize decoder_config");
let loaded = LoadedDecoder::create(
library,
hypergraph.vertex_num,
&edge_probs,
&edge_offsets,
&edge_vertices,
&decoder_config,
)
.unwrap_or_else(|e| panic!("plugin {} failed to build decoder: {e}", config.library.display()));
Self { loaded }
}
fn decode(&mut self, syndrome: &BitVector) -> ParityFactor {
let mut subgraph = Vec::new();
match self.loaded.decode(syndrome.size, &syndrome.data, &mut subgraph) {
Ok(()) => ParityFactor { subgraph },
Err(e) => panic!("dylib decode failed: {e}"),
}
}
fn reset(&mut self) {}
}
pub type DynLibDecoder = ThreadPoolingDecoder<DynLibInstance>;