1
//! Type-erased, reference-counted smart pointer with runtime borrow checking.
2
//!
3
//! # Safety
4
//!
5
//! This module provides `RefAny`, a type-erased container similar to `Arc<RefCell<dyn Any>>`,
6
//! but designed for FFI compatibility and cross-language interoperability.
7
//!
8
//! ## Memory Safety Guarantees
9
//!
10
//! 1. **Proper Alignment**: Fixed in commit addressing Miri UB - memory is allocated with correct
11
//!    alignment for the stored type using `Layout::from_size_align()`.
12
//!
13
//! 2. **Atomic Reference Counting**: All reference counts use `AtomicUsize` with `SeqCst` ordering,
14
//!    ensuring thread-safe access and preventing use-after-free.
15
//!
16
//! 3. **Runtime Type Safety**: Type IDs are checked before downcasting, preventing invalid pointer
17
//!    casts that would cause undefined behavior.
18
//!
19
//! 4. **Runtime Borrow Checking**: Shared and mutable borrows are tracked at runtime, enforcing
20
//!    Rust's borrowing rules dynamically (similar to `RefCell`).
21
//!
22
//! ## Thread Safety
23
//!
24
//! - `RefAny` is `Send`: Can be transferred between threads (data is heap-allocated)
25
//! - `RefAny` is `Sync`: Can be shared between threads (atomic operations + `&mut self` for
26
//!   borrows)
27
//!
28
//! The `SeqCst` (Sequentially Consistent) memory ordering provides the strongest guarantees:
29
//! all atomic operations appear in a single global order visible to all threads, preventing
30
//! race conditions where one thread doesn't see another's reference count updates.
31

            
32
use alloc::boxed::Box;
33
use alloc::string::String;
34
use core::{
35
    alloc::Layout,
36
    ffi::c_void,
37
    fmt,
38
    sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
39
};
40

            
41
use azul_css::AzString;
42

            
43
/// C-compatible destructor function type for RefAny.
44
/// Called when the last reference to a RefAny is dropped.
45
pub type RefAnyDestructorType = extern "C" fn(*mut c_void);
46

            
47
// NOTE: JSON serialization/deserialization callback types are defined in azul_layout::json
48
// The actual types are:
49
//   RefAnySerializeFnType = extern "C" fn(RefAny) -> Json
50
//   RefAnyDeserializeFnType = extern "C" fn(Json) -> ResultRefAnyString
51
// In azul_core, we only store function pointers as usize (0 = not set).
52

            
53
/// Internal reference counting metadata for `RefAny`.
54
///
55
/// This struct tracks:
56
///
57
/// - How many `RefAny` clones exist (`num_copies`)
58
/// - How many shared borrows are active (`num_refs`)
59
/// - How many mutable borrows are active (`num_mutable_refs`)
60
/// - Memory layout information for correct deallocation
61
/// - Type information for runtime type checking
62
///
63
/// # Thread Safety
64
///
65
/// All counters are `AtomicUsize` with `SeqCst` ordering, making them safe to access
66
/// from multiple threads simultaneously. The strong ordering ensures no thread can
67
/// observe inconsistent states (e.g., both seeing count=1 during final drop).
68
#[derive(Debug)]
69
#[repr(C)]
70
pub struct RefCountInner {
71
    /// Type-erased pointer to heap-allocated data.
72
    ///
73
    /// SAFETY: Must be properly aligned for the stored type (guaranteed by
74
    /// `Layout::from_size_align` in `new_c`). Never null for non-ZST types.
75
    ///
76
    /// This pointer is shared by all RefAny clones, so replace_contents
77
    /// updates are visible to all clones.
78
    pub _internal_ptr: *const c_void,
79

            
80
    /// Number of `RefAny` instances sharing the same data.
81
    /// When this reaches 0, the data is deallocated.
82
    pub num_copies: AtomicUsize,
83

            
84
    /// Number of active shared borrows (`Ref<T>`).
85
    /// While > 0, mutable borrows are forbidden.
86
    pub num_refs: AtomicUsize,
87

            
88
    /// Number of active mutable borrows (`RefMut<T>`).
89
    /// While > 0, all other borrows are forbidden.
90
    pub num_mutable_refs: AtomicUsize,
91

            
92
    /// Size of the stored type in bytes (from `size_of::<T>()`).
93
    pub _internal_len: usize,
94

            
95
    /// Layout size for deallocation (from `Layout::size()`).
96
    pub _internal_layout_size: usize,
97

            
98
    /// Required alignment for the stored type (from `align_of::<T>()`).
99
    /// CRITICAL: Must match the alignment used during allocation to prevent UB.
100
    pub _internal_layout_align: usize,
101

            
102
    /// Runtime type identifier computed from `TypeId::of::<T>()`.
103
    /// Used to prevent invalid downcasts.
104
    pub type_id: u64,
105

            
106
    /// Human-readable type name (e.g., "MyStruct") for debugging.
107
    pub type_name: AzString,
108

            
109
    /// Function pointer to correctly drop the type-erased data.
110
    /// SAFETY: Must be called with a pointer to data of the correct type.
111
    pub custom_destructor: extern "C" fn(*mut c_void),
112

            
113
    /// Function pointer to serialize RefAny to JSON (0 = not set).
114
    /// Cast to RefAnySerializeFnType (defined in azul_layout::json) when called.
115
    /// Type: extern "C" fn(RefAny) -> Json
116
    pub serialize_fn: usize,
117

            
118
    /// Function pointer to deserialize JSON to new RefAny (0 = not set).
119
    /// Cast to RefAnyDeserializeFnType (defined in azul_layout::json) when called.
120
    /// Type: extern "C" fn(Json) -> ResultRefAnyString
121
    pub deserialize_fn: usize,
122
}
123

            
124
/// Wrapper around a heap-allocated `RefCountInner`.
125
///
126
/// This is the shared metadata that all `RefAny` clones point to.
127
/// The `RefCount` is responsible for all memory management:
128
///
129
/// - `RefCount::clone()` increments `num_copies` in RefCountInner
130
/// - `RefCount::drop()` decrements `num_copies` and, if it reaches 0:
131
///   1. Frees the RefCountInner
132
///   2. Calls the custom destructor on the data
133
///   3. Deallocates the data memory
134
///
135
/// # Why `run_destructor: bool`
136
///
137
/// This flag tracks whether this `RefCount` instance should decrement
138
/// `num_copies` when dropped. Set to `true` for all clones (including
139
/// those created by `RefAny::clone()` and `AZ_REFLECT` macros).
140
/// Set to `false` after the decrement has been performed to prevent
141
/// double-decrement.
142
#[derive(Hash, PartialEq, PartialOrd, Ord, Eq)]
143
#[repr(C)]
144
pub struct RefCount {
145
    pub ptr: *const RefCountInner,
146
    pub run_destructor: bool,
147
}
148

            
149
impl fmt::Debug for RefCount {
150
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151
        self.downcast().fmt(f)
152
    }
