use serde_json::{Map, Value};
pub fn str_of(o: &Map<String, Value>, key: &str) -> Result<String, String> {
match o.get(key) {
Some(Value::String(s)) => Ok(s.clone()),
Some(_) => Err(format!("field {key:?} is not a string")),
None => Err(format!("missing field {key:?}")),
}
}
pub fn opt_str_of(o: &Map<String, Value>, key: &str) -> Result<Option<String>, String> {
match o.get(key) {
None | Some(Value::Null) => Ok(None),
Some(Value::String(s)) => Ok(Some(s.clone())),
Some(_) => Err(format!("field {key:?} is not a string")),
}
}
pub fn bool_of(o: &Map<String, Value>, key: &str) -> Result<bool, String> {
match o.get(key) {
Some(Value::Bool(b)) => Ok(*b),
Some(_) => Err(format!("field {key:?} is not a boolean")),
None => Err(format!("missing field {key:?}")),
}
}
pub fn strings_of(o: &Map<String, Value>, key: &str) -> Result<Vec<String>, String> {
let Some(value) = o.get(key) else {
return Err(format!("missing field {key:?}"));
};
let rows = value
.as_array()
.ok_or_else(|| format!("field {key:?} is not an array"))?;
rows.iter()
.map(|row| match row {
Value::String(s) => Ok(s.clone()),
_ => Err(format!(
"field {key:?} holds something that is not a string"
)),
})
.collect()
}
#[cfg(test)]
mod tests;