fu5ha / sdfu

Signed Distance Field Utilities
https://crates.io/crates/sdfu
118 stars 11 forks source link

Question: Creating an SDF trait object #10

Open sanisoclem opened 11 months ago

sanisoclem commented 11 months ago

I would like to store an SDF in a struct without making it generic. However I cannot use dyn and put in a Box or Arc because of the Self:Sized constraint (from Copy).

I would like to create a big SDF once and use it in multiple places immutably, in simple struct:

// compile error
pub struct Bounds(Arc<dyn SDF<f32, Vec2>>);

Making it generic would work but it makes it hard to work with as every single consumer would need to know what kind of SDF it is (they don't care). I would also like to put them all into a single immutable list, and generics make that very hard (impossible?).

Is it possible to drop the copy constraint from the trait itself? or any suggestions would be welcome (I'm fairly new to rust).

fu5ha commented 11 months ago

Yeah, object safety (i.e. ability to use as a trait object) was something of an oversight, which is a downside that I realized fairly quickly when using and was playing with a few possible solutions but never fully finished any of them. You can definitely remove the Copy bound but I think that won't be all you need to do to make it actually object safe.

If you can build your actual concrete sdf type through static dispatch and only want to actually 'sample' it afterwards, then another option that wouldn't require you to change sdfu itself would be to make your own object safe trait which you implement generically for your own struct. I.e. something like this

pub struct BuiltSdfHolder<S> {
    sdf: S,
}

pub trait BuiltSdf {
    fn dist(&self, p: Vec2) -> f32;
}

impl<S: SDF<f32, Vec2>> BuiltSdf for BuiltSdfHolder<S> {
    #[inline]
    fn dist(&self, p: Vec2) -> f32 {
        self.sdf.dist(p)
    }
}

// now you can do what you wanted
pub struct Bounds(Arc<dyn BuiltSdf>);

Otherwise, you'll need to remove the Copy bound but also change all the methods from taking self to &self, which may require other changes as well, I can't really remember. If you do try to reconfigure things and find a setup that feels nice to use to you, do open a PR :)

sanisoclem commented 11 months ago

Thanks for the response :)

I've made some changes that works for me although its not as clean as I would like:

https://github.com/fu5ha/sdfu/compare/master...sanisoclem:sdfu:master

I went the lazy route and just modified the SDF trait. I had to move the normal calculation functions to outside the trait as I needed normals too and just made them generic over any Clone + Deref<Target = dyn SDF<..> type. I hope I saw your comment first because that would be cleaner. If get around to doing it, I'll open a PR 👍