153
}
154

            
155
impl Clone for RefCount {
156
    /// Clones the RefCount and increments the reference count.
157
    ///
158
    /// # Safety
159
    ///
160
    /// This is safe because:
161
    /// - The ptr is valid (created from Box::into_raw)
162
    /// - num_copies is atomically incremented with SeqCst ordering
163
    /// - This ensures the RefCountInner is not freed while clones exist
164
2207
    fn clone(&self) -> Self {
165
        // CRITICAL: Must increment num_copies so the RefCountInner is not freed
166
        // while this clone exists. The C macros (AZ_REFLECT) use AzRefCount_clone
167
        // to create Ref/RefMut guards, and those guards must keep the data alive.
168
2207
        if !self.ptr.is_null() {
169
2207
            unsafe {
170
2207
                (*self.ptr).num_copies.fetch_add(1, AtomicOrdering::SeqCst);
171
2207
            }
172
        }
173
2207
        Self {
174
2207
            ptr: self.ptr,
175
2207
            run_destructor: true,
176
2207
        }
177
2207
    }
178
}
179

            
180
impl Drop for RefCount {
181
    /// Decrements the reference count when a RefCount clone is dropped.
182
    ///
183
    /// If this was the last reference (num_copies reaches 0), this will also
184
    /// free the RefCountInner and call the custom destructor.
185
22175
    fn drop(&mut self) {
186
        // Only decrement if run_destructor is true (meaning this is a clone)
187
        // and the pointer is valid
188
22175
        if !self.run_destructor || self.ptr.is_null() {
189
            return;
190
22175
        }
191
22175
        self.run_destructor = false;
192

            
193
        // Atomically decrement and get the PREVIOUS value
194
22175
        let current_copies = unsafe {
195
22175
            (*self.ptr).num_copies.fetch_sub(1, AtomicOrdering::SeqCst)
196
        };
197

            
198
        // If previous value wasn't 1, other references still exist
199
22175
        if current_copies != 1 {
200
19026
            return;
201
3149
        }
202

            
203
        // We're the last reference! Clean up.
204
        // SAFETY: ptr came from Box::into_raw, and we're the last reference
205
3149
        let sharing_info = unsafe { Box::from_raw(self.ptr as *mut RefCountInner) };
206
3149
        let sharing_info = *sharing_info; // Box deallocates RefCountInner here
207

            
208
        // Get the data pointer
209
3149
        let data_ptr = sharing_info._internal_ptr;
210

            
211
        // Handle zero-sized types specially
212
3149
        if sharing_info._internal_len == 0
213
2767
            || sharing_info._internal_layout_size == 0
214
2767
            || data_ptr.is_null()
215
382
        {
216
382
            let mut _dummy: [u8; 0] = [];
217
382
            // Call destructor even for ZSTs (may have side effects)
218
382
            (sharing_info.custom_destructor)(_dummy.as_ptr() as *mut c_void);
219
382
        } else {
220
            // Reconstruct the layout used during allocation
221
2767
            let layout = unsafe {
222
2767
                Layout::from_size_align_unchecked(
223
2767
                    sharing_info._internal_layout_size,
224
2767
                    sharing_info._internal_layout_align,
225
                )
226
            };
227

            
228
            // Phase 1: Run the custom destructor
229
2767
            (sharing_info.custom_destructor)(data_ptr as *mut c_void);
230

            
231
            // Phase 2: Deallocate the memory
232
2767
            unsafe {
233
2767
                alloc::alloc::dealloc(data_ptr as *mut u8, layout);
234
2767
            }
235
        }
236
22175
    }
237
}
238

            
239
/// Debug-friendly snapshot of `RefCountInner` with non-atomic values.
240
#[derive(Debug, Clone)]
241
pub(crate) struct RefCountInnerDebug {
242
    pub(crate) num_copies: usize,
243
    pub(crate) num_refs: usize,
244
    pub(crate) num_mutable_refs: usize,
245
    pub(crate) _internal_len: usize,
246
    pub(crate) _internal_layout_size: usize,
247
    pub(crate) _internal_layout_align: usize,
248
    pub(crate) type_id: u64,
249
    pub(crate) type_name: AzString,
250
    pub(crate) custom_destructor: usize,
251
    /// Serialization function pointer (0 = not set)
252
    pub(crate) serialize_fn: usize,
253
    /// Deserialization function pointer (0 = not set)
254
    pub(crate) deserialize_fn: usize,
255
}
256

            
257
impl RefCount {
258
    /// Creates a new `RefCount` by boxing the metadata on the heap.
259
    ///
260
    /// # Safety
261
    ///
262
    /// Safe because we're creating a new allocation with `Box::new`,
263
    /// then immediately leaking it with `into_raw` to get a stable pointer.
264
3149
    fn new(ref_count: RefCountInner) -> Self {
265
3149
        RefCount {
266
3149
            ptr: Box::into_raw(Box::new(ref_count)),
267
3149
            run_destructor: true,
268
3149
        }
269
3149
    }
270

            
271
    /// Dereferences the raw pointer to access the metadata.
272
    ///
273
    /// # Safety
274
    ///
275
    /// Safe because:
276
    /// - The pointer is created from `Box::into_raw`, so it's valid and properly aligned
277
    /// - The lifetime is tied to `&self`, ensuring the pointer is still alive
278
    /// - Reference counting ensures the data isn't freed while references exist
279
28367
    fn downcast(&self) -> &RefCountInner {
280
28367
        if self.ptr.is_null() {
281
            panic!("[RefCount::downcast] FATAL: self.ptr is null!");
282
28367
        }
283
28367
        unsafe { &*self.ptr }
284
28367
    }
285

            
286
    /// Creates a debug snapshot of the current reference counts.
287
    ///
288
    /// Loads all atomic values with `SeqCst` ordering to get a consistent view.
289
    pub(crate) fn debug_get_refcount_copied(&self) -> RefCountInnerDebug {
290
        let dc = self.downcast();
291
        RefCountInnerDebug {
292
            num_copies: dc.num_copies.load(AtomicOrdering::SeqCst),
293
            num_refs: dc.num_refs.load(AtomicOrdering::SeqCst),
294
            num_mutable_refs: dc.num_mutable_refs.load(AtomicOrdering::SeqCst),
295
            _internal_len: dc._internal_len,
296
            _internal_layout_size: dc._internal_layout_size,
297
            _internal_layout_align: dc._internal_layout_align,
298
            type_id: dc.type_id,
299
            type_name: dc.type_name.clone(),
300
            custom_destructor: dc.custom_destructor as usize,
301
            serialize_fn: dc.serialize_fn,
302
            deserialize_fn: dc.deserialize_fn,
303
        }
304
    }
305

            
306
    /// Runtime check: can we create a shared borrow?
307
    ///
308
    /// Returns `true` if there are no active mutable borrows.
309
    /// Multiple shared borrows can coexist (like `&T` in Rust).
310
    ///
311
    /// # Memory Ordering
312
    ///
313
    /// Uses `SeqCst` to ensure we see the most recent state from all threads.
314
    /// If another thread just released a mutable borrow, we'll see it.
315
1469
    pub fn can_be_shared(&self) -> bool {
316
1469
        self.downcast()
317
1469
            .num_mutable_refs
318
1469
            .load(AtomicOrdering::SeqCst)
319
1469
            == 0
320
1469
    }
321

            
322
    /// Runtime check: can we create a mutable borrow?
323
    ///
324
    /// Returns `true` only if there are ZERO active borrows of any kind.
325
    /// This enforces Rust's exclusive mutability rule (like `&mut T`).
326
    ///
327
    /// # Memory Ordering
328
    ///
329
    /// Uses `SeqCst` to ensure we see all recent borrows from all threads.
330
    /// Both counters must be checked atomically to prevent races.
331
738
    pub fn can_be_shared_mut(&self) -> bool {
332
738
        let info = self.downcast();
333
738
        info.num_mutable_refs.load(AtomicOrdering::SeqCst) == 0
334
738
            && info.num_refs.load(AtomicOrdering::SeqCst) == 0
335
738
    }
336

            
337
    /// Increments the shared borrow counter.
338
    ///
339
    /// Called when a `Ref<T>` is created. The `Ref::drop` will decrement it.
340
    ///
341
    /// # Memory Ordering
342
    ///
343
    /// `SeqCst` ensures this increment is visible to all threads before they
344
    /// try to acquire a mutable borrow (which checks this counter).
345
1469
    pub fn increase_ref(&self) {
346
1469
        self.downcast()
347
1469
            .num_refs
348
1469
            .fetch_add(1, AtomicOrdering::SeqCst);
349
1469
    }
350

            
351
    /// Decrements the shared borrow counter.
352
    ///
353
    /// Called when a `Ref<T>` is dropped, indicating the borrow is released.
354
    ///
355
    /// # Memory Ordering
356
    ///
357
    /// `SeqCst` ensures this decrement is immediately visible to other threads
358
    /// waiting to acquire a mutable borrow.
359
1469
    pub fn decrease_ref(&self) {
360
1469
        self.downcast()
361
1469
            .num_refs
362
1469
            .fetch_sub(1, AtomicOrdering::SeqCst);
363
1469
    }
364

            
365
    /// Increments the mutable borrow counter.
366
    ///
367
    /// Called when a `RefMut<T>` is created. Should only succeed when this
368
    /// counter and `num_refs` are both 0.
369
    ///
370
    /// # Memory Ordering
371
    ///
372
    /// `SeqCst` ensures this increment is visible to all other threads,
373
    /// blocking them from acquiring any borrow (shared or mutable).
374
738
    pub fn increase_refmut(&self) {
375
738
        self.downcast()
376
738
            .num_mutable_refs
377
738
            .fetch_add(1, AtomicOrdering::SeqCst);
378
738
    }
379

            
380
    /// Decrements the mutable borrow counter.
381
    ///
382
    /// Called when a `RefMut<T>` is dropped, releasing exclusive access.
383
    ///
384
    /// # Memory Ordering
385
    ///
386
    /// `SeqCst` ensures this decrement is immediately visible, allowing
387
    /// other threads to acquire borrows.
388
738
    pub fn decrease_refmut(&self) {
389
738
        self.downcast()
390
738
            .num_mutable_refs
391
738
            .fetch_sub(1, AtomicOrdering::SeqCst);
392
738
    }
393
}
394

            
395
/// RAII guard for a shared borrow of type `T` from a `RefAny`.
396
///
397
/// Similar to `std::cell::Ref`, this automatically decrements the borrow
398
/// counter when dropped, ensuring borrows are properly released.
399
///
400
/// # Deref
401
///
402
/// Implements `Deref<Target = T>` so you can use it like `&T`.
403
#[derive(Debug)]
404
#[repr(C)]
405
pub struct Ref<'a, T> {
406
    ptr: &'a T,
