TYMap



Dimmitt is a city in Castro County, Texas, United States. The population was 4,375 at the 2000 census. It is the county seat of Castro County. It is located on the old Ozark Trail, a road system from St. Louis, Missouri, to El Paso, Texas. The Ozark Trail is marked at the courthouse.
Dimmitt is located at 34°32′57″N 102°18′55″W / 34.54917°N 102.31528°W / 34.54917; -102.31528 (34.549052, -102.315355).
According to the United States Census Bureau, the city has a total area of 2.1 square miles (5.4 km²), all of it land. Dimmitt is south of Hereford, the seat of Deaf Smith County.

Or, creating a higher order 'mapping' type

Given a String of C type ty, returns the corresponding Fiddle constant. Ty can also accept an Array of C type Strings, and will be returned in a corresponding Array. If Hash tymap is provided, ty is expected to be the key, and the value will be the C type to be looked up. I want emails from Lonely Planet with travel and product information, promotions, advertisements, third-party offers, and surveys. I can unsubscribe any time using the unsubscribe link at the end of all emails.

Hacking with some performance-critical Rust code recently, I found myself missing some way to construct an enum with variants chosen at compile time by type reflection.

Here's an example of my ideal type (syntax aside):

But why?

I wanted to be able to specialize some struct or function, based on some kind of marker type.

Specifically, in my llama emulator project I wanted to be able to compile two versions of the main interpreter.The Nintendo 3DS uses two (actually three) CPU families: ARM9 and ARM11. And there are significant changes between them, but I wanted to express thesedifferences in terms of specialization. So here I wanted to be able to have some code like this:

You can think of it like a nicer version of C++'s std::enable_if.

Benefits over wrapping an enum

In the hot path, every last branch instruction is a potential performance pitfall. Because all the code that runs here is selected at compile-time, the optimizer can erase all reflection, just like using generics.

Tympanic

Is this idiomatic? What about traits?

Tympanogram

Traits would definitely be the idiomatic way to solve this problem. But using a tymap can provide both an enum's exhaustiveness guarantees and the code monomorphization of traits.

Tympanogram

And, most importantly, the tymap can be stored in structs without any type erasure or runtime penalty.

Implementation

Turns out, we can implement something very similar in stable Rust with the help of macros, enums, and a little unsafe code. See this GitHub repo if you'd like to browse a complete implementation.

Tympanic Temperature

Storage size and alignment

We need our tymap type to be at least as large as the largest variant, with the correct alignment as well. But we won't use a struct with all the variants, because we don't want to waste too much space. A union wouldn't work either, because Rust unions currently only accept Copy fields.

Fortunately, Rust's enum type already provides us size and alignment guarantees. And we can use #[repr(u8)] to allow us to access the enum variant data directly, without caring about the discriminant. This effectively allows us a union without union's restrictions:

Declaring a tymap

We'll have the following syntax for our tymap macro:

valX, here, is an ident, not a type, and is only used for for variable binding and type parameters; it doesn't provide any additional 'information' in the type declaration.

KeyTypeX is both an ident and a type, which unfortunately means that we can only use type names which are also valid idents (but type A = B mitigates this problem).

It would be nice if these tricks weren't necessary, but these are limitations of macro_rules!. A future iteration could use a procedural macro instead for an even nicer syntax.

Constructing a new tymap

First, let's add the type parameter K to $type_name, as well as the enum variant _hidden(PhantomData<K>). K will be the currently active 'key' of our type mapping.

Implementing match

TYMap

How would you use it?