{
  "$type": "site.standard.document",
  "bskyPostRef": {
    "cid": "bafyreico5xtcyxayrnspiucbi2fy236lehbairzb76hm52kiinap2ai5wu",
    "uri": "at://did:plc:ivbknywyskln22er3nkssdhl/app.bsky.feed.post/3mgeaf3wm5jv2"
  },
  "path": "/t/interior-mutability-and-safety-of-ownership-transfer-in-rust/24055#post_8",
  "publishedAt": "2026-03-05T21:11:30.000Z",
  "site": "https://internals.rust-lang.org",
  "textContent": "increasing:\n\n> If i understand correctly this is enough here, as any data behind an indirection won't be copied by `ptr::read/write` and so won't be duplicated during the reallocation.\n\nYes, to me that seems to be the case. \"Shallow\" interior mutability is a problem that can lead to data races, but interior mutability behind an indirection layer should be fine _if_ the duplication of values is in itself not unsound.\n\nBut it seems my description was not as clear as I had thought it was, so I'll try to explain it a bit better (hopefully).\n\nSo, a simplified version of the buffer type could look like this:\n\n\n    struct Buffer<K, V> {\n        len: usize,\n        pairs: [(K, V)], // Note: This field makes Buffer a DST!\n    }\n\n\nA pseudo-code function for growing a buffer would roughly look like this:\n\n\n    struct HashMap<K, V> {\n        buf: AtomicPtr<Buffer<K, V>>,\n        rcu: Rcu,\n    }\n\n    impl<K, V> HashMap<K, V>\n    where\n        K: Hash + Eq + Freeze,\n        V: Freeze,\n    {\n        unsafe fn grow_buffer(&self) {\n            let old: &Buffer<K, V> = &*self.buf.load(Ordering::Acquire);\n            let new: *mut Buffer<K, V> = Buffer::alloc_buffer(old.len * 2);\n\n            // semantically \"move\" all (K, V) from old to new\n            for i in 0..old.len {\n                let src: *const (K, V) = &old.pairs[i] as _;\n                // get  a raw pointer to the (K,V) pair through a raw pointer\n                let dst: *mut (K, V) = &raw mut (*new.pairs[i]);\n                // (K, V) exists in old and new at the same time!\n                // readers can still access `old` and get shared references\n                // into it.\n                dst.write(src.read());\n            }\n\n            // after this swap *new* readers will see the same values that exist\n            // in `old` but at a different memory location (only shared references)\n            let _ = self.buf.swap(new, Ordering::Release);\n            // This will block until no reader that started before the atomic swap is\n            // accessing `old` any more, i.e., there can no longer be *any* shared\n            // references into `old`.\n            self.rcu.synchronize();\n            // ... since there are no longer any references, `old` can be freed.\n            // this call frees the buffer's memory without dropping any `(K, V)`.\n            Buffer::<K, V>::free(old as *mut Buffer<K, V>);\n        }\n    }\n\n\nI hope this pseudo code is maybe a little easier to follow than my initial description. I doubt this would compile but it's close enough to what the real code would look like.\n\nOf course, the actual code would be significantly more complex with lots of `UnsafeCell`s and `MaybeUninit`s sprinkled throughout.",
  "title": "Interior mutability and safety of ownership transfer in Rust"
}