use serde_json::{Map, Value, json};
use crate::boundary::codec::fields::{list_of, opt_str_of, str_of, u64_of};
use crate::config_edit::form::{Control, Row};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ConfigView {
pub text: String,
pub settings: Vec<Row>,
}
pub(super) fn config(view: &ConfigView) -> Value {
json!({
"ok": true, "kind": "config", "text": view.text,
"settings": view.settings.iter().map(setting).collect::<Vec<Value>>(),
})
}
pub(crate) fn config_of(o: &Map<String, Value>) -> Result<ConfigView, String> {
Ok(ConfigView {
text: str_of(o, "text")?,
settings: list_of(o, "settings", decode)?,
})
}
fn setting(row: &Row) -> Value {
let mut map = Map::new();
map.insert("entry".to_owned(), json!(row.entry));
map.insert("name".to_owned(), json!(row.name));
map.insert("control".to_owned(), control(row.control));
map.insert("help".to_owned(), json!(row.help));
map.insert("value".to_owned(), json!(row.value));
if let Some(fault) = &row.fault {
map.insert("fault".to_owned(), json!(fault));
}
Value::Object(map)
}
fn control(control: Control) -> Value {
match control {
Control::Provider => json!({ "kind": "provider" }),
Control::List => json!({ "kind": "list" }),
Control::Text => json!({ "kind": "text" }),
Control::Number { min, max } => json!({ "kind": "number", "min": min, "max": max }),
}
}
fn decode(v: &Value) -> Result<Row, String> {
let o = v.as_object().ok_or("setting: not an object")?;
Ok(Row {
entry: str_of(o, "entry")?,
name: str_of(o, "name")?,
control: control_of(
o.get("control")
.ok_or("setting: missing field \"control\"")?,
)?,
help: str_of(o, "help")?,
value: str_of(o, "value")?,
fault: opt_str_of(o, "fault")?,
})
}
fn control_of(v: &Value) -> Result<Control, String> {
let o = v.as_object().ok_or("control: not an object")?;
match str_of(o, "kind")?.as_str() {
"provider" => Ok(Control::Provider),
"list" => Ok(Control::List),
"text" => Ok(Control::Text),
"number" => Ok(Control::Number {
min: u64_of(o, "min")?,
max: u64_of(o, "max")?,
}),
other => Err(format!("control: unknown kind {other:?}")),
}
}
#[cfg(test)]
mod tests;