Skip to content

Instantly share code, notes, and snippets.

@sodiboo
Created February 27, 2024 08:14
Show Gist options
  • Save sodiboo/98efa213e8d16ae91bd064d3f1b10ba3 to your computer and use it in GitHub Desktop.
Save sodiboo/98efa213e8d16ae91bd064d3f1b10ba3 to your computer and use it in GitHub Desktop.
single-child parsing knuffel
use knuffel::{errors::DecodeError, traits::ErrorSpan};
#[derive(knuffel::Decode, Debug)]
enum Width {
Fixed(#[knuffel(argument)] u64),
Proportion(#[knuffel(argument)] f64),
}
#[derive(Debug)]
enum OptChild<T>
{
None,
Some(T),
}
impl<T, S> knuffel::Decode<S> for OptChild<T>
where
T: knuffel::Decode<S>,
S: ErrorSpan,
{
fn decode_node(
node: &knuffel::ast::SpannedNode<S>,
ctx: &mut knuffel::decode::Context<S>,
) -> Result<Self, knuffel::errors::DecodeError<S>> {
let mut children = node.children();
if let Some(child) = children.next() {
if let Some(next) = children.next() {
Err(DecodeError::Unexpected { span: next.span().to_owned(), kind: "node", message: "diagnostic".into() })
} else {
T::decode_node(child, ctx).map(Self::Some)
}
} else {
Ok(Self::None)
}
}
}
#[derive(knuffel::Decode, Debug)]
struct TopLevel {
// Option::None => "no window rule"
// Option::Some(OptChild::None) => "no default width"
// Option::Some(OptChild::Some) => "default width"
#[knuffel(child)]
default_column_width: Option<OptChild<Width>>,
}
fn main() {
let docs = [
"default-column-width {\nproportion 0.5\n}",
"default-column-width {\nfixed 1280\n}",
"default-column-width {\n}",
"default-column-width",
"",
];
for doc in docs {
eprintln!("---");
eprintln!("{doc}");
if let Ok(parsed) = knuffel::parse::<TopLevel>("wh", doc) {
eprintln!("=> {parsed:?}");
} else {
eprintln!("=> (error)");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment