lazy-init icon indicating copy to clipboard operation
lazy-init copied to clipboard

Would it be safe to add a way to mutate the value if it were only possible through a &mut reference?

Open AlphaModder opened this issue 7 years ago • 1 comments

Sorry if this is not the place to ask this question, but I was wondering if a version of LazyTransform whose value could be mutated once initialized through an &mut reference would somehow break the thread-safety?

I'm imagining an implementation along the lines of this:

pub fn get_or_create_mut<F>(&mut self, f: F) -> &mut U 
    where F: FnOnce(T) -> U
{
    if !self.initialized.load(Ordering::Relaxed) {
        let value = unsafe { &mut *self.value.get() };
        let this = match value.take().unwrap() {
            ThisOrThat::This(t) => t,
            ThisOrThat::That(_) => panic!(), 
        };
        *value = Some(ThisOrThat::That(f(this)));
        self.initialized.store(true, Ordering::Relaxed);
    }
    self.extract_mut().unwrap()
}

fn extract_mut(&mut self) -> Option<&mut U> {
    match unsafe { (*self.value.get()).as_mut() } {
        None => None,
        Some(&mut ThisOrThat::This(_)) => panic!(),
        Some(&mut ThisOrThat::That(ref mut that)) => Some(that),
    }
}

Intuitiviely, I imagine the &mut reference would ensure there's no need for actual synchronization, but this stuff is tricky so I want to make sure. This isn't exactly a feature-request, though, since if it works, it's easy enough for me to implement on my own, so I hope you don't mind me using an issue to ask.

AlphaModder avatar Feb 18 '18 23:02 AlphaModder

You could do something like that. std::sync::Mutex has a get_mut which functions on the same principle: that if you have an &mut you are statically guaranteeing that nobody else is accessing the synchronized object.

I might quibble a bit with API design questions (like whether it makes sense to create the object/do the transform and then immediately mutate it) but the thread safety principle is sound.

khuey avatar Feb 19 '18 10:02 khuey