If both you and the user have shared access (&T) to a type with interior mutability, such as UnsafeCell, Mutex, or AtomicUsize, then there is no way for the user to not change the interior value. (Barring trivial methods such as ensuring that there is only one thread and taking away control flow from the user, or locking the mutex and dropping its guard).
The way I would tackle this scenario is to keep an AtomicU32, and a local u32. Anytime there's meaningful change to the local u32, you write to the AtomicU32. I'd also document that writing to the AtomicU32 does nothing, or I'd skip all of this outright and simply label it as a logical error (with the added modifiers as necessary, such as improperly modifying it would lead to UB, along with an unsafe marker as necessary).
In this callback-esque scenario, you could let the callback simply take updates by yielding u32s, rather than &AtomicU32s.