knuffel icon indicating copy to clipboard operation
knuffel copied to clipboard

Child or Property decoding

Open ghost opened this issue 2 years ago • 1 comments

Hello! I would like to parse the following document:

image "nginx" {
    reference "docker.io/library/nginx:1.23.4"
}

image "nginx" reference="docker.io/library/nginx:1.23.4"

Imagine that image could have 100 files. Or, it could have 1. Opening an entire block for just one argument seems excessive, but specifying 100 options using properties is similar. It would be nice if there was a way to decode either #knuffel(child, unwrap(argument)) or #knuffel(property) with a single derive argument. Here is my current, though admittedly fairly digusting, solution:

enum Image {
    Explicit(ExplicitImage),
    Inline(InlineImage),
}

impl<S: ErrorSpan> Decode<S> for Image {
    fn decode_node(
        node: &knuffel::ast::SpannedNode<S>,
        ctx: &mut knuffel::decode::Context<S>,
    ) -> Result<Self, knuffel::errors::DecodeError<S>> {
        if node.properties.is_empty() {
            ::knuffel::Decode::decode_node(node, ctx).map(Self::Explicit)
        } else {
            ::knuffel::Decode::decode_node(node, ctx).map(Self::Inline)
        }
    }
}

#[derive(knuffel::Decode)]
struct ExplicitImage {
    #[knuffel(argument)]
    name: String,
    #[knuffel(child, unwrap(argument))]
    reference: String,
}

#[derive(knuffel::Decode)]
struct InlineImage {
    #[knuffel(argument)]
    name: String,
    #[knuffel(property)]
    reference: String,
}

At the end of the day, we end up with two identical structs and a manual Decode implementation. That's a lot of boilerplate!

ghost avatar Apr 09 '23 03:04 ghost

Yeah, I think this could be done. I'm not sure if I have time for that any time soon.

In the meantime, you can probably achieve less repeating code by making a quick rule-based macro that defines three similar structs (two intermediate and one final) with different attributes on fields.

tailhook avatar Apr 09 '23 10:04 tailhook