pub mod types;
pub mod traits;
pub mod json;
pub const FORMAT_VERSION: &str = "1.0";
pub use types::{ModelMetadata, ModelType, SerializedModel};
pub use traits::{ModelLoad, ModelSave};
#[macro_export]
macro_rules! impl_serialization {
($type_name:ty, $model_type:expr, $type_str:expr) => {
impl $crate::serialization::ModelSave for $type_name {
fn save_with_name(&self, path: &str, name: Option<String>) -> $crate::error::Result<()> {
use $crate::serialization::{ModelMetadata, SerializedModel};
use $crate::error::Error;
let data = serde_json::to_value(self).map_err(|e| {
Error::SerializationError(format!("Failed to serialize {}: {}", $type_str, e))
})?;
let mut metadata = ModelMetadata::new($model_type, env!("CARGO_PKG_VERSION").to_string());
if let Some(n) = name {
metadata = metadata.with_name(n);
}
let model = SerializedModel::new(metadata, data);
$crate::serialization::json::save_to_file(&model, path)
}
fn model_type() -> $crate::serialization::ModelType {
$model_type
}
}
impl $crate::serialization::ModelLoad for $type_name {
fn load(path: &str) -> $crate::error::Result<Self> {
let model = $crate::serialization::json::load_from_file(path)?;
if model.metadata.model_type != $model_type {
return Err($crate::error::Error::ModelTypeMismatch {
expected: $type_str.to_string(),
found: model.metadata.model_type.to_string(),
});
}
Self::from_serialized(model)
}
fn from_serialized(model: $crate::serialization::SerializedModel) -> $crate::error::Result<Self> {
use $crate::error::Error;
serde_json::from_value(model.data).map_err(|e| {
Error::DeserializationError(format!("Failed to deserialize {}: {}", $type_str, e))
})
}
fn model_type() -> $crate::serialization::ModelType {
$model_type
}
}
};
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
struct TestModel {
value: f64,
}
impl_serialization!(TestModel, ModelType::OLS, "TestModel");
#[test]
fn test_macro_generates_save() {
let model = TestModel { value: 42.0 };
assert_eq!(<TestModel as ModelSave>::model_type(), ModelType::OLS);
}
#[test]
fn test_macro_generates_load() {
assert_eq!(<TestModel as ModelLoad>::model_type(), ModelType::OLS);
}
}