407
    sharing_info: RefCount,
408
}
409

            
410
impl<'a, T> Drop for Ref<'a, T> {
411
    /// Automatically releases the shared borrow when the guard goes out of scope.
412
    ///
413
    /// # Safety
414
    ///
415
    /// Safe because `decrease_ref` uses atomic operations and is designed to be
416
    /// called exactly once per `Ref` instance.
417
649
    fn drop(&mut self) {
418
649
        self.sharing_info.decrease_ref();
419
649
    }
420
}
421

            
422
impl<'a, T> core::ops::Deref for Ref<'a, T> {
423
    type Target = T;
424

            
425
974
    fn deref(&self) -> &Self::Target {
426
974
        self.ptr
427
974
    }
428
}
429

            
430
/// RAII guard for a mutable borrow of type `T` from a `RefAny`.
431
///
432
/// Similar to `std::cell::RefMut`, this automatically decrements the mutable
433
/// borrow counter when dropped, releasing exclusive access.
434
///
435
/// # Deref / DerefMut
436
///
437
/// Implements both `Deref` and `DerefMut` so you can use it like `&mut T`.
438
#[derive(Debug)]
439
#[repr(C)]
440
pub struct RefMut<'a, T> {
441
    ptr: &'a mut T,
442
    sharing_info: RefCount,
443
}
444

            
445
impl<'a, T> Drop for RefMut<'a, T> {
446
    /// Automatically releases the mutable borrow when the guard goes out of scope.
447
    ///
448
    /// # Safety
449
    ///
450
    /// Safe because `decrease_refmut` uses atomic operations and is designed to be
451
    /// called exactly once per `RefMut` instance.
452
323
    fn drop(&mut self) {
453
323
        self.sharing_info.decrease_refmut();
454
323
    }
455
}
456

            
457
impl<'a, T> core::ops::Deref for RefMut<'a, T> {
458
    type Target = T;
459

            
460
2
    fn deref(&self) -> &Self::Target {
461
2
        &*self.ptr
462
2
    }
463
}
464

            
465
impl<'a, T> core::ops::DerefMut for RefMut<'a, T> {
466
6186
    fn deref_mut(&mut self) -> &mut Self::Target {
467
6186
        self.ptr
468
6186
    }
469
}
470

            
471
/// Type-erased, reference-counted smart pointer with runtime borrow checking.
472
///
473
/// `RefAny` is similar to `Arc<RefCell<dyn Any>>`, providing:
474
/// - Type erasure (stores any `'static` type)
475
/// - Reference counting (clones share the same data)
476
/// - Runtime borrow checking (enforces Rust's borrowing rules at runtime)
477
/// - FFI compatibility (`#[repr(C)]` and C-compatible API)
478
///
479
/// # Thread Safety
480
///
481
/// - `Send`: Can be moved between threads (heap-allocated data, atomic counters)
482
/// - `Sync`: Can be shared between threads (`downcast_ref/mut` require `&mut self`)
483
///
484
/// # Memory Safety
485
///
486
/// Fixed critical UB bugs in alignment, copy count, and pointer provenance.
487
/// All operations are verified with Miri to ensure absence of undefined behavior.
488
///
489
/// # Usage
490
///
491
/// ```rust
492
/// # use azul_core::refany::RefAny;
493
/// let data = RefAny::new(42i32);
494
/// let mut data_clone = data.clone(); // shares the same heap allocation
495
///
496
/// // Runtime-checked downcasting with type safety
497
/// if let Some(value_ref) = data_clone.downcast_ref::<i32>() {
498
///     assert_eq!(*value_ref, 42);
499
/// };
500
///
501
/// // Runtime-checked mutable borrowing
502
/// if let Some(mut value_mut) = data_clone.downcast_mut::<i32>() {
503
///     *value_mut = 100;
504
/// };
505
/// ```
506
#[derive(Debug, Hash, PartialEq, PartialOrd, Ord, Eq)]
507
#[repr(C)]
508
pub struct RefAny {
509
    /// Shared metadata: reference counts, type info, destructor, AND data pointer.
510
    ///
511
    /// All `RefAny` clones point to the same `RefCountInner` via this field.
512
    /// The data pointer is stored in RefCountInner so all clones see the same
513
    /// pointer, even after replace_contents() is called.
514
    ///
515
    /// The `run_destructor` flag on `RefCount` controls whether dropping this
516
    /// RefAny should decrement the reference count and potentially free memory.
517
    pub sharing_info: RefCount,
518

            
519
    /// Unique ID for this specific clone (root = 0, subsequent clones increment).
520
    ///
521
    /// Used to distinguish between the original and clones for debugging.
522
    pub instance_id: u64,
523
}
524

            
525
impl_option!(
526
    RefAny,
527
    OptionRefAny,
528
    copy = false,
529
    [Debug, Hash, Clone, PartialEq, PartialOrd, Ord, Eq]
530
);
531

            
532
// SAFETY: RefAny is Send because:
533
// - The data pointer points to heap memory (can be sent between threads)
534
// - All shared state (RefCountInner) uses atomic operations
535
// - No thread-local storage is used
536
unsafe impl Send for RefAny {}
537

            
538
// SAFETY: RefAny is Sync because:
539
// - Methods on `&RefAny` (like `clone`, `get_type_id`) only use atomic operations or
540
//   read immutable data, which is inherently thread-safe
541
// - The runtime borrow checker (via `can_be_shared/shared_mut`) uses SeqCst atomics
542
//
543
// KNOWN ISSUE: `downcast_ref/mut` require `&mut self`, but clones of the same RefAny
544
// are independent values that can each provide `&mut self` concurrently while sharing
545
// the same `RefCountInner`. The check-then-increment in downcast_ref/mut is not atomic,
546
// so concurrent borrows via different clones can race. See replace_contents() for the
547
// correct compare_exchange pattern.
548
unsafe impl Sync for RefAny {}
549

            
550
impl RefAny {
551
    /// Creates a new type-erased `RefAny` containing the given value.
552
    ///
553
    /// This is the primary way to construct a `RefAny` from Rust code.
554
    ///
555
    /// # Type Safety
556
    ///
557
    /// Stores the `TypeId` of `T` for runtime type checking during downcasts.
558
    ///
559
    /// # Memory Layout
560
    ///
561
    /// - Allocates memory on the heap with correct size (`size_of::<T>()`) and alignment
562
    ///   (`align_of::<T>()`)
563
    /// - Copies the value into the heap allocation
564
    /// - Forgets the original value to prevent double-drop
565
    ///
566
    /// # Custom Destructor
567
    ///
568
    /// Creates a type-specific destructor that:
569
    /// 1. Copies the data from heap back to stack
570
    /// 2. Calls `mem::drop` to run `T`'s destructor
571
    /// 3. The heap memory is freed separately in `RefAny::drop`
572
    ///
573
    /// This two-phase destruction ensures proper cleanup even for complex types.
574
    ///
575
    /// # Safety
576
    ///
577
    /// Safe because:
578
    /// - `mem::forget` prevents double-drop of the original value
579
    /// - Type `T` and destructor `<U>` are matched at compile time
580
    /// - `ptr::copy_nonoverlapping` with count=1 copies exactly one `T`
581
    ///
582
    /// # Example
583
    ///
584
    /// ```rust
585
    /// # use azul_core::refany::RefAny;
586
    /// let mut data = RefAny::new(42i32);
587
    /// let value = data.downcast_ref::<i32>().unwrap();
588
    /// assert_eq!(*value, 42);
589
    /// ```
590
1379
    pub fn new<T: 'static>(value: T) -> Self {
591
        /// Type-specific destructor that properly drops the inner value.
592
        ///
593
        /// # Safety
594
        ///
595
        /// Safe to call ONLY with a pointer that was created by `RefAny::new<U>`.
596
        /// The type `U` must match the original type `T`.
597
        ///
598
        /// # Why Copy to Stack?
599
        ///
600
        /// Rust's drop glue expects a value, not a pointer. We copy the data
601
        /// to the stack so `mem::drop` can run the destructor properly.
602
        ///
603
        /// # Critical Fix
604
        ///
605
        /// The third argument to `copy_nonoverlapping` is the COUNT (1 element),
606
        /// not the SIZE in bytes. Using `size_of::<U>()` here would copy
607
        /// `size_of::<U>()` elements, causing buffer overflow.
608
1379
        extern "C" fn default_custom_destructor<U: 'static>(ptr: *mut c_void) {
609
            use core::{mem, ptr};
610

            
611
1379
            unsafe {
612
1379
                // Allocate uninitialized stack space for one `U`
613
1379
                let mut stack_mem = mem::MaybeUninit::<U>::uninit();
614
1379

            
615
1379
                // Copy 1 element of type U from heap to stack
616
1379
                ptr::copy_nonoverlapping(
617
1379
                    ptr as *const U,
618
1379
                    stack_mem.as_mut_ptr(),
619
1379
                    1, // CRITICAL: This is element count, not byte count!
620
1379
                );
621
1379

            
622
1379
                // Take ownership and run the destructor
623
1379
                let stack_mem = stack_mem.assume_init();
624
1379
                mem::drop(stack_mem); // Runs U's Drop implementation
625
1379
            }
626
1379
        }
627

            
628
1379
        let type_name = ::core::any::type_name::<T>();
