Skip to content

Option to keep/generate "closed form" enum #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
fu5ha opened this issue Oct 2, 2024 · 4 comments
Open

Option to keep/generate "closed form" enum #25

fu5ha opened this issue Oct 2, 2024 · 4 comments

Comments

@fu5ha
Copy link

fu5ha commented Oct 2, 2024

In implementing #24 and using it in our code based, the TryFromKnownRepr is useful but only moderately, since you still can't get an exhaustive match on just the known variants afterwards. It would be nice to somehow expose the original closed form of the enum as well, either as just OriginalIdentClosed or perhaps some trait

trait OpenEnum {
    type Closed;
}

then you can OriginalIdent::Closed?

And provide infallible From<Closed> for Open and fallible TryFrom<Closed> for Open, as replacement for TryFromKnownRepr.

@fu5ha
Copy link
Author

fu5ha commented Oct 4, 2024

I took a stab at implementing this in this branch: https://github.com/EmbarkStudios/open-enum/tree/with_closed but in actually trying to use it in our FFI layer it proved less ergonomic than I thought, so I'm not going to go ahead with cleaning it up and PRing unless some more design work happens.

@kupiakos
Copy link
Owner

kupiakos commented Dec 9, 2024

I'm thinking that maybe it should go the other way, where users can write #[derive(OpenEnum)] enum Foo { ... }. The derive(OpenEnum) would work exactly like #[open_enum] except it generates a new open enum type instead of replacing the definition.

I'm on the fence regarding a new trait.

@kupiakos
Copy link
Owner

kupiakos commented Feb 3, 2025

Some open questions and challenges:

Does derive(OpenEnum) generate a new wrapper type, or does it implement a trait to allow for a shared generic type to "open up this enum"? I'd prefer the latter to avoid extra types and enable generic code.

  • If it generates a new type, what's its name, and how can that be controlled? Foo generates an OpenFoo? OpenFoo follows English adjective-noun word ordering. However, FooOpen keeps it next to Foo in sorted autocomplete.
  • If it's done by implementing a trait, how do you access the open version of Foo::Bar? open_enum::Open<LocalEnum> is a foreign type and so inherent constants are forbidden.
    • My initial idea here was to generate a helper struct FooOpenConstants that defines Open<Foo> associated constants in its impl and to nest these all under Foo::Open. However, I couldn't match on the syntax Foo::Open::Bar, with rustc saying there is no Open variant.
    • A...not ideal workaround for this is to put an Open prefix on associated constants on the enum. So Foo::Bar and Foo::OpenBar both exist and only the latter is Open<Foo>. IME it'll be a pain to deal with name conflicts and this could be confusing.
  • Do I support both derive(OpenEnum) and derive(OpenEnumNewtype)?

@kupiakos
Copy link
Owner

kupiakos commented Feb 5, 2025

A macro workaround for open!(Foo::Bar) in match arms could work, but there are caveats and requiring a macro is an ergonomic loss. There are two ways I know to make this work in stable today, since the simple const { Open::new($name) } doesn't work in a pattern yet:

  1. Look up the repr integer in a const generic. Expand to e.g. <Foo as OpenWithVal<{Foo::Bar as i128}>>::VAL, which accesses Open<Self> associated constants generated by the derive. Each variant has a generally accessible discriminant value, though do consider that you can't as cast to get the discriminant from a &Foo where Foo is a !Copy enum
  2. Look up the name in a const generic. This involves a const-time hash of the variant name. Expand to e.g. <Foo as OpenWithName<{const_hash_str(stringify!(Bar))}>>::VAL and do something similar to above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants