use std::collections::HashMap;
use std::fs::File;
use std::io::BufReader;
use std::path::Path;
use super::error::Error;
use burn::record::serde::{adapter::DefaultAdapter, data::NestedValue, de::Deserializer};
use candle_core::pickle::{Object, Stack};
use serde::de::DeserializeOwned;
use zip::ZipArchive;
fn read_pt_info<P: AsRef<Path>>(file_path: P, key: Option<&str>) -> Result<NestedValue, Error> {
let mut zip = ZipArchive::new(BufReader::new(File::open(file_path)?))?;
let data_pkl_path = (0..zip.len()).find_map(|i| {
let file = zip.by_index(i).ok()?; if file.name().ends_with("data.pkl") {
Some(file.name().to_string())
} else {
None
}
});
let data_pkl_path =
data_pkl_path.ok_or_else(|| Error::Other("data.pkl not found in archive".to_string()))?;
let reader = zip.by_name(&data_pkl_path)?;
let mut reader = BufReader::new(reader);
let mut stack = Stack::empty();
stack.read_loop(&mut reader)?;
let obj = stack.finalize()?;
let obj = extract_relevant_object(obj, key)?;
to_nested_value(obj)
}
fn to_nested_value(obj: Object) -> Result<NestedValue, Error> {
match obj {
Object::Bool(v) => Ok(NestedValue::Bool(v)),
Object::Int(v) => Ok(NestedValue::I32(v)),
Object::Float(v) => Ok(NestedValue::F64(v)),
Object::Unicode(v) => Ok(NestedValue::String(v)),
Object::List(v) => {
let list = v
.into_iter()
.map(to_nested_value)
.collect::<Result<Vec<_>, _>>()?;
Ok(NestedValue::Vec(list))
}
Object::Dict(key_values) => {
let map = key_values
.into_iter()
.filter_map(|(name, value)| {
if let Object::Unicode(name) = name {
let nested_value = to_nested_value(value).ok()?;
Some((name, nested_value))
} else {
None }
})
.collect::<HashMap<_, _>>();
Ok(NestedValue::Map(map))
}
_ => Err(Error::Other("Unsupported value type".into())),
}
}
fn extract_relevant_object(obj: Object, key: Option<&str>) -> Result<Object, Error> {
if let Some(key) = key {
if let Object::Dict(key_values) = obj {
key_values
.into_iter()
.find(|(k, _)| {
if let Object::Unicode(k_str) = k {
k_str == key
} else {
false
}
})
.map(|(_, v)| v)
.ok_or_else(|| Error::Other(format!("Key `{key}` not found")))
} else {
Err(Error::Other(
"Object is not a dictionary as expected".into(),
))
}
} else {
Ok(obj)
}
}
pub fn config_from_file<D, P>(path: P, top_level_key: Option<&str>) -> Result<D, Error>
where
D: DeserializeOwned,
P: AsRef<Path>,
{
let nested_value = read_pt_info(path, top_level_key)?;
let deserializer = Deserializer::<DefaultAdapter>::new(nested_value, true);
let value = D::deserialize(deserializer)?;
Ok(value)
}