virtue icon indicating copy to clipboard operation
virtue copied to clipboard

Missing feature to specify attributes on GenStruct

Open mscofield0 opened this issue 2 years ago • 1 comments

My use case is the following: I would like to derive a macro for my enum and then for each struct-field variant generate an identical struct which the same attributes as the enum (Clone, Debug, etc...).

mscofield0 avatar Dec 09 '23 10:12 mscofield0

Should be pretty easy:

  • Add a field to the GenStruct struct
  • Add functions to that struct to add attributes
  • Add documentations that also test the output, see this for an example

VictorKoenders avatar Dec 10 '23 19:12 VictorKoenders

I'm taking a stab at thing one too, but the API is a bit tricky. I have attributes stored a pairs of the attribute name and a StreamBuilder for the rest. Adding a single attribute could look like this:

impl<'a, P: Parent> GenStruct<'a, P> {
    pub fn with_attribute<T>(
        &mut self,
        name: impl Into<String>,
        value: impl FnOnce(&mut StreamBuilder) -> Result
    ) -> Result<&mut Self> {
        // ...
    }
}

If we want to add multiple attributes at once, it's unclear how we'd extend this builder pattern to an impl IntoIterator. Another option is to implement TryFrom and From on StreamBuilder for strings and token streams, and use that instead, but that's less flexible than the builder pattern I think.

For fields, it's very cumbersome. For a field with a single attribute, I currently have this to fit with the current field methods:

// GenStruct impl
pub fn add_field_with_attribute<T>(
    &mut self,
    name: impl Into<String>,
    ty: impl Into<String>,
    attribute_name: impl Into<String>,
    attribute_value: T
) -> Result<&mut Self>
where
    T: FnOnce(&mut StreamBuilder) -> Result
{
    // ...
}

You cannot repeat this to add more attributes to the field, unlike with_attribute. If add_field returned a builder, adding attributes to that would be trivial. A non-breaking, easier to use alternative could be:

// GenStruct impl
pub fn add_field_with(
    &mut self,
    name: impl Into<String>,
    ty: impl Into<String>,
    build: impl FnOnce(&mut Field) -> Result
) -> Result<&mut Self> {
    // ...
}

struct Field {
    attributes: Vec<(String, StreamBuilder)>,
    // ...
}

impl Field {
    pub fn with_attribute<T>(
        &mut self,
        name: impl Into<String>,
        value: impl FnOnce(&mut StreamBuilder) -> Result
    ) -> Result<&mut Self> {
        // ...
    }
}

Thoughts?

NightEule5 avatar Jun 11 '24 08:06 NightEule5

If we want to add multiple attributes at once

Let's do the simple solution first; only 1 attribute at a time. We can come up with something smarter in the future

If add_field returned a builder, adding attributes to that would be trivial.

I'd rather make breaking changes early, especially since virtue is still on 0.0.x, so feel free to add a FieldBuilder or something

VictorKoenders avatar Jun 12 '24 05:06 VictorKoenders