use pyo3::prelude::*;
use pyo3::types::PyDict;
use pyo3::IntoPyObjectExt;
use std::collections::HashMap;
pub fn get_nested_dict_value(
named: &HashMap<String, PyObject>,
path: &[String],
py: Python,
) -> PyResult<Option<PyObject>> {
if path.is_empty() {
return Ok(None);
}
if path.len() == 1 {
return Ok(named.get(&path[0]).map(|obj| obj.clone_ref(py)));
}
let first_key = &path[0];
let mut current_obj: PyObject = match named.get(first_key) {
Some(v) => v.clone_ref(py),
None => return Ok(None),
};
for key in path.iter().skip(1) {
let current_dict = match current_obj.bind(py).downcast::<PyDict>() {
Ok(d) => d,
Err(_) => return Ok(None), };
match current_dict.get_item(key.as_str())? {
Some(v) => {
current_obj = v.into();
}
None => return Ok(None), }
}
Ok(Some(current_obj))
}
pub fn insert_nested_dict(
named: &mut HashMap<String, PyObject>,
path: &[String],
value: PyObject,
py: Python,
) -> PyResult<()> {
if path.is_empty() {
return Ok(());
}
if path.len() == 1 {
named.insert(path[0].clone(), value);
return Ok(());
}
let first_key = &path[0];
let top_dict = if let Some(existing) = named.get(first_key) {
if let Ok(dict) = existing.bind(py).downcast::<PyDict>() {
dict.clone()
} else {
let new_dict = PyDict::new(py);
let new_dict_obj = new_dict.clone().into_py_any(py)?;
named.insert(first_key.clone(), new_dict_obj);
new_dict
}
} else {
let new_dict = PyDict::new(py);
let new_dict_obj = new_dict.clone().into_py_any(py)?;
named.insert(first_key.clone(), new_dict_obj);
new_dict
};
let mut current_dict = top_dict;
for key in path.iter().skip(1).take(path.len() - 2) {
let nested_dict = if let Some(existing) = current_dict.get_item(key.as_str())? {
if let Ok(dict) = existing.downcast::<PyDict>() {
dict.clone()
} else {
let new_dict = PyDict::new(py);
let new_dict_obj = new_dict.clone().into_py_any(py)?;
current_dict.set_item(key.as_str(), new_dict_obj)?;
new_dict
}
} else {
let new_dict = PyDict::new(py);
let new_dict_obj = new_dict.clone().into_py_any(py)?;
current_dict.set_item(key.as_str(), new_dict_obj)?;
new_dict
};
current_dict = nested_dict;
}
let final_key = &path[path.len() - 1];
current_dict.set_item(final_key.as_str(), value)?;
Ok(())
}