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, ROLES_SCHEMA, Schema, schema_for};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Row {
pub entry: String,
pub name: String,
pub control: Control,
pub help: String,
pub value: String,
pub fault: Option<String>,
}
pub fn read(schema: &Schema, text: &str, provider_rows: &[String]) -> Vec<Row> {
entry_names(text, schema.block)
.into_iter()
.flat_map(|entry| {
schema
.fields
.iter()
.filter_map(|spec| row(schema, text, &entry, spec, provider_rows))
.collect::<Vec<Row>>()
})
.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(),
name: spec.name.to_owned(),
control: spec.control,
help: spec.help.to_owned(),
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,
entry: &str,
spec: &FieldSpec,
value: &str,
) -> Result<String, GrammarError> {
set_field(
schema.file,
text,
schema.block,
entry,
spec.name,
&normalize(spec.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;