Skip to content
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

Hierarchical enums using arbitrary enum discriminants #81

Closed
hecatia-elegua opened this issue Nov 20, 2022 · 6 comments
Closed

Hierarchical enums using arbitrary enum discriminants #81

hecatia-elegua opened this issue Nov 20, 2022 · 6 comments

Comments

@hecatia-elegua
Copy link

Relevant issue: rust-lang/rust#60553

I am currently working on a PCI driver with many predefined values for classes and their subclasses:

enum ClassCode {
    Old(Old) = 0x0,
    MassStorage(MassStorageController) = 0x1,
    Network(NetworkController) = 0x2,
//...
enum MassStorageController {
    SCSI(SCSIController) = 0x0,
    IDE(IDEController) = 0x1,
    FloppyDiskController = 0x2,
//...
enum SCSIController {
    VendorSpecific = 0x00,
    StorageDevice = 0x11,
//...

As you can see, these form a kind of hierarchy.
Now I would want to parse the raw values from pci into an enum-value of type ClassCode.

This would allow for a very nice API:

for device in pci::pci_device_iter() {
    match device.class {
        ClassCode::MassStorage(MassStorageController::SCSI(_)) => //...
        ClassCode::Network(_)  => //...
    }
}
@hecatia-elegua

This comment was marked as outdated.

@hecatia-elegua
Copy link
Author

hecatia-elegua commented Dec 19, 2022

Any input on this, now that arbitrary_enum_discriminant is stabilized?

@illicitonion
Copy link
Owner

Sorry for the delay in getting back to you on this one.

This seems like very specific behaviour, and I'm not sure how general it is... I also don't fully follow the examples, though, so it could be that I'm just not following.

Is there some fixed relationship between the outer and inner enums? Or is the situation that the inner-most enums all have uniquely specified discriminants, each of the inner enums may only appear in exactly one outer enum, and we should just pick whichever outer enum happens to be allowed to contain the inner enum?

Could you point at some real-world code which is currently being manually written, and give some example inputs and how they map to outputs?

@hecatia-elegua
Copy link
Author

I want to reduce things like this: https://github.com/rust-osdev/pci_types/blob/8fe7af081fbd34b2022cd33812635244992f8c72/src/device_type.rs#L185 and the enum above.
PCI and USB and possibly others will send some sort of byte codes which I currently translate with c-like enums and try_from.

Now for the highest possibly safety and ergonomics it makes sense to parse class, subclass (and sub-subclass) at once.
I could use this:

MassStorageSCSIVendorSpecific = 0x1_0000_0000,
MassStorageSCSIStorageDevice = 0x1_0000_0011,

but it's a bit much.

It looks like there are two usecases for how to parse nested enums:

  • you just want to split an enum into multiple sub-types, with only the leaves representing the values
  • my usecase of all nodes representing a value, parsing downward and filling all remaining bytes with zeroes

example for the enums I defined in my initial comment:
PCI gives me some bytes:
[0x1, 0x0, 0x11] -parse> MassStorage(SCSI(StorageDevice))
[0x1, 0x2, 0x0] -parse> MassStorage(FloppyDiskController)

@hecatia-elegua
Copy link
Author

hecatia-elegua commented Mar 20, 2023

@illicitonion
Copy link
Owner

I think this feels like pretty special-case behaviour that probably warrants its own independent implementation outside of this crate. I don't think there's an obvious unique mapping from raw values to a hierarchy of enum values here, so I'd suggest writing a new macro which may use the TryFrom/From implementations generated by this one, and build on top of them.

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