Closed halotroop2288 closed 1 year ago
Done. Could you take it for a spin before I publish the release?
Certainly! I've done a bit of testing, it seems that Rust doesn't like it when you do this:
strike! {
union XEX2Version {
value: u32be,
fields: struct {
major: u32be,
minor: u32be,
build: u32be,
qfe: u32be,
},
}
}
Or this:
pub enum XEX2SectionType {
XEXSectionCode = 1,
XEXSectionData = 2,
XEXSectionReadOnlyData = 3,
}
strike! {
struct XEX2PageDescriptor {
a: union {
value: u32be,
b: struct {
info: XEX2SectionType,
page_count: u32be,
},
},
data_digest: [u8; 0x14],
}
}
Here's the error:
error[E0740]: unions cannot contain fields that may need dropping
...
note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
This is also a problem for some structs that aren't anonymously nested like this. It's kind of annoying.
Also, if there's no name for the anon struct, it does this:
error: proc macro panicked
...
help: message: cannot parse named fields: expected `:` punct, got Some(Group { delimiter: Brace, stream: TokenStream [Ident { ident: "major", span: #0 bytes(18977..18982) }, Punct { ch: ':', spacing: Alone, span: #0 bytes(18982..18983) }, Ident { ident: "u32be", span: #0 bytes(18984..18989) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(18989..18990) }, Ident { ident: "minor", span: #0 bytes(19003..19008) }, Punct { ch: ':', spacing: Alone, span: #0 bytes(19008..19009) }, Ident { ident: "u32be", span: #0 bytes(19010..19015) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(19015..19016) }, Ident { ident: "build", span: #0 bytes(19029..19034) }, Punct { ch: ':', spacing: Alone, span: #0 bytes(19034..19035) }, Ident { ident: "u32be", span: #0 bytes(19036..19041) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(19041..19042) }, Ident { ident: "qfe", span: #0 bytes(19055..19058) }, Punct { ch: ':', spacing: Alone, span: #0 bytes(19058..19059) }, Ident { ident: "u32be", span: #0 bytes(19060..19065) }, Punct { ch: ',', spacing: Alone, span: #0 bytes(19065..19066) }], span: #0 bytes(18963..19076) })
But you'd probably expect that in Rust.
I'm kind of considering finding a workaround so I don't have to use unions at all. unions are of course "intrinsically unsafe" so it's probably the best course of action. Still, I think it would be cool to have that working in this crate. :)
it it seem that Rust doesn't like it when you do this:
Yeah, but that has little to do with structstruck. If you try cargo expand
and use the source from there, the same error still appears. (The only thing that's different is that the diagnostic isn't in the wrong place. Not sure what to do about that.)
struct B {
info: XEX2SectionType,
page_count: u32be,
}
union A {
value: u32be,
b: B,
}
struct XEX2PageDescriptor {
a: A,
data_digest: [u8; 0x14],
}
You can get around that by just doing what rustc says. Your stuff needs to be Copy
, which rust takes as a proof that it is "plain old data" (or whatever the rust term for that is).
#[derive(Clone, Copy)]
pub enum XEX2SectionType {
XEXSectionCode = 1,
XEXSectionData = 2,
XEXSectionReadOnlyData = 3,
}
structstruck::strike! {
struct XEX2PageDescriptor {
a: union {
value: u32be,
b: struct {
#![strikethrough[derive(Clone, Copy)]]
info: XEX2SectionType,
page_count: u32be,
},
},
data_digest: [u8; 0x14],
}
}
I did however find one bug: If you take the other part of rustc's advice and do b: std::mem::DropManually<struct { … }>
, venial chokes on the :
. Again unrelated to this, I'll fix it some other day.
Also, if there's no name for the anon struct, it does this:
You mean like this?
union XEX2Version {
value: u32be,
struct {
major: u32be,
}
}
This is partially venial not really being on board with the whole "a compiler is an error reporting tool with a code generation side gig", and partially a disadvantage of something like structstruck: The grammar allowed by structstruck is just much more complex, so the error messages won't be as helpful.
My goal is to port some particularly awful C++ code for legacy support (emulation), and it makes heavy use of patterns like:
It would be nice if you could support this pattern to maybe save me some time. 😅
I'm hoping for an implementation something like this: