I'm writing a procedural macro that initializes fields of some struct based on the list of key, values. Something like this:
#[derive(FromKeyValue)]
struct SomeStruct {
field1: Field,
field2: Vec<Field>,
}
fn main() {
let some = SomeStruct::from_key_values(..).
}
The issue here is that my procedural macro needs to distinguish Vec
from everything else (the rules are that for Vec
repeating keys are appended, for non-Vec
, it's an error). Ideally, I will be able to implement some trait FromKeyValue
for Vec<Field>
and for Field
. However, for various reasons, it's not that easy. For example, my Value
type in key value list is not the same as Field
, but rather Value: Into<Field>
, which makes type challenges way too complicated.
I would like to have a trait "specialization" based on the target field type: if it's Vec
, go Vec
path, otherwise go plain path. However, to use @dtolnay's trick, I need to dispatch on the target type. But I don't have an instance of it yet, because I'm about to construct it!
If Field
is Default
, this becomes trivial: just make a Default::default()
instance, dispatch on it, then update it with the proper value.
However, in my case, it is not Default
(not always, anyways). I came up with the following trick to trick compiler into inferring the type without actually initializing the value: Rust Playground
And it works!
However, my concern here, is it UB or not? The code inside the if false { .. }
block would be an UB, if it ever runs (since it will dereference pointer that was not initialized). However, that blocks never runs, so it should be okay?
P.S. I think, this question was asked after the discussion I had with other folks, and yes, typeof
would have helped here (I would still had to create some "fake" instance for "specialization" to work, but it would have been something like MaybeUninit<typeof(struct.field)>::uninit().as_ptr()
).
P.P.S. This better be not a UB... I already converted our procedural macro and I was able to remove all the type sniffing based on the syntax (checking that fields are marked by certain attributes, checking literal type names, etc). This autoref specialization is simply genius. It fits macros very nicely since those "tags" are completely different types, and whatever you do on them has to only match syntactically (not on the type system level) -- reminds me of SFINAE in C++.