629
1379
        let type_id = Self::get_type_id_static::<T>();
630

            
631
1379
        let st = AzString::from_const_str(type_name);
632
1379
        let s = Self::new_c(
633
1379
            (&value as *const T) as *const c_void,
634
1379
            ::core::mem::size_of::<T>(),
635
1379
            ::core::mem::align_of::<T>(), // CRITICAL: Pass alignment to prevent UB
636
1379
            type_id,
637
1379
            st,
638
1379
            default_custom_destructor::<T>,
639
            0, // serialize_fn: not set for Rust types by default
640
            0, // deserialize_fn: not set for Rust types by default
641
        );
642
1379
        ::core::mem::forget(value); // Prevent double-drop
643
1379
        s
644
1379
    }
645

            
646
    /// C-ABI compatible function to create a `RefAny` from raw components.
647
    ///
648
    /// This is the low-level constructor used by FFI bindings (C, Python, etc.).
649
    ///
650
    /// # Parameters
651
    ///
652
    /// - `ptr`: Pointer to the value to store (will be copied)
653
    /// - `len`: Size of the value in bytes (`size_of::<T>()`)
654
    /// - `align`: Required alignment in bytes (`align_of::<T>()`)
655
    /// - `type_id`: Unique identifier for the type (for downcast safety)
656
    /// - `type_name`: Human-readable type name (for debugging)
657
    /// - `custom_destructor`: Function to call when the last reference is dropped
658
    /// - `serialize_fn`: Function pointer for JSON serialization (0 = not set)
659
    /// - `deserialize_fn`: Function pointer for JSON deserialization (0 = not set)
660
    ///
661
    /// # Safety
662
    ///
663
    /// Caller must ensure:
664
    /// - `ptr` points to valid data of size `len` with alignment `align`
665
    /// - `type_id` uniquely identifies the type
666
    /// - `custom_destructor` correctly drops the type at `ptr`
667
    /// - `len` and `align` match the actual type's layout
668
    /// - If `serialize_fn != 0`, it must be a valid function pointer of type
669
    ///   `extern "C" fn(RefAny) -> Json`
670
    /// - If `deserialize_fn != 0`, it must be a valid function pointer of type
671
    ///   `extern "C" fn(Json) -> ResultRefAnyString`
672
    ///
673
    /// # Zero-Sized Types
674
    ///
675
    /// Special case: ZSTs use a null pointer but still track the type info
676
    /// and call the destructor (which may have side effects even for ZSTs).
677
3149
    pub fn new_c(
678
3149
        // *const T
679
3149
        ptr: *const c_void,
680
3149
        // sizeof(T)
681
3149
        len: usize,
682
3149
        // alignof(T)
683
3149
        align: usize,
684
3149
        // unique ID of the type (used for type comparison when downcasting)
685
3149
        type_id: u64,
686
3149
        // name of the class such as "app::MyData", usually compiler- or macro-generated
687
3149
        type_name: AzString,
688
3149
        custom_destructor: extern "C" fn(*mut c_void),
689
3149
        // function pointer for JSON serialization (0 = not set)
690
3149
        serialize_fn: usize,
691
3149
        // function pointer for JSON deserialization (0 = not set)
692
3149
        deserialize_fn: usize,
693
3149
    ) -> Self {
694
        use core::ptr;
695

            
696
        // CRITICAL: Validate input pointer for non-ZST types
697
        // A NULL pointer for a non-zero-sized type would cause UB when copying
698
3149
        if len > 0 && ptr.is_null() {
699
            panic!(
700
                "RefAny::new_c: NULL pointer passed for non-ZST type (size={}). \
701
                This would cause undefined behavior. Type: {:?}",
702
                len,
703
                type_name.as_str()
704
            );
705
3149
        }
706

            
707
        // Special case: Zero-sized types
708
        //
709
        // Calling `alloc(Layout { size: 0, .. })` is UB, so we use a null pointer.
710
        // The destructor is still called (it may have side effects even for ZSTs).
711
3149
        let (_internal_ptr, layout) = if len == 0 {
712
382
            let _dummy: [u8; 0] = [];
713
382
            (ptr::null_mut(), Layout::for_value(&_dummy))
714
        } else {
715
            // CRITICAL FIX: Use the caller-provided alignment, not alignment of [u8]
716
            //
717
            // Previous bug: `Layout::for_value(&[u8])` created align=1
718
            // This caused unaligned references when downcasting to types like i32 (align=4)
719
            //
720
            // Fixed: `Layout::from_size_align(len, align)` respects the type's alignment
721
2767
            let layout = Layout::from_size_align(len, align).expect("Failed to create layout");
722

            
723
            // Allocate heap memory with correct alignment
724
2767
            let heap_struct_as_bytes = unsafe { alloc::alloc::alloc(layout) };
725

            
726
            // Handle allocation failure (aborts the program)
727
2767
            if heap_struct_as_bytes.is_null() {
728
                alloc::alloc::handle_alloc_error(layout);
729
2767
            }
730

            
731
            // Copy the data byte-by-byte to the heap
732
            // SAFETY: Both pointers are valid, non-overlapping, and properly aligned
733
2767
            unsafe { ptr::copy_nonoverlapping(ptr as *const u8, heap_struct_as_bytes, len) };
734

            
735
2767
            (heap_struct_as_bytes, layout)
736
        };
737

            
738
3149
        let ref_count_inner = RefCountInner {
739
3149
            _internal_ptr: _internal_ptr as *const c_void,
740
3149
            num_copies: AtomicUsize::new(1),       // This is the first instance
741
3149
            num_refs: AtomicUsize::new(0),         // No borrows yet
742
3149
            num_mutable_refs: AtomicUsize::new(0), // No mutable borrows yet
743
3149
            _internal_len: len,
744
3149
            _internal_layout_size: layout.size(),
745
3149
            _internal_layout_align: layout.align(),
746
3149
            type_id,
747
3149
            type_name,
748
3149
            custom_destructor,
749
3149
            serialize_fn,
750
3149
            deserialize_fn,
751
3149
        };
752

            
753
3149
        let sharing_info = RefCount::new(ref_count_inner);
754

            
755
3149
        Self {
756
3149
            sharing_info,
757
3149
            instance_id: 0, // Root instance
758
3149
        }
759
3149
    }
760

            
761
    /// Returns the raw data pointer for FFI downcasting.
762
    ///
763
    /// This is used by the AZ_REFLECT macros in C/C++ to access the
764
    /// type-erased data pointer for downcasting operations.
765
    ///
766
    /// # Safety
767
    ///
768
    /// The returned pointer must only be dereferenced after verifying
769
    /// the type ID matches the expected type. Callers are responsible
770
    /// for proper type safety checks.
771
38
    pub fn get_data_ptr(&self) -> *const c_void {
772
38
        self.sharing_info.downcast()._internal_ptr
773
38
    }
