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
949
    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
949
        if !self.ptr.is_null() {
169
949
            unsafe {
170
949
                (*self.ptr).num_copies.fetch_add(1, AtomicOrdering::SeqCst);
171
949
            }
172
        }
173
949
        Self {
174
949
            ptr: self.ptr,
175
949
            run_destructor: true,
176
949
        }
177
949
    }
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
2636
    fn drop(&mut self) {
186
        // Only decrement if run_destructor is true (meaning this is a clone)
187
        // and the pointer is valid
188
2636
        if !self.run_destructor || self.ptr.is_null() {
189
            return;
190
2636
        }
191
2636
        self.run_destructor = false;
192

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

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

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

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

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

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

            
231
            // Phase 2: Deallocate the memory
232
1001
            unsafe {
233
1001
                alloc::alloc::dealloc(data_ptr as *mut u8, layout);
234
1001
            }
235
        }
236
2636
    }
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
1279
    fn new(ref_count: RefCountInner) -> Self {
265
1279
        RefCount {
266
1279
            ptr: Box::into_raw(Box::new(ref_count)),
267
1279
            run_destructor: true,
268
1279
        }
269
1279
    }
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
5612
    fn downcast(&self) -> &RefCountInner {
280
5612
        if self.ptr.is_null() {
281
            panic!("[RefCount::downcast] FATAL: self.ptr is null!");
282
5612
        }
283
5612
        unsafe { &*self.ptr }
284
5612
    }
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
661
    pub fn can_be_shared(&self) -> bool {
316
661
        self.downcast()
317
661
            .num_mutable_refs
318
661
            .load(AtomicOrdering::SeqCst)
319
661
            == 0
320
661
    }
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
288
    pub fn can_be_shared_mut(&self) -> bool {
332
288
        let info = self.downcast();
333
288
        info.num_mutable_refs.load(AtomicOrdering::SeqCst) == 0
334
288
            && info.num_refs.load(AtomicOrdering::SeqCst) == 0
335
288
    }
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
661
    pub fn increase_ref(&self) {
346
661
        self.downcast()
347
661
            .num_refs
348
661
            .fetch_add(1, AtomicOrdering::SeqCst);
349
661
    }
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
661
    pub fn decrease_ref(&self) {
360
661
        self.downcast()
361
661
            .num_refs
362
661
            .fetch_sub(1, AtomicOrdering::SeqCst);
363
661
    }
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
288
    pub fn increase_refmut(&self) {
375
288
        self.downcast()
376
288
            .num_mutable_refs
377
288
            .fetch_add(1, AtomicOrdering::SeqCst);
378
288
    }
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
288
    pub fn decrease_refmut(&self) {
389
288
        self.downcast()
390
288
            .num_mutable_refs
391
288
            .fetch_sub(1, AtomicOrdering::SeqCst);
392
288
    }
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
33
    fn drop(&mut self) {
418
33
        self.sharing_info.decrease_ref();
419
33
    }
420
}
421

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

            
425
50
    fn deref(&self) -> &Self::Target {
426
50
        self.ptr
427
50
    }
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
14
    fn drop(&mut self) {
453
14
        self.sharing_info.decrease_refmut();
454
14
    }
455
}
456

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

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

            
465
impl<'a, T> core::ops::DerefMut for RefMut<'a, T> {
466
25
    fn deref_mut(&mut self) -> &mut Self::Target {
467
25
        self.ptr
468
25
    }
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
56
    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
56
        extern "C" fn default_custom_destructor<U: 'static>(ptr: *mut c_void) {
609
            use core::{mem, ptr};
610

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

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

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

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

            
631
56
        let st = AzString::from_const_str(type_name);
632
56
        let s = Self::new_c(
633
56
            (&value as *const T) as *const c_void,
634
56
            ::core::mem::size_of::<T>(),
635
56
            ::core::mem::align_of::<T>(), // CRITICAL: Pass alignment to prevent UB
636
56
            type_id,
637
56
            st,
638
56
            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
56
        ::core::mem::forget(value); // Prevent double-drop
643
56
        s
644
56
    }
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
1279
    pub fn new_c(
678
1279
        // *const T
679
1279
        ptr: *const c_void,
680
1279
        // sizeof(T)
681
1279
        len: usize,
682
1279
        // alignof(T)
683
1279
        align: usize,
684
1279
        // unique ID of the type (used for type comparison when downcasting)
685
1279
        type_id: u64,
686
1279
        // name of the class such as "app::MyData", usually compiler- or macro-generated
687
1279
        type_name: AzString,
688
1279
        custom_destructor: extern "C" fn(*mut c_void),
689
1279
        // function pointer for JSON serialization (0 = not set)
690
1279
        serialize_fn: usize,
691
1279
        // function pointer for JSON deserialization (0 = not set)
692
1279
        deserialize_fn: usize,
693
1279
    ) -> 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
1279
        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
1279
        }
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
1279
        let (_internal_ptr, layout) = if len == 0 {
712
278
            let _dummy: [u8; 0] = [];
713
278
            (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
1001
            let layout = Layout::from_size_align(len, align).expect("Failed to create layout");
722

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

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

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

            
735
1001
            (heap_struct_as_bytes, layout)
736
        };
737

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

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

            
755
1279
        Self {
756
1279
            sharing_info,
757
1279
            instance_id: 0, // Root instance
758
1279
        }
759
1279
    }
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
34
    pub fn get_data_ptr(&self) -> *const c_void {
772
34
        self.sharing_info.downcast()._internal_ptr
773
34
    }
774

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

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

            
846
34
        if !is_same_type {
847
1
            return None;
848
33
        }
849

            
850
        // Runtime borrow check: ensure no mutable borrows exist
851
33
        let can_be_shared = self.sharing_info.can_be_shared();
852
33
        if !can_be_shared {
853
            return None;
854
33
        }
855

            
856
        // Get data pointer from shared RefCountInner
857
33
        let data_ptr = self.sharing_info.downcast()._internal_ptr;
858

            
859
        // Null check: ZSTs or uninitialized
860
33
        if data_ptr.is_null() {
861
            return None;
862
33
        }
863

            
864
        // Increment shared borrow count atomically
865
33
        self.sharing_info.increase_ref();
866

            
867
33
        Some(Ref {
868
33
            // SAFETY: Type check passed, pointer is non-null and properly aligned
869
33
            ptr: unsafe { &*(data_ptr as *const U) },
870
33
            sharing_info: self.sharing_info.clone(),
871
33
        })
872
34
    }
873

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

            
913
        // Runtime exclusive borrow check
914
14
        let can_be_shared_mut = self.sharing_info.can_be_shared_mut();
915
14
        if !can_be_shared_mut {
916
            return None;
917
14
        }
918

            
919
        // Get data pointer from shared RefCountInner
920
14
        let data_ptr = self.sharing_info.downcast()._internal_ptr;
921

            
922
        // Null check
923
14
        if data_ptr.is_null() {
924
            return None;
925
14
        }
926

            
927
        // Increment mutable borrow count atomically
928
14
        self.sharing_info.increase_refmut();
929

            
930
14
        Some(RefMut {
931
14
            // SAFETY: Type and borrow checks passed, exclusive access guaranteed
932
14
            ptr: unsafe { &mut *(data_ptr as *mut U) },
933
14
            sharing_info: self.sharing_info.clone(),
934
14
        })
935
15
    }
936

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

            
957
105
        let t_id = TypeId::of::<T>();
958

            
959
        // SAFETY: TypeId is a valid type, we're only reading it
960
105
        let struct_as_bytes = unsafe {
961
105
            core::slice::from_raw_parts(
962
105
                (&t_id as *const TypeId) as *const u8,
963
105
                mem::size_of::<TypeId>(),
964
            )
965
        };
966

            
967
        // Convert first 8 bytes to u64 using proper bit positions
968
105
        struct_as_bytes
969
105
            .into_iter()
970
105
            .enumerate()
971
105
            .take(8) // Only use first 8 bytes (64 bits fit in u64)
972
840
            .map(|(s_pos, s)| (*s as u64) << (s_pos * 8))
973
105
            .sum()
974
105
    }
975

            
976
    /// Checks if the stored type matches the given type ID.
977
68
    pub fn is_type(&self, type_id: u64) -> bool {
978
68
        self.sharing_info.downcast().type_id == type_id
979
68
    }
980

            
981
    /// Returns the stored type ID.
982
1306
    pub fn get_type_id(&self) -> u64 {
983
1306
        self.sharing_info.downcast().type_id
984
1306
    }
985

            
986
    /// Returns the human-readable type name for debugging.
987
    pub fn get_type_name(&self) -> AzString {
988
        self.sharing_info.downcast().type_name.clone()
989
    }
990

            
991
    /// Returns the current reference count (number of `RefAny` clones sharing this data).
992
    ///
993
    /// This is useful for debugging and metadata purposes.
994
    pub fn get_ref_count(&self) -> usize {
995
        self.sharing_info
996
            .downcast()
997
            .num_copies
998
            .load(AtomicOrdering::SeqCst)
999
    }
    /// 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
408
    fn clone(&self) -> Self {
        // Atomically increment the reference count
408
        let inner = self.sharing_info.downcast();
408
        let prev = inner.num_copies.fetch_add(1, AtomicOrdering::SeqCst);
408
        let new_instance_id = (prev + 1) as u64;
408
        Self {
408
            // Data pointer is now in RefCountInner, shared automatically
408
            sharing_info: RefCount {
408
                ptr: self.sharing_info.ptr, // Share the same metadata (and data pointer)
408
                run_destructor: true,       // This clone should decrement num_copies on drop
408
            },
408
            // Give this clone a unique ID based on the updated count
408
            instance_id: new_instance_id,
408
        }
408
    }
}
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.
1687
    fn drop(&mut self) {
        // RefCount::drop handles everything automatically.
        // The sharing_info field is dropped by Rust, triggering RefCount::drop.
1687
    }
}