#Deref, but for fields. Is it possible?

37 messages · Page 1 of 1 (latest)

fast moon
#

I almost got it to work, but field access requires unsafe.

#![feature(untagged_unions)]
use std::ops::Deref;

struct T {
    _a: u32,
    _b: u32,
}

impl T {
    fn new(a: u32, b: u32) -> Self {
        T { _a: a, _b: b }
    }
}

impl Deref for T {
    type Target = U;

    fn deref(&self) -> &Self::Target {
        unsafe { std::mem::transmute(self) }
    }
}

struct A {
    a: u32,
    b: u32,
}

impl Deref for A {
    type Target = u32;

    fn deref(&self) -> &Self::Target {
        &self.a
    }
}

struct B {
    a: u32,
    b: u32,
}

impl Deref for B {
    type Target = u32;

    fn deref(&self) -> &Self::Target {
        &self.b
    }
}

union U {
    a: A,
    b: B,
}

fn main() {
    let t = T::new(1, 2);
    unsafe {
        println!("{}", *t.a + *t.b);
    }
}
rigid vigil
#

You don't need the feature, by the way.

#

You can instead wrap the union's fields in ManuallyDrop, or make them be Copy

fast moon
#

That also work too

#

But I had to do println!("{}", **t.a + **t.b);

rigid vigil
#

You can remove the transmute by using something like U { a: self }, I think?

#

But, uh, what exactly are you trying to do?

fast moon
#

Make field access a function

#

I guess?

rigid vigil
#

Actually wait, no, you do need the transmute, right

rigid vigil
fast moon
#

true

#

But I want to do this for consistency

rigid vigil
#

You can get a function to run when some field is accessed, but you won't know which field that was.

#

You can (ab)use deref to do that

#

(and it can be dodged by simply accessing the field by value)

fast moon
#

I think I'm already abusing deref to the max level though

#

I literally have a struct that derefs to a union that has structs for each field that derefs to the type of the field

rigid vigil
#

So now field access is unsafe for... What reason?

fast moon
#

union field accesses are unsafe

rigid vigil
#

Tbh I don't see what exactly the union is buying you

#

That's my point

fast moon
#

union lets me (virtually) implement deref per field

#

I do understand why union accesses are unsafe, but I wish there was at least an option to override it

rigid vigil
#

Are you interested in cursed solutions that don't involve unions and I'm not sure work?

fast moon
#

I love cursed stuff

#

Bring it on

rigid vigil
#

Assume Foo has fields a, b, c. Make structs A, AB, ABC containing only the corresponding fields, plus padding (_pad: [MaybeUninit<u8>; APPROPRIATE_SIZE]) so they're all equally big.
Foo derefs to A derefs to AB derefs to ABC. The deref operation is implemented by transmuting the reference.

Now, foo.a derefs once, and accesses A::a. foo.b derefs twice, and accesses AB::b. foo.c, of course, derefs thrice, and accesses ABC::c

fast moon
#

That should work

#

Holy

#

The only concern is how well the compiler will handle 10+ deref chains

rigid vigil
#

It also means you run all the intermediate derefs, which don't know if they're the last one or not. This might possibly be fixable? I wouldn't know how, that's for sure.

fast moon
#

it actually works

rigid vigil
#

A doesn't expose a, but derefs to something that does... No wait, only one deref per struct

#

For the sake of sanity, please don't do this in production or otherwise outside of toy/personal cose.

fast moon
#

I think I'll just keep it as a temporary solution