774

            
775
    /// Returns the byte length of the type-erased payload behind
776
    /// [`Self::get_data_ptr`] (`size_of::<T>()` of the stored type;
777
    /// `0` for ZSTs).
778
    pub fn get_data_len(&self) -> usize {
779
        self.sharing_info.downcast()._internal_len
780
    }
781

            
782
    /// Checks if this is the only `RefAny` instance with no active borrows.
783
    ///
784
    /// Returns `true` only if:
785
    /// - `num_copies == 1` (no clones exist)
786
    /// - `num_refs == 0` (no shared borrows active)
787
    /// - `num_mutable_refs == 0` (no mutable borrows active)
788
    ///
789
    /// Useful for checking if you have exclusive ownership.
790
    ///
791
    /// # Memory Ordering
792
    ///
793
    /// Uses `SeqCst` to ensure a consistent view across all three counters.
794
    pub(crate) fn has_no_copies(&self) -> bool {
795
        self.sharing_info
796
            .downcast()
797
            .num_copies
798
            .load(AtomicOrdering::SeqCst)
799
            == 1
800
            && self
801
                .sharing_info
802
                .downcast()
803
                .num_refs
804
                .load(AtomicOrdering::SeqCst)
805
                == 0
806
            && self
807
                .sharing_info
808
                .downcast()
809
                .num_mutable_refs
810
                .load(AtomicOrdering::SeqCst)
811
                == 0
812
    }
813

            
814
    /// Attempts to downcast to a shared reference of type `U`.
815
    ///
816
    /// Returns `None` if:
817
    /// - The stored type doesn't match `U` (type safety)
818
    /// - A mutable borrow is already active (borrow checking)
819
    /// - The pointer is null (ZST or uninitialized)
820
    ///
821
    /// # Type Safety
822
    ///
823
    /// Compares `type_id` at runtime before casting. This prevents casting
824
    /// `*const c_void` to the wrong type, which would be immediate UB.
825
    ///
826
    /// # Borrow Checking
827
    ///
828
    /// Checks `can_be_shared()` to enforce Rust's borrowing rules:
829
    /// - Multiple shared borrows are allowed
830
    /// - Shared and mutable borrows cannot coexist
831
    ///
832
    /// # Safety
833
    ///
834
    /// The `unsafe` cast is safe because:
835
    /// - Type ID check ensures `U` matches the stored type
836
    /// - Memory was allocated with correct alignment for `U`
837
    /// - Lifetime `'a` is tied to `&'a mut self`, preventing use-after-free
838
    /// - Reference count is incremented atomically before returning
839
    ///
840
    /// # Why `&mut self`?
841
    ///
842
    /// Requires `&mut self` to prevent multiple threads from calling this
843
    /// simultaneously on the same `RefAny`. The borrow checker enforces this.
844
    /// Clones of the `RefAny` can call this independently (they share data
845
    /// but have separate runtime borrow tracking).
846
    #[inline]
