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
//! Shared (reference-counted) pointers.
//!
//! Per `docs/PORTING.md` §Pointers, the Rust port maps `bun.ptr.Shared(*T)` →
//! `std::rc::Rc<T>` and `bun.ptr.AtomicShared(*T)` → `std::sync::Arc<T>` directly,
//! and explicitly forbids introducing a custom `bun_ptr::Shared<T>` to shave the
//! weak-count header word ("4 uses tree-wide, 8 bytes per allocation is negligible,
//! and you lose `Rc::downgrade`/`make_mut`/`get_mut`").
//!
//! This module therefore re-exports `Rc`/`Arc`/`Weak` under the Zig names so that
//! mechanical `bun_ptr::shared::*` references resolve, and documents the 1:1 method
//! mapping for reviewers diffing against `src/ptr/shared.zig`.
use Rc;
// ───────────────────────────────────────────────────────────────────────────────
// Options
// ───────────────────────────────────────────────────────────────────────────────
/// Options for `WithOptions`.
///
/// In the Rust port these collapse to the std `Rc`/`Arc` knobs:
///
/// * `Allocator` — std `Rc`/`Arc` always use the global allocator (mimalloc via
/// `#[global_allocator]`). `Rc::new_in`/`Arc::new_in` are nightly-only
/// (`feature(allocator_api)`); see `// TODO(port)` on `SharedIn` below.
/// * `atomic` — picks `Rc` vs `Arc`.
/// * `allow_weak` — `Rc`/`Arc` always carry a weak count, so this is always
/// effectively `true`. The Zig flag existed only to save 4 bytes when weak
/// pointers were not needed.
/// * `deinit` — `Rc`/`Arc` always run `Drop` on the inner `T`. To suppress
/// `Drop`, wrap the payload in `ManuallyDrop<T>` at the call site.
//
// TODO(port): this struct is kept only as documentation of the Zig surface; no
// Rust code should construct it. Remove once all `WithOptions` call sites are
// migrated to plain `Rc<T>`/`Arc<T>`.
// ───────────────────────────────────────────────────────────────────────────────
// Shared / AtomicShared
// ───────────────────────────────────────────────────────────────────────────────
/// `Option<Rc<T>>` is one word).
///
/// This type is not thread-safe: all pointers to the same piece of data must live on the same
/// thread. See `AtomicShared` for a thread-safe version.
///
/// ## Method map (Zig → Rust)
///
/// | Zig | Rust |
/// |-----------------------------|-----------------------------------------------|
/// | `Shared(*T).alloc(v)` | `Rc::new(v)` (infallible; aborts on OOM) |
/// | `Shared(*T).allocIn(v, a)` | — (allocator_api unstable; `// TODO(port)`) |
/// | `Shared(*T).new(v)` | `Rc::new(v)` |
/// | `s.get()` | `&*s` / `Rc::as_ptr(&s)` |
/// | `s.clone()` | `Rc::clone(&s)` |
/// | `s.cloneWeak()` | `Rc::downgrade(&s)` |
/// | `s.deinit()` | `drop(s)` (implicit at scope exit) |
/// | `Shared(?*T).initNull()` | `None::<Rc<T>>` |
/// | `s.take()` | `Option::take` on `Option<Rc<T>>` |
/// | `s.toOptional()` | `Some(s)` |
/// | `s.strongCount()` | `Rc::strong_count(&s)` |
/// | `s.weakCount()` | `Rc::weak_count(&s)` |
/// | `s.leak()` | `Rc::into_raw(s)` |
/// | `Self.adoptRawUnsafe(p)` | `unsafe { Rc::from_raw(p) }` |
/// | `Self.cloneFromRawUnsafe(p)`| `unsafe { Rc::increment_strong_count(p); Rc::from_raw(p) }` |
///
// PERF(port): Rc weak-count header — profile if hot (PORTING.md §Pointers).
pub type Shared<T> = ;
/// A shared pointer allocated using a specific type of allocator.
///
/// The requirements for `Allocator` are the same as `bun.ptr.OwnedIn`.
/// `Allocator` may be `std.mem.Allocator` to allow any kind of allocator.
//
/// A thread-safe shared pointer allocated using a specific type of allocator.
//
/// Like `Shared`, but takes explicit options.
//
// ───────────────────────────────────────────────────────────────────────────────
// Weak
// ───────────────────────────────────────────────────────────────────────────────
/// A weak pointer.
///
/// Weak pointers must be upgraded to strong pointers before the shared data can be
/// accessed. This upgrading can fail if no shared pointers exist anymore, as the shared
/// data will have been deinitialized in that case.
///
/// ## Method map (Zig → Rust)
///
/// | Zig | Rust |
/// |----------------------|---------------------------------------|
/// | `w.upgrade()` | `w.upgrade()` (→ `Option<Rc<T>>`) |
/// | `w.clone()` | `w.clone()` |
/// | `w.deinit()` | `drop(w)` |
/// | `Weak.initNull()` | `Weak::new()` (dangling) or `None` |
/// | `w.isNull()` | `Option::is_none` / `w.ptr_eq(&Weak::new())` |
/// | `w.strongCount()` | `w.strong_count()` |
/// | `w.weakCount()` | `w.weak_count()` |
pub type Weak<T> = Weak;
// ───────────────────────────────────────────────────────────────────────────────
// FullData / NonAtomicCount / AtomicCount
// ───────────────────────────────────────────────────────────────────────────────
//
// The Zig `FullData` struct (value + strong_count + weak_count + allocator +
// thread_lock) is the moral equivalent of `RcInner<T>` / `ArcInner<T>` in std,
// which are private implementation details. We do not re-implement them.
//
// `NonAtomicCount` ↔ `Cell<usize>` inside `RcInner`.
// `AtomicCount` ↔ `AtomicUsize` inside `ArcInner` (with the same
// `.monotonic` increment / `.acq_rel` decrement ordering and
// the same CAS-loop `try_increment` for `Weak::upgrade`).
//
// The `thread_lock: bun.safety.ThreadLock` debug-assertion that a non-atomic
// `Shared` is only touched from one thread is enforced statically in Rust by
// `Rc<T>: !Send + !Sync`.
//
// The `fromValuePtr` (`@fieldParentPtr("value", ptr)`) recovery is provided by
// `Rc::from_raw` / `Arc::from_raw`, which subtract the header offset internally.
//
// TODO(port): if profiling shows the std weak-count word is measurable in a
// hot array, revisit with a `#[repr(C)]` hand-rolled inner — but per
// PORTING.md this is explicitly deprioritized.
// `RawCount` was `u32` in Zig; std uses `usize`. The overflow assertion
// (`old != maxInt(RawCount)`) is replaced by std's own abort-on-overflow check
// in `Arc::clone` (it aborts if the count would exceed `isize::MAX`).
// `parsePointer` (Zig comptime reflection over `*T` / `?*T`) has no Rust
// analogue and is not needed: optionality is expressed at the use site as
// `Option<Rc<T>>`, and slices/const are rejected by the type system rather than
// a comptime check.
// ported from: src/ptr/shared.zig