John Simon
John Simon

Reputation: 11

Temporarily Mutating Immutable Structs

I am attempting to create something similar to the code below. Is it safe to cast raw pointers as such given that I am only temporarily modifying the immutable struct (I undo the changes I make)?

#[derive(Debug)]
struct Num(i32); // doesn't impl Copy

// prints one more than the input num
fn modify_read_undo(num: &Num) {
    let num_ptr = num as *const Num as *mut Num; // the scary part
    unsafe {
        (*num_ptr).0 += 1;
        println!("{:?}", *num_ptr);
        (*num_ptr).0 -= 1;
    }
}

fn main() {
    let num = Num(0);
    modify_read_undo(&num); // prints "Num(1)" as hoped for
}

In this small example, everything seems to be working as it should, but I am worried that this is somehow undefined behavior that just happens to be working for now. Is this sort of function possible if it just takes an immutable reference? If not, how can a similar pattern (modify, read, undo) be achieved?

I know that this could work if I use a mutable reference or just take ownership – I am specifically interested in making this work with an immutable reference (to satisfy trait bounds). I can post my full code if that is necessary, but this example is a pretty good demonstration of what I want.

Note: Is there a way to make an immutable reference mutable? is similar, but not quite the same because they permanently change the immutable struct, whereas I undo my changes right after making them.

Upvotes: 1

Views: 66

Answers (1)

devio
devio

Reputation: 1169

Here's a simple example using Cell:

use std::cell::Cell;

#[derive(Debug)]
struct Num(Cell<i32>); // Use Cell for interior mutability

fn modify_read_undo(num: &Num) {
    // Update the value directly with no need for borrowing
    num.0.set(num.0.get() + 1);
    println!("{:?}", num);
    // Undo the change
    num.0.set(num.0.get() - 1);
}

fn main() {
    let num = Num(Cell::new(0));
    modify_read_undo(&num);
    println!("{:?}", num); // prints "Num(Cell { value: 0 })"
}

Upvotes: 1

Related Questions