847
650
    pub fn downcast_ref<'a, U: 'static>(&'a mut self) -> Option<Ref<'a, U>> {
848
        // Runtime type check: prevent downcasting to wrong type
849
650
        let stored_type_id = self.get_type_id();
850
650
        let target_type_id = Self::get_type_id_static::<U>();
851
650
        let is_same_type = stored_type_id == target_type_id;
852

            
853
650
        if !is_same_type {
854
1
            return None;
855
649
        }
856

            
857
        // Runtime borrow check: ensure no mutable borrows exist
858
649
        let can_be_shared = self.sharing_info.can_be_shared();
859
649
        if !can_be_shared {
860
            return None;
861
649
        }
862

            
863
        // Get data pointer from shared RefCountInner
864
649
        let data_ptr = self.sharing_info.downcast()._internal_ptr;
865

            
866
        // Null check: ZSTs or uninitialized
867
649
        if data_ptr.is_null() {
868
            return None;
869
649
        }
870

            
871
        // Increment shared borrow count atomically
872
649
        self.sharing_info.increase_ref();
873

            
874
649
        Some(Ref {
875
649
            // SAFETY: Type check passed, pointer is non-null and properly aligned
876
649
            ptr: unsafe { &*(data_ptr as *const U) },
877
649
            sharing_info: self.sharing_info.clone(),
878
649
        })
879
650
    }
880

            
881
    /// Attempts to downcast to a mutable reference of type `U`.
882
    ///
883
    /// Returns `None` if:
884
    /// - The stored type doesn't match `U` (type safety)
885
    /// - Any borrow is already active (borrow checking)
886
    /// - The pointer is null (ZST or uninitialized)
887
    ///
888
    /// # Type Safety
889
    ///
890
    /// Compares `type_id` at runtime before casting, preventing UB.
891
    ///
892
    /// # Borrow Checking
893
    ///
894
    /// Checks `can_be_shared_mut()` to enforce exclusive mutability:
895
    /// - No other borrows (shared or mutable) can be active
896
    /// - This is Rust's `&mut T` rule, enforced at runtime
897
    ///
898
    /// # Safety
899
    ///
900
    /// The `unsafe` cast is safe because:
901
    ///
902
    /// - Type ID check ensures `U` matches the stored type
903
    /// - Memory was allocated with correct alignment for `U`
904
    /// - Borrow check ensures no other references exist
905
    /// - Lifetime `'a` is tied to `&'a mut self`, preventing aliasing
906
    /// - Mutable reference count is incremented atomically
907
    ///
908
    /// # Memory Ordering
909
    ///
910
    /// The `increase_refmut()` uses `SeqCst`, ensuring other threads see
911
    /// this mutable borrow before they try to acquire any borrow.
912
    #[inline]
913
324
    pub fn downcast_mut<'a, U: 'static>(&'a mut self) -> Option<RefMut<'a, U>> {
914
        // Runtime type check
915
324
        let is_same_type = self.get_type_id() == Self::get_type_id_static::<U>();
916
324
        if !is_same_type {
917
1
            return None;
918
323
        }
919

            
920
        // Runtime exclusive borrow check
921
323
        let can_be_shared_mut = self.sharing_info.can_be_shared_mut();
922
323
        if !can_be_shared_mut {
923
            return None;
924
323
        }
925

            
926
        // Get data pointer from shared RefCountInner
927
323
        let data_ptr = self.sharing_info.downcast()._internal_ptr;
928

            
929
        // Null check
930
323
        if data_ptr.is_null() {
931
            return None;
932
323
        }
933

            
934
        // Increment mutable borrow count atomically
935
323
        self.sharing_info.increase_refmut();
936

            
937
323
        Some(RefMut {
938
323
            // SAFETY: Type and borrow checks passed, exclusive access guaranteed
939
323
            ptr: unsafe { &mut *(data_ptr as *mut U) },
940
323
            sharing_info: self.sharing_info.clone(),
941
323
        })
942
324
    }
943

            
944
    /// Computes a runtime type ID from Rust's `TypeId`.
945
    ///
946
    /// Rust's `TypeId` is not `#[repr(C)]` and can't cross FFI boundaries.
947
    /// This function converts it to a `u64` by treating it as a byte array.
948
    ///
949
    /// # Safety
950
    ///
951
    /// Safe because:
952
    /// - `TypeId` is a valid type with a stable layout
953
    /// - We only read from it, never write
954
    /// - The slice lifetime is bounded by the function scope
955
    ///
956
    /// # Implementation
957
    ///
958
    /// Treats the `TypeId` as bytes and sums them with bit shifts to create
959
    /// a unique (but not cryptographically secure) hash.
960
    #[inline]
961
2353
    fn get_type_id_static<T: 'static>() -> u64 {
962
        use core::{any::TypeId, mem};
963

            
964
2353
        let t_id = TypeId::of::<T>();
965

            
966
        // SAFETY: TypeId is a valid type, we're only reading it
967
2353
        let struct_as_bytes = unsafe {
968
2353
            core::slice::from_raw_parts(
969
2353
                (&t_id as *const TypeId) as *const u8,
970
2353
                mem::size_of::<TypeId>(),
971
            )
972
        };
973

            
974
        // Convert first 8 bytes to u64 using proper bit positions
975
2353
        struct_as_bytes
976
2353
            .into_iter()
977
2353
            .enumerate()
978
2353
            .take(8) // Only use first 8 bytes (64 bits fit in u64)
979
18824
            .map(|(s_pos, s)| (*s as u64) << (s_pos * 8))
980
2353
            .sum()
981
2353
    }
982

            
983
    /// Checks if the stored type matches the given type ID.
984
76
    pub fn is_type(&self, type_id: u64) -> bool {
985
76
        self.sharing_info.downcast().type_id == type_id
986
76
    }
987

            
988
    /// Returns the stored type ID.
989
2606
    pub fn get_type_id(&self) -> u64 {
990
2606
        self.sharing_info.downcast().type_id
991
2606
    }
992

            
993
    /// Returns the human-readable type name for debugging.
994
    pub fn get_type_name(&self) -> AzString {
995
        self.sharing_info.downcast().type_name.clone()
996
    }
997

            
998
    /// Returns the current reference count (number of `RefAny` clones sharing this data).
999
    ///
    /// This is useful for debugging and metadata purposes.
    pub fn get_ref_count(&self) -> usize {
        self.sharing_info
            .downcast()
            .num_copies
            .load(AtomicOrdering::SeqCst)
    }
    /// Returns the serialize function pointer (0 = not set).
    /// 
    /// This is used for JSON serialization of RefAny contents.
    pub fn get_serialize_fn(&self) -> usize {
        self.sharing_info.downcast().serialize_fn
    }
    /// Returns the deserialize function pointer (0 = not set).
    /// 
    /// This is used for JSON deserialization to create a new RefAny.
    pub fn get_deserialize_fn(&self) -> usize {
        self.sharing_info.downcast().deserialize_fn
    }
    /// Sets the serialize function pointer.
    ///
    /// # Safety
    ///
    /// The caller must ensure the function pointer is valid and has the correct
    /// signature: `extern "C" fn(RefAny) -> Json`
    ///
    /// **Known issue:** `&mut self` is exclusive to this clone, not to the shared
    /// `RefCountInner`. Concurrent calls via different clones are a data race
    /// because `serialize_fn` is a plain `usize`, not atomic.
    pub fn set_serialize_fn(&mut self, serialize_fn: usize) {
        // FIXME: &mut self is exclusive to this clone only, not to the shared
        // RefCountInner — concurrent calls via different clones are a data race.
        let inner = self.sharing_info.ptr as *mut RefCountInner;
        unsafe {
            (*inner).serialize_fn = serialize_fn;
        }
    }
    /// Sets the deserialize function pointer.
    ///
    /// # Safety
    ///
    /// The caller must ensure the function pointer is valid and has the correct
    /// signature: `extern "C" fn(Json) -> ResultRefAnyString`
    ///
    /// **Known issue:** `&mut self` is exclusive to this clone, not to the shared
    /// `RefCountInner`. Concurrent calls via different clones are a data race
    /// because `deserialize_fn` is a plain `usize`, not atomic.
    pub fn set_deserialize_fn(&mut self, deserialize_fn: usize) {
        // FIXME: &mut self is exclusive to this clone only, not to the shared
        // RefCountInner — concurrent calls via different clones are a data race.
        let inner = self.sharing_info.ptr as *mut RefCountInner;
        unsafe {
            (*inner).deserialize_fn = deserialize_fn;
        }
    }
    /// Returns true if this RefAny supports JSON serialization.
    pub fn can_serialize(&self) -> bool {
        self.get_serialize_fn() != 0
    }
    /// Returns true if this RefAny type supports JSON deserialization.
    pub fn can_deserialize(&self) -> bool {
        self.get_deserialize_fn() != 0
    }
    /// Replaces the contents of this RefAny with a new value from another RefAny.
    ///
    /// This method:
    /// 1. Atomically acquires a mutable "lock" via compare_exchange
    /// 2. Calls the destructor on the old value
    /// 3. Deallocates the old memory
    /// 4. Copies the new value's memory
    /// 5. Updates metadata (type_id, type_name, destructor, serialize/deserialize fns)
    /// 6. Updates the shared _internal_ptr so ALL clones see the new data
    /// 7. Releases the lock
    ///
    /// Since all clones of a RefAny share the same `RefCountInner`, this change
    /// will be visible to ALL clones of this RefAny.
    ///
    /// # Returns
    ///
    /// - `true` if the replacement was successful
    /// - `false` if there are active borrows (would cause UB)
    ///
    /// # Thread Safety
    ///
    /// Uses compare_exchange to atomically acquire exclusive access, preventing
    /// any race condition between checking for borrows and modifying the data.
    ///
    /// # Safety
    ///
    /// Safe because:
    /// - We atomically acquire exclusive access before modifying
    /// - The old destructor is called before deallocation
    /// - Memory is properly allocated with correct alignment
    /// - All metadata is updated while holding the lock
    pub fn replace_contents(&mut self, new_value: RefAny) -> bool {
        use core::ptr;
        let inner = self.sharing_info.ptr as *mut RefCountInner;
        // Atomically acquire exclusive access by setting num_mutable_refs to 1.
        // This uses compare_exchange to ensure no race condition:
        // - If num_mutable_refs is 0, set it to 1 (success)
        // - If num_mutable_refs is not 0, someone else has it (fail)
        // We also need to check num_refs == 0 atomically.
        let inner_ref = self.sharing_info.downcast();
        // First, try to acquire the mutable lock
        let mutable_lock_result = inner_ref.num_mutable_refs.compare_exchange(
            0,  // expected: no mutable refs
            1,  // desired: we take the mutable ref
            AtomicOrdering::SeqCst,
            AtomicOrdering::SeqCst,
        );
        if mutable_lock_result.is_err() {
            // Someone else has a mutable reference
            return false;
        }
        // Now check that there are no shared references
        // Note: We hold the mutable lock, so no new shared refs can be acquired
        if inner_ref.num_refs.load(AtomicOrdering::SeqCst) != 0 {
            // Release the lock and fail
            inner_ref.num_mutable_refs.store(0, AtomicOrdering::SeqCst);
            return false;
        }
        // We now have exclusive access - perform the replacement
        unsafe {
            // Get old layout info before we overwrite it
            let old_ptr = (*inner)._internal_ptr;
            let old_len = (*inner)._internal_len;
            let old_layout_size = (*inner)._internal_layout_size;
            let old_layout_align = (*inner)._internal_layout_align;
            let old_destructor = (*inner).custom_destructor;
            // Step 1: Call destructor on old value (if non-ZST)
            if old_len > 0 && !old_ptr.is_null() {
                old_destructor(old_ptr as *mut c_void);
            }
            // Step 2: Deallocate old memory (if non-ZST)
            if old_layout_size > 0 && !old_ptr.is_null() {
                let old_layout = Layout::from_size_align_unchecked(old_layout_size, old_layout_align);
                alloc::alloc::dealloc(old_ptr as *mut u8, old_layout);
            }
            // Get new value's metadata
            let new_inner = new_value.sharing_info.downcast();
            let new_ptr = new_inner._internal_ptr;
            let new_len = new_inner._internal_len;
            let new_layout_size = new_inner._internal_layout_size;
            let new_layout_align = new_inner._internal_layout_align;
            // Step 3: Allocate new memory and copy data
            let allocated_ptr = if new_len == 0 {
                ptr::null_mut()
            } else {
                let new_layout = Layout::from_size_align(new_len, new_layout_align)
                    .expect("Failed to create layout");
                let heap_ptr = alloc::alloc::alloc(new_layout);
                if heap_ptr.is_null() {
                    alloc::alloc::handle_alloc_error(new_layout);
                }
                // Copy data from new_value
                ptr::copy_nonoverlapping(
                    new_ptr as *const u8,
                    heap_ptr,
                    new_len,
                );
                heap_ptr
            };
            // Step 4: Update the shared internal pointer in RefCountInner
            // All clones will see this new pointer!
            (*inner)._internal_ptr = allocated_ptr as *const c_void;
            // Step 5: Update metadata in RefCountInner
            (*inner)._internal_len = new_len;
            (*inner)._internal_layout_size = new_layout_size;
            (*inner)._internal_layout_align = new_layout_align;
            (*inner).type_id = new_inner.type_id;
            (*inner).type_name = new_inner.type_name.clone();
            (*inner).custom_destructor = new_inner.custom_destructor;
            (*inner).serialize_fn = new_inner.serialize_fn;
            (*inner).deserialize_fn = new_inner.deserialize_fn;
        }
        // Release the mutable lock
        self.sharing_info.downcast().num_mutable_refs.store(0, AtomicOrdering::SeqCst);
        // Prevent new_value from running its destructor (we copied the data)
        core::mem::forget(new_value);
        true
    }
}
impl Clone for RefAny {
    /// Creates a new `RefAny` sharing the same heap-allocated data.
    ///
    /// This is cheap (just increments a counter) and is how multiple parts
    /// of the code can hold references to the same data.
    ///
    /// # Reference Counting
    ///
    /// Atomically increments `num_copies` with `SeqCst` ordering before
    /// creating the clone. This ensures all threads see the updated count
    /// before the clone can be used.
    ///
    /// # Instance ID
    ///
    /// Each clone gets a unique `instance_id` based on the current copy count.
    /// The original has `instance_id=0`, the first clone gets `1`, etc.
    ///
    /// # Memory Ordering
    ///
    /// The `fetch_add` followed by `load` both use `SeqCst`:
    /// - `fetch_add`: Ensures the increment is visible to all threads
    /// - `load`: Gets the updated value for the instance_id
    ///
    /// This prevents race conditions where two threads clone simultaneously
    /// and both see the same instance_id.
    ///
    /// # Safety
    ///
    /// Safe because:
    ///
    /// - Atomic operations prevent data races
    /// - The heap allocation remains valid (only freed when count reaches 0)
    /// - `run_destructor` is set to `true` for all clones
16819
    fn clone(&self) -> Self {
        // Atomically increment the reference count
16819
        let inner = self.sharing_info.downcast();
16819
        let prev = inner.num_copies.fetch_add(1, AtomicOrdering::SeqCst);
16819
        let new_instance_id = (prev + 1) as u64;
16819
        Self {
16819
            // Data pointer is now in RefCountInner, shared automatically
16819
            sharing_info: RefCount {
16819
                ptr: self.sharing_info.ptr, // Share the same metadata (and data pointer)
16819
                run_destructor: true,       // This clone should decrement num_copies on drop
16819
            },
16819
            // Give this clone a unique ID based on the updated count
16819
            instance_id: new_instance_id,
16819
        }
16819
    }
}
impl Drop for RefAny {
    /// Empty drop implementation - all cleanup is handled by `RefCount::drop`.
    ///
    /// When a `RefAny` is dropped, its `sharing_info: RefCount` field is automatically
    /// dropped by Rust. The `RefCount::drop` implementation handles all cleanup:
    ///
    /// 1. Atomically decrements `num_copies` with `fetch_sub`
    /// 2. If the previous value was 1 (we're the last reference):
    ///    - Reclaims the `RefCountInner` via `Box::from_raw`
    ///    - Calls the custom destructor to run `T::drop()`
    ///    - Deallocates the heap memory with the stored layout
    ///
    /// # Why No Code Here?
    ///
    /// Previously, `RefAny::drop` handled cleanup, but this caused issues with the
    /// C API where `Ref<T>` and `RefMut<T>` guards (which clone the `RefCount`) need
    /// to keep the data alive even after the original `RefAny` is dropped.
    ///
    /// By moving all cleanup to `RefCount::drop`, we ensure that:
    /// - `RefAny::clone()` creates a `RefCount` with `run_destructor = true`
    /// - `AZ_REFLECT` macros create `Ref`/`RefMut` guards that clone `RefCount`
    /// - Each `RefCount` drop decrements the counter
    /// - Only the LAST drop (when `num_copies` was 1) cleans up memory
    ///
    /// See `RefCount::drop` for the full algorithm and safety documentation.
19968
    fn drop(&mut self) {
        // RefCount::drop handles everything automatically.
        // The sharing_info field is dropped by Rust, triggering RefCount::drop.
19968
    }
}