use std::path::Path;
use std::sync::Arc;
use onnx_runtime_ir::Graph;
use onnx_runtime_shape_inference::{InferenceRegistry, MergePolicy};
use crate::graph_builder::BuiltGraph;
pub mod encoder;
pub mod epcontext;
pub mod graph_builder;
pub mod proto;
pub mod weights;
pub mod writer;
mod pathsafe;
pub use encoder::{
encode_model, encode_model_proto, write_model, Model, ModelMetadata, DEFAULT_IR_VERSION,
};
pub use epcontext::{
ep_context_node_ids, ep_context_nodes, is_ep_context_op, resolve_ep_context, EmbedMode,
EpContextBlob, EpContextNode,
};
pub use error::LoaderError;
pub use weights::WeightStore;
pub use writer::{dump_ep_context, EpContextDumpConfig, EpContextPartition};
mod error {
use std::path::PathBuf;
#[derive(Debug, thiserror::Error)]
pub enum LoaderError {
#[error("failed to read model file {path}: {source}")]
Io {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("failed to parse ONNX protobuf: {0}")]
ProtobufParse(String),
#[error("unsupported opset: domain={domain}, version={version}")]
UnsupportedOpset { domain: String, version: u64 },
#[error("external data file not found: {path}")]
ExternalDataNotFound { path: PathBuf },
#[error("external data path rejected ({reason}): {path}")]
ExternalDataPath { path: String, reason: &'static str },
#[error("weight mmap failed: {0}")]
Mmap(String),
#[error("EPContext node error: {0}")]
EpContext(String),
#[error("EPContext external path rejected ({reason}): {path}")]
EpContextPath { path: String, reason: &'static str },
#[error("graph construction failed: {0}")]
GraphBuild(String),
#[error("unsupported ONNX data_type {raw} at {context}")]
UnsupportedDataType { raw: i32, context: String },
#[error("shape inference failed: {0}")]
ShapeInference(#[from] onnx_runtime_shape_inference::ShapeInferError),
#[error(transparent)]
Ir(#[from] onnx_runtime_ir::IrError),
}
}
pub fn load_model(path: impl AsRef<Path>) -> Result<Graph, LoaderError> {
Ok(load_model_with_weights(path)?.0)
}
pub fn load_model_bytes(bytes: &[u8]) -> Result<Graph, LoaderError> {
Ok(load_model_bytes_with_weights(bytes, Path::new("."))?.0)
}
pub fn load_model_with_weights(
path: impl AsRef<Path>,
) -> Result<(Graph, Arc<WeightStore>), LoaderError> {
let path = path.as_ref();
let bytes = std::fs::read(path).map_err(|source| LoaderError::Io {
path: path.to_path_buf(),
source,
})?;
let model_dir = path.parent().unwrap_or_else(|| Path::new("."));
build_from_bytes_with_weights(&bytes, model_dir)
}
pub fn load_model_bytes_with_weights(
bytes: &[u8],
base_dir: impl AsRef<Path>,
) -> Result<(Graph, Arc<WeightStore>), LoaderError> {
build_from_bytes_with_weights(bytes, base_dir.as_ref())
}
fn build_from_bytes_with_weights(
bytes: &[u8],
model_dir: &Path,
) -> Result<(Graph, Arc<WeightStore>), LoaderError> {
let model = proto::decode_model(bytes)?;
let BuiltGraph {
mut graph,
name_map,
} = graph_builder::build_graph(&model)?;
let store = weights::load_weights(&model, model_dir, &name_map)?;
for (&vid, weight) in &store.weights {
graph.set_initializer(vid, weight.clone());
}
let registry = InferenceRegistry::default_registry();
let opset_imports = graph.opset_imports.clone();
registry.infer_graph(&mut graph, &opset_imports, MergePolicy::Permissive)?;
Ok((graph, Arc::new(store)))
}