Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mutable Swizzles #516

Open
the-ssd opened this issue May 26, 2024 · 3 comments
Open

Mutable Swizzles #516

the-ssd opened this issue May 26, 2024 · 3 comments

Comments

@the-ssd
Copy link

the-ssd commented May 26, 2024

The main Idea is to be able to do this

let mut test_vec = Vec3::ZERO;
*test_vec.xy_mut() = Vec2::ONE;
assert_eq!(test_vec, Vec3::new(1.0, 1.0, 0.0))

Here is something that works, but only done for xy_mut()

trait MutSwizzleVec3<'a> {
    fn xy_mut(&'a mut self) -> Vec3XY<'a>;
}

impl<'a> MutSwizzleVec3<'a> for Vec3 {
    fn xy_mut(&'a mut self) -> Vec3XY<'a> {
        let xy = self.xy();
        Vec3XY {
            inner: self,
            thing: xy,
        }
    }
}

struct Vec3XY<'a> {
    inner: &'a mut Vec3,
    thing: Vec2,
}

impl<'a> core::ops::Deref for Vec3XY<'a> {
    type Target = Vec2;

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

impl<'a> core::ops::DerefMut for Vec3XY<'a> {
    fn deref_mut(&mut self) -> &mut Vec2 {
        &mut self.thing
    }
}

impl Drop for Vec3XY<'_> {
    fn drop(&mut self) {
        self.inner.x = self.thing.x;
        self.inner.y = self.thing.y;
    }
}

#[test]
fn _test() {
    let mut test_vec = Vec3::ZERO;
    *test_vec.xy_mut() = Vec2::ONE;
    assert_eq!(test_vec, Vec3::new(1.0, 1.0, 0.0))
}
@the-ssd
Copy link
Author

the-ssd commented May 26, 2024

Alternatively, it can be implemented like this. (But this doesn't allow passing &mut Vec2 to a function, for example)

pub trait Vec3SwizzleSet {
    fn set_xz(&mut self, thing: Vec2);
    fn set_xy(&mut self, thing: Vec2);
    fn set_zy(&mut self, thing: Vec2);
    fn set_yz(&mut self, thing: Vec2);
}

impl Vec3SwizzleSet for Vec3 {
    fn set_xz(&mut self, thing: Vec2) {
        self.x = thing.x;
        self.z = thing.y;
    }

    fn set_xy(&mut self, thing: Vec2) {
        self.x = thing.x;
        self.y = thing.y;
    }

    fn set_zy(&mut self, thing: Vec2) {
        self.z = thing.x;
        self.y = thing.y;
    }

    fn set_yz(&mut self, thing: Vec2) {
        self.y = thing.x;
        self.z = thing.y;
    }
}

@bitshifter
Copy link
Owner

I was thinking about this when adding the with_x etc. methods, which would be an alternative to a set that mutates,

So rather than fn set_zy(&mut self, v: Vec2) it would be fn with_zy(self, v: Vec2) -> Self, although both have their uses.

The swizzles are all generated code which does reduce the amount of typing required but that particular bit of codegen is reasonably complex.

One complication is it would be good to support Vec3 and Vec3A as the thing vector which will probably make the trait slightly more complex.

@the-ssd
Copy link
Author

the-ssd commented May 27, 2024

What about making it impl Into<Vec3>?
If both have their use cases, then maybe have both?

I saw, and I was trying to understand what was going on, but failed.
I made a marco which generates Vec3SwizzleSet. But AFAIK macros will slow down compilation compared to the current approach. (maybe with proc-marco2 the codegen can be modified to output the generated code into a file?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants