1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
//! 下書き
//!
//! ## Draft
//!
//! ### 生ポインタの使用
//!
//! 構造体 `Foo` と、それを参照する構造体 `FooRef<BorrowType>` を考える。
//! `BorrowType` は今後追加していくが、一旦 `Boxed<Foo>` のように振る舞う `marker::Owned`
//! と、`&'a Foo` のように振る舞う `marker::Immut<'a>` を考える。
//!
//! ```
//! use std::{marker::PhantomData, ptr::NonNull};
//!
//! struct Foo(u32);
//! struct FooRef<BorrowType> {
//! foo: NonNull<Foo>,
//! _marker: PhantomData<BorrowType>,
//! }
//!
//! mod marker {
//! use std::marker::PhantomData;
//!
//! pub enum Owned {}
//! pub struct Immut<'a>(PhantomData<&'a ()>);
//! }
//!
//! impl Foo {
//! pub fn new() -> Box<Self> { Box::new(Self(0)) }
//! }
//! impl FooRef<marker::Owned> {
//! pub fn new_ref() -> Self {
//! Self { foo: NonNull::from(Box::leak(Foo::new())), _marker: PhantomData }
//! }
//! }
//! impl<BorrowType> FooRef<BorrowType> {
//! pub fn borrow(&self) -> FooRef<marker::Immut<'_>> {
//! FooRef { foo: self.foo, _marker: PhantomData }
//! }
//! pub fn get(&self) -> &u32 { unsafe { &(*self.foo.as_ptr()).0 } }
//! }
//!
//! let foo_ref = FooRef::new_ref();
//! assert_eq!(*foo_ref.get(), 0);
//!
//! let foo_ref_immut = foo_ref.borrow();
//! assert_eq!(*foo_ref_immut.get(), 0);
//!
//! assert_eq!(*foo_ref.get(), 0);
//! assert_eq!(*foo_ref_immut.get(), 0);
//!
//! unsafe { drop(Box::from_raw(foo_ref.foo.as_ptr())) };
//! ```
//!
//! 当然、`Immut<'a>` だけでなく `Mut<'a>` も欲しい。
//! `drop` に関しては、`Boxed<Foo>` のように振る舞うところの `FooRef<marker::Owned>`
//! でのみ実装したいが、そういうことはできない ([E0366])。
//! ここでは、手動で呼び出すための `.drop()` を提供しつつ `Boxed<Foo>` のように振る舞う
//! `FooRef<marker::Dying>` を別途作ることにする。
//!
//! また、連想配列を実装することを見据えると、一部のメンバ変数についてのみ可変参照を公開したいこともある。
//! ここでは `struct Foo(u32, u32);` の `foo: Foo` に対して、`&foo.0` と `&mut foo.1`
//! を公開する `FooRef<marker::SndMut<'a>>` を作ることにする。
//! このとき、`&foo.0` にアクセスしても `&mut foo.1` が invalidate
//! されないように気をつける必要がある(逆も然り)。
//!
//! [E0366]: https://doc.rust-lang.org/error_codes/E0366.html
//!
//! 加えて、`marker::Mut<'a>` の lifetime を消して、一時的に静的解析の対象外にできる
//! `marker::DormantMut` も作っておく[^dormant]。もちろん、冒頭の例で触れたように
//! Stacked Borrows のルールには従う必要がある。
//!
//! [^dormant]: dormant や (re-)awaken という表現がしばしば使われている印象がある。
//!
//! 別の marker を返すようなメソッドにおいては、`FooRef { foo: self.foo, _marker: PhantomData }`
//! の boilerplate を都度書く必要があってややうれしくない。`PhantomData`
//! の型パラメータを陽に書く必要がないので、見かけ上は全く同じものになっている。
//! また、どの marker からどの marker への遷移をできるかを意識しておくとよいかもしれない。
//!
//! 他にも、`FooRef<marker::Immut<'a>>` は `Copy`/`Clone`
//! であるとか、諸々の変換などの実装が欲しくなるであろう。
//!
//! ### 参照の無効化
//!
//! さて、`marker::Mut<'a>` で `.get_mut()` のようなメソッドを公開するにあたり、
//! 無効な参照を返さないように気をつける必要がある。
//! 最初の例のように、下記のコードは未定義動作となる。
//!
//! ```
//! struct Foo(u32);
//! let mut foo = Foo(0);
//! ```
//!
//! ```ignore
//! # struct Foo(u32);
//! # let mut foo = Foo(0);
//! let foo_ptr_1: *mut _ = &mut foo;
//! let foo_ptr_2: *mut _ = &mut foo;
//! unsafe { (*foo_ptr_1).0 }; // UB
//! ```
//!
//! [`std::ptr`] には「`&mut foo` を `*mut _` にキャストするときは他の参照があってはいけない」とあり、
//! `foo_ptr_1` が生きている状態で `&mut foo` しているのが悪いように読める。Stacked Borrows
//! のルール的には、二つ目の `&mut foo` をした時点で `foo_ptr_1` が無効化されるので、
//! その後の参照が未定義動作になるという説明になると思われる。
//! 同じ可変参照から作ったポインタであれば問題ないようである。
//!
//! ```
//! # struct Foo(u32);
//! # let mut foo = Foo(0);
//! let mut foo_mut = &mut foo;
//! let foo_ptr_1: *mut _ = foo_mut;
//! let foo_ptr_2: *mut _ = foo_mut;
//! unsafe { (*foo_ptr_1).0 = 10 };
//! unsafe { (*foo_ptr_2).0 = 20 };
//! assert_eq!(foo.0, 20);
//! ```
//!
//! [`NonNull`][`std::ptr::NonNull`] を介して生ポインタを作っても、[`.as_mut()`][`std::ptr::NonNull::as_mut`]
//! を使って可変参照を作ってしまうとうまくいかない。
//!
//! ```ignore
//! use std::ptr::NonNull;
//!
//! # struct Foo(u32);
//! # let mut foo = Foo(0);
//! let mut foo_nonnull = NonNull::from(&mut foo);
//! let foo0_mut_1 = unsafe { &mut foo_nonnull.as_mut().0 };
//! let foo0_mut_2 = unsafe { &mut foo_nonnull.as_mut().0 };
//! *foo0_mut_1 = 10; // UB
//! ```
//!
//! ```ignore
//! use std::ptr::NonNull;
//!
//! # struct Foo(u32);
//! # let mut foo = Foo(0);
//! let mut foo_nonnull = NonNull::from(&mut foo);
//! let foo_mut_1 = unsafe { foo_nonnull.as_mut() };
//! let foo_mut_2 = unsafe { foo_nonnull.as_mut() };
//! foo_mut_1.0 = 10; // UB
//! ```
//!
//! 下記も同様。
//!
//! ```ignore
//! use std::ptr::NonNull;
//!
//! # struct Foo(u32);
//! # let mut foo = Foo(0);
//! let mut foo_nonnull = NonNull::from(&mut foo);
//! let foo0_mut_1 = unsafe { &mut (*foo_nonnull.as_ptr()).0 };
//! let foo0_mut_2 = unsafe { &mut (*foo_nonnull.as_ptr()).0 };
//! *foo0_mut_1 = 10; // UB
//! ```
//!
//! 今度は、メンバを複数持つような場合を考える。
//!
//! ```
//! struct Foo(u32, u32);
//! let mut foo = Foo(0, 0);
//! ```
//!
//! ```
//! # struct Foo(u32, u32);
//! # let mut foo = Foo(0, 0);
//! let foo0_mut = &mut foo.0;
//! let foo1_mut = &mut foo.1;
//! *foo0_mut = 10;
//! *foo1_mut = 20;
//! assert_eq!((foo.0, foo.1), (10, 20)); // ok
//! ```
//!
//! Safe Rust では上記のように書けるが、事情があって生ポインタを使う必要がある状況とする。
//!
//! ```
//! use std::ptr::NonNull;
//!
//! # struct Foo(u32, u32);
//! # let mut foo = Foo(0, 0);
//! let foo_nonnull = NonNull::from(&mut foo);
//! let foo0_mut = unsafe { &mut (*foo_nonnull.as_ptr()).0 };
//! let foo1_mut = unsafe { &mut (*foo_nonnull.as_ptr()).1 };
//! *foo0_mut = 10;
//! *foo1_mut = 20;
//! assert_eq!((foo.0, foo.1), (10, 20)); // ok
//! ```
//!
//! 下記のように [`std::ptr::NonNull::as_mut`] を使うと、アクセスしていない部分も無効化されるように見える。
//!
//! ```ignore
//! use std::ptr::NonNull;
//!
//! # struct Foo(u32, u32);
//! # let mut foo = Foo(0, 0);
//! let mut foo_nonnull = NonNull::from(&mut foo);
//! let foo0_mut = unsafe { &mut foo_nonnull.as_mut().0 };
//! let foo1_mut = unsafe { &mut foo_nonnull.as_mut().1 };
//! *foo0_mut = 10; // UB
//! ```
//!
//! [`std::ptr::NonNull::as_ptr`] を使うと無効化されない模様。
//!
//! ```
//! use std::ptr::{addr_of_mut, NonNull};
//!
//! # struct Foo(u32, u32);
//! # let mut foo = Foo(0, 0);
//! let mut foo_nonnull = NonNull::from(&mut foo);
//! let foo0_mut = unsafe { &mut *addr_of_mut!((*foo_nonnull.as_ptr()).0) };
//! let foo1_mut = unsafe { &mut *addr_of_mut!((*foo_nonnull.as_ptr()).1) };
//! *foo0_mut = 10;
//! *foo1_mut = 20;
//! assert_eq!((foo.0, foo.1), (10, 20)); // ok
//! ```
//!
//! [`std::ptr::addr_of_mut`] を使わなくても問題ない模様 (cf. [`&`/`&mut`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#borrow-operators), [`*`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-dereference-operator), [place expressions](https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions))。`addr_of_mut` は dereferenceability
//! を無視したいときに使うもので、無効化を防ぎたいときに使うものではない?
//!
//! ```
//! use std::ptr::{addr_of_mut, NonNull};
//!
//! # struct Foo(u32, u32);
//! # let mut foo = Foo(0, 0);
//! let mut foo_nonnull = NonNull::from(&mut foo);
//! let foo0_mut = unsafe { &mut (*foo_nonnull.as_ptr()).0 };
//! let foo1_mut = unsafe { &mut (*foo_nonnull.as_ptr()).1 };
//! *foo0_mut = 10;
//! *foo1_mut = 20;
//! assert_eq!((foo.0, foo.1), (10, 20)); // ok
//! ```
//!
//! ### 可変な参照を返す例
//!
//! 上記を踏まえ、`marker::Mut<'a>` などを含めた `FooRef<BorrowType>` を考える。
//!
//! | `BorrowType` | like ... |
//! |---|---|
//! | `marker::Owned` | `Boxed<Foo>` |
//! | `marker::Dying` | `Boxed<Foo>` (\*1) |
//! | `marker::Immut<'a>` | `&'a Foo` |
//! | `marker::Mut<'a>` | `&'a mut Foo` |
//! | `marker::SndMut<'a>` | `&'a mut Foo` (\*2) |
//!
//! (\*1): `drop` 相当のメソッドを提供する。
//! (\*2): `foo.0` (fst) に関しては不変参照、`foo.1` (snd) に関しては可変参照を公開する。
//!
//! ```ignore
//! use std::{marker::PhantomData, ptr::NonNull};
//!
//! struct Foo(u32, u32);
//! struct FooRef<BorrowType> {
//! foo: NonNull<Foo>,
//! _marker: PhantomData<BorrowType>,
//! }
//!
//! todo!();
//! ```
//!
//! TODO: 使い方の例として、テストめいたものを書く。
//!
//! ### 簡単な例
//!
//! TODO: 簡単な doubly-linked list めいたものを書く。
//!
//! ### それ以外
//!
//! TODO: variance を気にするべき例を書く。
//!
//! TODO: Stacked Borrows のルールを陽に書いた方がいい?
//!
//! ## References
//! - [The Rustonomicon](https://doc.rust-lang.org/nomicon/)
//! - [Learn Rust With Entirely Too Many Linked Lists](https://rust-unofficial.github.io/too-many-lists/)
//! - [`alloc::collections::btree::node`](https://doc.rust-lang.org/src/alloc/collections/btree/node.rs.html)
//! - [rust-lang / **unsafe-code-guidelines** :: /wip/**stacked-borrows.md**](https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md)
use std::{
marker::PhantomData,
ptr::{self, NonNull},
};
pub struct Foo {
key: u32,
val: u32,
}
pub struct FooRef<BorrowType> {
foo: NonNull<Foo>,
_marker: PhantomData<BorrowType>,
}
pub mod marker {
use std::marker::PhantomData;
pub enum Owned {}
pub enum Dying {}
pub enum DormantMut {}
pub struct Immut<'a>(PhantomData<&'a ()>);
pub struct Mut<'a>(PhantomData<&'a ()>);
pub struct ValMut<'a>(PhantomData<&'a ()>);
}
impl Foo {
pub fn new() -> Box<Self> { Box::new(Self { key: 0, val: 0 }) }
}
impl FooRef<marker::Owned> {
pub fn new_foo() -> Self {
Self {
foo: NonNull::from(Box::leak(Foo::new())),
_marker: PhantomData,
}
}
pub fn borrow_mut(&mut self) -> FooRef<marker::Mut<'_>> {
FooRef { foo: self.foo, _marker: PhantomData }
}
pub fn borrow_valmut(&mut self) -> FooRef<marker::ValMut<'_>> {
FooRef { foo: self.foo, _marker: PhantomData }
}
pub fn into_dying(self) -> FooRef<marker::Dying> {
FooRef { foo: self.foo, _marker: PhantomData }
}
}
impl<BorrowType> FooRef<BorrowType> {
pub fn reborrow(&self) -> FooRef<marker::Immut<'_>> {
FooRef { foo: self.foo, _marker: PhantomData }
}
fn as_ptr(this: &Self) -> *mut Foo { this.foo.as_ptr() }
}
impl Copy for FooRef<marker::Immut<'_>> {}
impl Clone for FooRef<marker::Immut<'_>> {
fn clone(&self) -> Self { *self }
}
impl<'a> FooRef<marker::Mut<'a>> {
pub unsafe fn reborrow_mut(&mut self) -> FooRef<marker::Mut<'_>> {
FooRef { foo: self.foo, _marker: PhantomData }
}
pub fn dormant(&self) -> FooRef<marker::DormantMut> {
FooRef { foo: self.foo, _marker: PhantomData }
}
fn as_mut(&mut self) -> &mut Foo {
let ptr = Self::as_ptr(self);
unsafe { &mut *ptr }
}
pub fn key_mut(&mut self) -> &mut u32 { &mut self.as_mut().key }
pub fn val_mut(&mut self) -> &mut u32 { &mut self.as_mut().val }
}
impl<'a> FooRef<marker::ValMut<'a>> {
pub fn into_key_valmut(mut self) -> (&'a u32, &'a mut u32) {
let ptr = Self::as_ptr(&mut self);
let key = unsafe { &*ptr::addr_of!((*ptr).key) };
let val = unsafe { &mut *ptr::addr_of_mut!((*ptr).val) };
(key, val)
}
}
impl FooRef<marker::DormantMut> {
pub unsafe fn awaken<'a>(self) -> FooRef<marker::Mut<'a>> {
FooRef { foo: self.foo, _marker: PhantomData }
}
}
impl FooRef<marker::Dying> {
pub fn drop(self) { unsafe { drop(Box::from_raw(Self::as_ptr(&self))) } }
}
#[test]
fn test_foo_ref() {
let mut foo_ref = FooRef::new_foo();
let mut foo_ref_mut_1 = foo_ref.borrow_mut();
let key_mut = foo_ref_mut_1.key_mut();
assert_eq!(*key_mut, 0);
*key_mut += 10;
assert_eq!(*key_mut, 10);
let val_mut = foo_ref_mut_1.val_mut();
assert_eq!(*val_mut, 0);
*val_mut += 100;
assert_eq!(*val_mut, 100);
let mut foo_ref_mut_2 = unsafe { foo_ref_mut_1.reborrow_mut() };
let key_mut = foo_ref_mut_2.key_mut();
assert_eq!(*key_mut, 10);
*key_mut += 10;
assert_eq!(*key_mut, 20);
let val_mut = foo_ref_mut_2.val_mut();
assert_eq!(*val_mut, 100);
*val_mut += 100;
assert_eq!(*val_mut, 200);
let foo_dormant = foo_ref_mut_2.dormant();
let foo_ref_kvm = foo_ref.borrow_valmut();
let (key, val) = foo_ref_kvm.into_key_valmut();
assert_eq!(*key, 20);
assert_eq!(*val, 200);
*val += 1;
assert_eq!(*key, 20);
assert_eq!(*val, 201);
let mut foo_ref_mut_3 = unsafe { foo_dormant.awaken() };
let key_mut = foo_ref_mut_3.key_mut();
assert_eq!(*key_mut, 20);
*key_mut += 10;
assert_eq!(*key_mut, 30);
let val_mut = foo_ref_mut_3.val_mut();
assert_eq!(*val_mut, 201);
*val_mut += 100;
assert_eq!(*val_mut, 301);
// *val += 1; // UB
foo_ref.into_dying().drop();
}
#[test]
fn ptr_read() {
struct Foo(u32, u32);
let mut foo = Foo(0, 0);
// {
// let foo_ptr_fst: *mut _ = &mut foo;
// let foo_ptr_snd: *mut _ = &mut foo;
// // unsafe { (*foo_ptr_fst).0 = 10 }; // UB
// }
// {
// let mut foo_nonnull = NonNull::from(&mut foo);
// let foo_mut_fst = unsafe { &mut foo_nonnull.as_mut().0 };
// let foo_mut_snd = unsafe { &mut foo_nonnull.as_mut().1 };
// *foo_mut_fst = 10; // UB
// }
{
let foo_nonnull = NonNull::from(&mut foo);
let foo_ptr_1 = foo_nonnull.as_ptr();
let foo_ptr_2 = foo_nonnull.as_ptr();
unsafe { (*foo_ptr_1).0 += 1 };
unsafe { (*foo_ptr_1).1 += 2 };
unsafe { (*foo_ptr_2).0 += 10 };
unsafe { (*foo_ptr_2).1 += 20 };
unsafe { (*foo_ptr_1).0 += 10 };
unsafe { (*foo_ptr_1).1 += 10 };
unsafe { (*foo_ptr_2).0 -= 10 };
unsafe { (*foo_ptr_2).1 -= 10 };
assert_eq!((foo.0, foo.1), (11, 22)); // ok
unsafe { (*foo_ptr_1).0 }; // ok
foo.0 += 100; // invalidates `foo_ptr_1` and `foo_nonnull`
// unsafe { (*foo_ptr_1).0 }; // UB
}
{
let foo_nonnull = NonNull::from(&mut foo);
let foo_ptr_1 = foo_nonnull.as_ptr();
unsafe { foo_ptr_1.read().0 };
let _ptr = NonNull::from(&mut foo); // invalidates them
// unsafe { foo_ptr_1.read().0 }; // UB
}
}