Implicit as u8?

impl RegId {
    pub fn to_u8(&self) -> u8 {
        self.0}}

Is there a way to do an implicit RegId -> u8 conversion? Where anywhere we need a u8, we can pass it a RegId, and Rust will auto insert a .to_u8() ?

For whatever reason I've come across plenty of examples like this recently.

fn uses_u8<U: Into<u8>>(value: U) -> u8 { value.into().some_u8_calculation() }

I doubt auto-conversion without an explicit pathway is possible, but the alternative isn't bad.

1 Like

This is a very cool solution, but unfortunately does not work in my case. I have a bunch of dynasm ( GitHub - CensoredUsername/dynasm-rs: A dynasm-like tool for rust. ) code where there is a macro where one of the arguments is a u8 (indicates which register to use).

There's no way to do a true implicit conversion, but your macro could insert u8::from(value).

If the RegId is a newtype over u8, I think such implicit coercion would pass the benefits of the newtype patterns in vain as two different kinds of ids can be mixed together implicitly as a raw integer form.

1 Like

dynasm-rs/lib.rs at master · CensoredUsername/dynasm-rs · GitHub is the macro in question

That's actually a good point. This started as

type RegId = u8

I changed it to

pub struct RegId(u8);

an auto conversion would pretty much undo all benefits.

1 Like

Hmm... maybe RegId should have stayed as a simple type alias, then?

You mentioned this will be used in a macro, so why not update the macro definition to always call .into() on each of its arguments? Every type, T, can be turned into itself so this would end up being a noop most of the time while letting you "implicitly" (from the point of view of the macro's caller) use a RegId as a u8.

Or alternatively, if you are passing values back and forth between assembly you could add a #[repr(transparent)] to the RegId definition. This would allow you to freely transmute back and forth between a RegId and its u8 version, letting you use strong types on the Rust side and a byte in the generated machine code.

I'll just mention that u8::from can work(can't speak to whether it's a good idea), because this is valid in the crate that declares RegId:

impl From<RegId> for u8 {
    fn from(this: RegId) -> u8 {
        this.0
    }
}