use crate::model_pick::grammar::{
GrammarError, entry_field, entry_names, flow_members, flow_value, is_unknown_row, set_field,
};
mod schema;
pub use schema::{
CADENCE_SCHEMA, Control, FieldSpec, MODELS_SCHEMA, ROLES_SCHEMA, Schema, schema_for,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Row {
pub entry: String,
pub field: &'static str,
pub control: Control,
pub help: &'static str,
pub value: String,
pub fault: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Group {
pub entry: String,
pub rows: Vec<Row>,
}
pub fn read(schema: &Schema, text: &str, provider_rows: &[String]) -> Vec<Group> {
entry_names(text, schema.block)
.into_iter()
.map(|entry| {
let rows = schema
.fields
.iter()
.filter_map(|spec| row(schema, text, &entry, spec, provider_rows))
.collect();
Group { entry, rows }
})
.collect()
}
fn row(
schema: &Schema,
text: &str,
entry: &str,
spec: &FieldSpec,
provider_rows: &[String],
) -> Option<Row> {
let raw = entry_field(text, schema.block, entry, spec.name)?;
let (value, fault) = present(spec.control, &raw, provider_rows);
Some(Row {
entry: entry.to_owned(),
field: spec.name,
control: spec.control,
help: spec.help,
value,
fault,
})
}
fn present(control: Control, raw: &str, provider_rows: &[String]) -> (String, Option<String>) {
match control {
Control::Provider => (
raw.to_owned(),
is_unknown_row(raw, provider_rows).then(|| {
format!(
"brazen's table has no provider row `{raw}` — every dispatch \
through it dies with `unknown provider`; pick a live row, or \
add the row in the brazen config editor"
)
}),
),
Control::List => match flow_members(raw) {
Some(members) => (members.join(", "), None),
None => (
raw.to_owned(),
Some(format!(
"not the inline `[a, b]` form yog edits — fix `{raw}` in the \
raw text below"
)),
),
},
Control::Number { min, max } => (
raw.to_owned(),
match raw.parse::<u64>() {
Ok(n) if (min..=max).contains(&n) => None,
_ => Some(format!("expected a whole number from {min} to {max}")),
},
),
Control::Text => (raw.to_owned(), None),
}
}
pub fn write(schema: &Schema, text: &str, row: &Row, value: &str) -> Result<String, GrammarError> {
set_field(
schema.file,
text,
schema.block,
&row.entry,
row.field,
&normalize(row.control, value),
)
}
fn normalize(control: Control, value: &str) -> String {
match control {
Control::Number { min, max } => value
.trim()
.parse::<u64>()
.unwrap_or(min)
.clamp(min, max)
.to_string(),
Control::List => flow_value(
&value
.split(',')
.map(str::trim)
.filter(|s| !s.is_empty())
.map(str::to_owned)
.collect::<Vec<String>>(),
),
Control::Provider | Control::Text => value.trim().to_owned(),
}
}
#[cfg(test)]
mod tests;