wrnrlr / g3

Neat 3D math and graphics library
ISC License
32 stars 2 forks source link

Use a state type for normalised points #10

Open wrnrlr opened 1 year ago

wrnrlr commented 1 year ago

Some operations are only sensible when the point in normalised and rust has a way of refining what methods can be called on a trait/struct based on some extra type info. Investigate and if possible implement the use of this "generic state type" for normalised points.

Example from https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=24c550bb3e2b129c38fff338017b49f4

struct Point<State>{
    x: f32,
    y: f32,
    _s: State
}

trait PointState {}

struct Normalized;
impl PointState for Normalized{}

struct PossiblyNormalized;
impl PointState for PossiblyNormalized{}

impl Point<PossiblyNormalized>{
    fn new(x: f32, y: f32) -> Self {
        Self {x, y, _s: PossiblyNormalized}
    }
}

// all Points can be added to
impl<State: PointState> Point<State> {
    // we can see from this function signature that adding a constant may break normalization
    fn add(&self, z: f32) -> Point<PossiblyNormalized> {
        Point {
            x: self.x + z,
            y: self.y + z,
            _s: PossiblyNormalized
        }
    }

    // any Point can be re-normalized and applied back, and we can encode that into the type system
    fn normalize(self) -> Point<Normalized>{
        let m = self.magnitude();
        Point {
            x: self.x/m,
            y: self.y/m,
            _s: Normalized
        }
    }
    fn magnitude(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

// this method will only apply to Points that are known to be Normalized
impl Point<Normalized>{
    fn print_normalized(&self){
        println!(" we know that this one has only normalized fields");
        // do stuff that depends on it being normalized
    }
}

fn main(){
    let p: Point<PossiblyNormalized> = Point::new(4.0, 5.0);
    // we can't call print_normalized yet

    let p: Point<Normalized> = p.normalize();
    p.print_normalized();
}

What methods besides normalize can benefit from this?