shared_container/
lib.rs

1//! # Shared Container - Type-Safe Shared Data Access
2//!
3//! This library provides type-safe abstractions for shared data access across
4//! different runtime environments: synchronous multi-threaded, asynchronous (tokio),
5//! and single-threaded (WebAssembly).
6//!
7//! ## Quick Start
8//!
9//! ### Synchronous Usage
10//!
11//! ```rust
12//! use shared_container::{Shared, SyncAccess};
13//!
14//! let container = Shared::new(42);
15//!
16//! // Read access
17//! let guard = container.read().unwrap();
18//! assert_eq!(*guard, 42);
19//! drop(guard);
20//!
21//! // Write access
22//! let mut guard = container.write().unwrap();
23//! *guard = 100;
24//! ```
25//!
26//! ### Asynchronous Usage (with `async` feature)
27//!
28//! ```rust
29//! # #[cfg(feature = "async")]
30//! # async fn example() {
31//! use shared_container::{AsyncShared, AsyncAccess};
32//!
33//! let container = AsyncShared::new(42);
34//!
35//! // Async read access
36//! let guard = container.read_async().await;
37//! assert_eq!(*guard, 42);
38//! drop(guard);
39//!
40//! // Async write access
41//! let mut guard = container.write_async().await;
42//! *guard = 100;
43//! # }
44//! ```
45//!
46//! ## Key Features
47//!
48//! - **Type-Level Separation**: `Shared<T>` for sync, `AsyncShared<T>` for async
49//! - **Platform-Aware**: Automatically uses the right backend based on target
50//!   - Native: `Arc<RwLock<T>>`
51//!   - WebAssembly: `Rc<RefCell<T>>`
52//!   - Async: `Arc<tokio::sync::RwLock<T>>`
53//! - **Explicit Errors**: `Result<_, AccessError>` instead of `Option` or panics
54//! - **Zero Runtime Overhead**: No blocking operations or runtime initialization
55//!
56//! ## Feature Flags
57//!
58//! - **`async`**: Enables `AsyncShared<T>` and async trait methods (requires tokio)
59//! - **`std-sync`** (default): Legacy support for `SharedContainer` with std sync primitives
60//! - **`tokio-sync`**: Legacy support for `SharedContainer` with tokio primitives
61//! - **`wasm-sync`**: Legacy support for forcing WebAssembly backend
62//!
63//! ## Migration from 2.x
64//!
65//! The old `SharedContainer<T>` API is deprecated. Migrate to the new type-safe API:
66//!
67//! | Old (2.x) | New (0.3) |
68//! |-----------|-----------|
69//! | `SharedContainer::new(v)` (std-sync) | `Shared::new(v)` |
70//! | `SharedContainer::new(v)` (tokio-sync) | `AsyncShared::new(v)` |
71//! | `container.read()` → `Option<_>` | `container.read()` → `Result<_, AccessError>` |
72//! | `container.read_async().await` | `container.read_async().await` |
73//!
74//! ## Error Handling
75//!
76//! The new API uses `AccessError` enum for explicit error handling:
77//!
78//! ```rust
79//! use shared_container::{Shared, SyncAccess, AccessError};
80//!
81//! let container = Shared::new(42);
82//! match container.read() {
83//!     Ok(guard) => println!("Value: {}", *guard),
84//!     Err(AccessError::Poisoned) => println!("Lock was poisoned"),
85//!     Err(AccessError::BorrowConflict) => println!("Already borrowed"),
86//!     Err(AccessError::UnsupportedMode) => println!("Wrong container type"),
87//! }
88//! ```
89
90#![cfg_attr(docsrs, feature(doc_cfg))]
91
92use std::ops::{Deref, DerefMut};
93
94// Standard library synchronization primitives (default)
95#[cfg(all(
96    feature = "std-sync",
97    not(feature = "tokio-sync"),
98    not(feature = "wasm-sync")
99))]
100use std::sync::{Arc, RwLock, Weak};
101
102// Tokio async synchronization primitives
103#[cfg(feature = "tokio-sync")]
104use std::sync::{Arc, Weak};
105#[cfg(feature = "tokio-sync")]
106use tokio::sync::RwLock;
107
108// WebAssembly/single-threaded synchronization primitives
109#[cfg(any(
110    feature = "wasm-sync",
111    all(
112        target_arch = "wasm32",
113        not(feature = "std-sync"),
114        not(feature = "tokio-sync")
115    )
116))]
117use std::cell::{Ref, RefCell, RefMut};
118#[cfg(any(
119    feature = "wasm-sync",
120    all(
121        target_arch = "wasm32",
122        not(feature = "std-sync"),
123        not(feature = "tokio-sync")
124    )
125))]
126use std::rc::{Rc, Weak as RcWeak};
127
128/// A unified container for shared data that works in both multi-threaded and single-threaded environments.
129///
130/// **DEPRECATED**: Use [`Shared<T>`](crate::Shared) for synchronous code or
131/// `AsyncShared<T>` (with `async` feature) for asynchronous code instead.
132///
133/// This struct provides an abstraction over different container types:
134/// - `Arc<std::sync::RwLock<T>>` (used in standard multi-threaded environments)
135/// - `Arc<tokio::sync::RwLock<T>>` (used for async/await support)
136/// - `Rc<RefCell<T>>` (used in single-threaded environments like WebAssembly)
137///
138/// ## Migration Guide
139///
140/// ```rust
141/// // Old (2.x with std-sync)
142/// // use shared_container::SharedContainer;
143/// // let container = SharedContainer::new(42);
144///
145/// // New (0.3)
146/// use shared_container::{Shared, SyncAccess};
147/// let container = Shared::new(42);
148/// ```
149///
150/// For async code with tokio:
151/// ```rust
152/// # #[cfg(feature = "async")]
153/// # async fn example() {
154/// // Old (2.x with tokio-sync)
155/// // use shared_container::SharedContainer;
156/// // let container = SharedContainer::new(42);
157///
158/// // New (0.3)
159/// use shared_container::{AsyncShared, AsyncAccess};
160/// let container = AsyncShared::new(42);
161/// # }
162/// ```
163#[deprecated(
164    since = "0.3.0",
165    note = "Use `Shared<T>` for sync or `AsyncShared<T>` for async instead. See migration guide in docs."
166)]
167#[derive(Debug)]
168pub struct SharedContainer<T> {
169    // Standard library thread-safe implementation
170    #[cfg(all(
171        feature = "std-sync",
172        not(feature = "tokio-sync"),
173        not(feature = "wasm-sync")
174    ))]
175    std_inner: Arc<RwLock<T>>,
176
177    // Tokio async implementation
178    #[cfg(feature = "tokio-sync")]
179    tokio_inner: Arc<RwLock<T>>,
180
181    // Single-threaded implementation for WebAssembly
182    #[cfg(any(
183        feature = "wasm-sync",
184        all(
185            target_arch = "wasm32",
186            not(feature = "std-sync"),
187            not(feature = "tokio-sync")
188        )
189    ))]
190    wasm_inner: Rc<RefCell<T>>,
191}
192
193// Implement Send and Sync for SharedContainer only for thread-safe implementations
194#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
195unsafe impl<T: Send> Send for SharedContainer<T> {}
196
197#[cfg(any(feature = "std-sync", feature = "tokio-sync"))]
198unsafe impl<T: Send + Sync> Sync for SharedContainer<T> {}
199
200/// A weak reference to a `SharedContainer`.
201///
202/// **DEPRECATED**: Use [`WeakShared<T>`](crate::WeakShared) for synchronous code or
203/// `WeakAsyncShared<T>` (with `async` feature) for asynchronous code instead.
204///
205/// This struct provides an abstraction over different weak reference types:
206/// - `Weak<std::sync::RwLock<T>>` (used in standard multi-threaded environments)
207/// - `Weak<tokio::sync::RwLock<T>>` (used for async/await support)
208/// - `Weak<RefCell<T>>` (used in single-threaded environments like WebAssembly)
209///
210/// Weak references don't prevent the value from being dropped when no strong references
211/// remain. This helps break reference cycles that could cause memory leaks.
212#[deprecated(
213    since = "0.3.0",
214    note = "Use `WeakShared<T>` for sync or `WeakAsyncShared<T>` for async instead."
215)]
216#[derive(Debug)]
217pub struct WeakSharedContainer<T> {
218    // Standard library thread-safe implementation
219    #[cfg(all(
220        feature = "std-sync",
221        not(feature = "tokio-sync"),
222        not(feature = "wasm-sync")
223    ))]
224    std_inner: Weak<RwLock<T>>,
225
226    // Tokio async implementation
227    #[cfg(feature = "tokio-sync")]
228    tokio_inner: Weak<RwLock<T>>,
229
230    // Single-threaded implementation for WebAssembly
231    #[cfg(any(
232        feature = "wasm-sync",
233        all(
234            target_arch = "wasm32",
235            not(feature = "std-sync"),
236            not(feature = "tokio-sync")
237        )
238    ))]
239    wasm_inner: RcWeak<RefCell<T>>,
240}
241
242impl<T> Clone for WeakSharedContainer<T> {
243    fn clone(&self) -> Self {
244        // Different implementations for different platforms
245        #[cfg(all(
246            feature = "std-sync",
247            not(feature = "tokio-sync"),
248            not(feature = "wasm-sync")
249        ))]
250        {
251            WeakSharedContainer {
252                std_inner: self.std_inner.clone(),
253            }
254        }
255
256        #[cfg(feature = "tokio-sync")]
257        {
258            WeakSharedContainer {
259                tokio_inner: self.tokio_inner.clone(),
260            }
261        }
262
263        #[cfg(any(
264            feature = "wasm-sync",
265            all(
266                target_arch = "wasm32",
267                not(feature = "std-sync"),
268                not(feature = "tokio-sync")
269            )
270        ))]
271        {
272            WeakSharedContainer {
273                wasm_inner: self.wasm_inner.clone(),
274            }
275        }
276    }
277}
278
279impl<T: PartialEq> PartialEq for SharedContainer<T> {
280    fn eq(&self, _other: &Self) -> bool {
281        #[cfg(feature = "tokio-sync")]
282        {
283            // Note: PartialEq is not supported with tokio-sync feature
284            // as it would require blocking operations in a sync context.
285            // Consider comparing values manually using async methods.
286            false
287        }
288
289        #[cfg(not(feature = "tokio-sync"))]
290        {
291            match (self.read(), _other.read()) {
292                (Some(self_val), Some(other_val)) => *self_val == *other_val,
293                _ => false,
294            }
295        }
296    }
297}
298
299impl<T> Clone for SharedContainer<T> {
300    fn clone(&self) -> Self {
301        #[cfg(all(
302            feature = "std-sync",
303            not(feature = "tokio-sync"),
304            not(feature = "wasm-sync")
305        ))]
306        {
307            SharedContainer {
308                std_inner: Arc::clone(&self.std_inner),
309            }
310        }
311
312        #[cfg(feature = "tokio-sync")]
313        {
314            SharedContainer {
315                tokio_inner: Arc::clone(&self.tokio_inner),
316            }
317        }
318
319        #[cfg(any(
320            feature = "wasm-sync",
321            all(
322                target_arch = "wasm32",
323                not(feature = "std-sync"),
324                not(feature = "tokio-sync")
325            )
326        ))]
327        {
328            SharedContainer {
329                wasm_inner: Rc::clone(&self.wasm_inner),
330            }
331        }
332    }
333}
334
335impl<T: Clone> SharedContainer<T> {
336    /// Gets a clone of the contained value.
337    ///
338    /// This method acquires a read lock, clones the value, and releases the lock.
339    ///
340    /// # Returns
341    /// * `Some(T)`: A clone of the contained value
342    /// * `None`: If the lock couldn't be acquired
343    ///
344    /// # Note
345    /// When using the `tokio-sync` feature, this method will try to acquire the lock
346    /// in a blocking manner, which may not be ideal for async code. Consider using
347    /// `get_cloned_async()` instead.
348    #[cfg_attr(
349        feature = "tokio-sync",
350        doc = "WARNING: This method uses blocking operations when using tokio-sync feature, which is not ideal for async code. Consider using get_cloned_async() instead."
351    )]
352    pub fn get_cloned(&self) -> Option<T> {
353        #[cfg(feature = "tokio-sync")]
354        {
355            // Note: This method is not recommended with tokio-sync feature.
356            // Use get_cloned_async() instead for better async behavior.
357            None
358        }
359
360        #[cfg(not(feature = "tokio-sync"))]
361        {
362            let guard = self.read()?;
363            Some((*guard).clone())
364        }
365    }
366
367    /// Gets a clone of the contained value asynchronously.
368    ///
369    /// This method is only available when the `tokio-sync` feature is enabled.
370    ///
371    /// # Returns
372    /// A clone of the contained value
373    ///
374    /// # Examples
375    ///
376    /// ```
377    /// # #[cfg(feature = "tokio-sync")]
378    /// # async fn example() {
379    /// # use shared_container::SharedContainer;
380    /// let container = SharedContainer::new(42);
381    /// let value = container.get_cloned_async().await;
382    /// assert_eq!(value, 42);
383    /// # }
384    /// ```
385    #[cfg(feature = "tokio-sync")]
386    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
387    pub async fn get_cloned_async(&self) -> T
388    where
389        T: Clone,
390    {
391        let guard = self.tokio_inner.read().await;
392        (*guard).clone()
393    }
394}
395
396impl<T> SharedContainer<T> {
397    /// Creates a new `SharedContainer` containing the given value.
398    ///
399    /// # Parameters
400    /// * `value`: The value to store in the container
401    ///
402    /// # Returns
403    /// A new `SharedContainer` instance containing the value
404    pub fn new(value: T) -> Self {
405        #[cfg(all(
406            feature = "std-sync",
407            not(feature = "tokio-sync"),
408            not(feature = "wasm-sync")
409        ))]
410        {
411            SharedContainer {
412                std_inner: Arc::new(RwLock::new(value)),
413            }
414        }
415
416        #[cfg(feature = "tokio-sync")]
417        {
418            SharedContainer {
419                tokio_inner: Arc::new(RwLock::new(value)),
420            }
421        }
422
423        #[cfg(any(
424            feature = "wasm-sync",
425            all(
426                target_arch = "wasm32",
427                not(feature = "std-sync"),
428                not(feature = "tokio-sync")
429            )
430        ))]
431        {
432            SharedContainer {
433                wasm_inner: Rc::new(RefCell::new(value)),
434            }
435        }
436    }
437
438    /// Gets a read-only access guard to the contained value.
439    ///
440    /// # Returns
441    /// * `Some(SharedReadGuard<T>)`: A guard allowing read-only access to the value
442    /// * `None`: If the lock couldn't be acquired
443    ///
444    /// # Note
445    /// When using the `tokio-sync` feature, this method will always return `None`.
446    /// Use `read_async()` instead for async access.
447    #[cfg_attr(
448        feature = "tokio-sync",
449        doc = "WARNING: This method always returns None when using tokio-sync feature. Use read_async() instead."
450    )]
451    pub fn read(&self) -> Option<SharedReadGuard<'_, T>> {
452        #[cfg(feature = "tokio-sync")]
453        {
454            // Tokio's RwLock doesn't have a non-async read method, so we can't use it here
455            // Users should use read_async instead
456            return None;
457        }
458
459        #[cfg(all(
460            feature = "std-sync",
461            not(feature = "tokio-sync"),
462            not(feature = "wasm-sync")
463        ))]
464        {
465            match self.std_inner.read() {
466                Ok(guard) => Some(SharedReadGuard::StdSync(guard)),
467                Err(_) => None,
468            }
469        }
470
471        #[cfg(any(
472            feature = "wasm-sync",
473            all(
474                target_arch = "wasm32",
475                not(feature = "std-sync"),
476                not(feature = "tokio-sync")
477            )
478        ))]
479        {
480            match self.wasm_inner.try_borrow() {
481                Ok(borrow) => Some(SharedReadGuard::Single(borrow)),
482                Err(_) => None,
483            }
484        }
485    }
486
487    /// Gets a writable access guard to the contained value.
488    ///
489    /// # Returns
490    /// * `Some(SharedWriteGuard<T>)`: A guard allowing read-write access to the value
491    /// * `None`: If the lock couldn't be acquired
492    ///
493    /// # Note
494    /// When using the `tokio-sync` feature, this method will always return `None`.
495    /// Use `write_async()` instead for async access.
496    #[cfg_attr(
497        feature = "tokio-sync",
498        doc = "WARNING: This method always returns None when using tokio-sync feature. Use write_async() instead."
499    )]
500    pub fn write(&self) -> Option<SharedWriteGuard<'_, T>> {
501        #[cfg(feature = "tokio-sync")]
502        {
503            // Tokio's RwLock doesn't have a non-async write method, so we can't use it here
504            // Users should use write_async instead
505            return None;
506        }
507
508        #[cfg(all(
509            feature = "std-sync",
510            not(feature = "tokio-sync"),
511            not(feature = "wasm-sync")
512        ))]
513        {
514            match self.std_inner.write() {
515                Ok(guard) => Some(SharedWriteGuard::StdSync(guard)),
516                Err(_) => None,
517            }
518        }
519
520        #[cfg(any(
521            feature = "wasm-sync",
522            all(
523                target_arch = "wasm32",
524                not(feature = "std-sync"),
525                not(feature = "tokio-sync")
526            )
527        ))]
528        {
529            match self.wasm_inner.try_borrow_mut() {
530                Ok(borrow) => Some(SharedWriteGuard::Single(borrow)),
531                Err(_) => None,
532            }
533        }
534    }
535
536    /// Creates a weak reference to this container.
537    ///
538    /// A weak reference doesn't prevent the value from being dropped when no strong
539    /// references remain, which helps break reference cycles that could cause memory leaks.
540    ///
541    /// # Returns
542    /// A `WeakSharedContainer` that points to the same data
543    pub fn downgrade(&self) -> WeakSharedContainer<T> {
544        #[cfg(all(
545            feature = "std-sync",
546            not(feature = "tokio-sync"),
547            not(feature = "wasm-sync")
548        ))]
549        {
550            WeakSharedContainer {
551                std_inner: Arc::downgrade(&self.std_inner),
552            }
553        }
554
555        #[cfg(feature = "tokio-sync")]
556        {
557            WeakSharedContainer {
558                tokio_inner: Arc::downgrade(&self.tokio_inner),
559            }
560        }
561
562        #[cfg(any(
563            feature = "wasm-sync",
564            all(
565                target_arch = "wasm32",
566                not(feature = "std-sync"),
567                not(feature = "tokio-sync")
568            )
569        ))]
570        {
571            WeakSharedContainer {
572                wasm_inner: Rc::downgrade(&self.wasm_inner),
573            }
574        }
575    }
576
577    /// Asynchronously gets a read-only access guard to the contained value.
578    ///
579    /// This method is only available when the `tokio-sync` feature is enabled.
580    ///
581    /// # Returns
582    /// A guard allowing read-only access to the value
583    ///
584    /// # Examples
585    ///
586    /// ```
587    /// # #[cfg(feature = "tokio-sync")]
588    /// # async fn example() {
589    /// # use shared_container::SharedContainer;
590    /// let container = SharedContainer::new(42);
591    /// let guard = container.read_async().await;
592    /// assert_eq!(*guard, 42);
593    /// # }
594    /// ```
595    #[cfg(feature = "tokio-sync")]
596    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
597    pub async fn read_async(&self) -> SharedReadGuard<'_, T> {
598        let guard = self.tokio_inner.read().await;
599        SharedReadGuard::TokioSync(guard)
600    }
601
602    /// Asynchronously gets a writable access guard to the contained value.
603    ///
604    /// This method is only available when the `tokio-sync` feature is enabled.
605    ///
606    /// # Returns
607    /// A guard allowing read-write access to the value
608    ///
609    /// # Examples
610    ///
611    /// ```
612    /// # #[cfg(feature = "tokio-sync")]
613    /// # async fn example() {
614    /// # use shared_container::SharedContainer;
615    /// let container = SharedContainer::new(42);
616    /// let mut guard = container.write_async().await;
617    /// *guard = 100;
618    /// # }
619    /// ```
620    #[cfg(feature = "tokio-sync")]
621    #[cfg_attr(docsrs, doc(cfg(feature = "tokio-sync")))]
622    pub async fn write_async(&self) -> SharedWriteGuard<'_, T> {
623        let guard = self.tokio_inner.write().await;
624        SharedWriteGuard::TokioSync(guard)
625    }
626}
627
628impl<T> WeakSharedContainer<T> {
629    /// Attempts to create a strong `SharedContainer` from this weak reference.
630    ///
631    /// This will succeed if the value has not yet been dropped, i.e., if there are
632    /// still other strong references to it.
633    ///
634    /// # Returns
635    /// * `Some(SharedContainer<T>)`: If the value still exists
636    /// * `None`: If the value has been dropped
637    pub fn upgrade(&self) -> Option<SharedContainer<T>> {
638        // Different implementations for different platforms
639        #[cfg(all(
640            feature = "std-sync",
641            not(feature = "tokio-sync"),
642            not(feature = "wasm-sync")
643        ))]
644        {
645            self.std_inner
646                .upgrade()
647                .map(|inner| SharedContainer { std_inner: inner })
648        }
649
650        #[cfg(feature = "tokio-sync")]
651        {
652            self.tokio_inner
653                .upgrade()
654                .map(|inner| SharedContainer { tokio_inner: inner })
655        }
656
657        #[cfg(any(
658            feature = "wasm-sync",
659            all(
660                target_arch = "wasm32",
661                not(feature = "std-sync"),
662                not(feature = "tokio-sync")
663            )
664        ))]
665        {
666            self.wasm_inner
667                .upgrade()
668                .map(|inner| SharedContainer { wasm_inner: inner })
669        }
670    }
671}
672/// A read-only guard for accessing data in a `SharedContainer`.
673///
674/// This type abstracts over the differences between different read guards:
675/// - `std::sync::RwLockReadGuard` (used in standard multi-threaded environments)
676/// - `tokio::sync::RwLockReadGuard` (used for async/await support)
677/// - `std::cell::Ref` (used in single-threaded environments like WebAssembly)
678///
679/// It implements `Deref` to allow transparent access to the underlying data.
680pub enum SharedReadGuard<'a, T> {
681    #[cfg(all(
682        feature = "std-sync",
683        not(feature = "tokio-sync"),
684        not(feature = "wasm-sync")
685    ))]
686    StdSync(std::sync::RwLockReadGuard<'a, T>),
687
688    #[cfg(feature = "tokio-sync")]
689    TokioSync(tokio::sync::RwLockReadGuard<'a, T>),
690
691    #[cfg(any(
692        feature = "wasm-sync",
693        all(
694            target_arch = "wasm32",
695            not(feature = "std-sync"),
696            not(feature = "tokio-sync")
697        )
698    ))]
699    Single(Ref<'a, T>),
700}
701
702impl<'a, T> Deref for SharedReadGuard<'a, T> {
703    type Target = T;
704
705    fn deref(&self) -> &Self::Target {
706        #[cfg(all(
707            feature = "std-sync",
708            not(feature = "tokio-sync"),
709            not(feature = "wasm-sync")
710        ))]
711        {
712            match self {
713                SharedReadGuard::StdSync(guard) => guard.deref(),
714                #[allow(unreachable_patterns)]
715                _ => unreachable!(),
716            }
717        }
718
719        #[cfg(feature = "tokio-sync")]
720        {
721            match self {
722                SharedReadGuard::TokioSync(guard) => guard.deref(),
723                #[allow(unreachable_patterns)]
724                _ => unreachable!(),
725            }
726        }
727
728        #[cfg(any(
729            feature = "wasm-sync",
730            all(
731                target_arch = "wasm32",
732                not(feature = "std-sync"),
733                not(feature = "tokio-sync")
734            )
735        ))]
736        {
737            match self {
738                SharedReadGuard::Single(borrow) => borrow.deref(),
739                #[allow(unreachable_patterns)]
740                _ => unreachable!(),
741            }
742        }
743    }
744}
745
746/// A writable guard for accessing and modifying data in a `SharedContainer`.
747///
748/// This type abstracts over the differences between different write guards:
749/// - `std::sync::RwLockWriteGuard` (used in standard multi-threaded environments)
750/// - `tokio::sync::RwLockWriteGuard` (used for async/await support)
751/// - `std::cell::RefMut` (used in single-threaded environments like WebAssembly)
752///
753/// It implements both `Deref` and `DerefMut` to allow transparent access to the underlying data.
754pub enum SharedWriteGuard<'a, T> {
755    #[cfg(all(
756        feature = "std-sync",
757        not(feature = "tokio-sync"),
758        not(feature = "wasm-sync")
759    ))]
760    StdSync(std::sync::RwLockWriteGuard<'a, T>),
761
762    #[cfg(feature = "tokio-sync")]
763    TokioSync(tokio::sync::RwLockWriteGuard<'a, T>),
764
765    #[cfg(any(
766        feature = "wasm-sync",
767        all(
768            target_arch = "wasm32",
769            not(feature = "std-sync"),
770            not(feature = "tokio-sync")
771        )
772    ))]
773    Single(RefMut<'a, T>),
774}
775
776impl<'a, T> Deref for SharedWriteGuard<'a, T> {
777    type Target = T;
778
779    fn deref(&self) -> &Self::Target {
780        #[cfg(all(
781            feature = "std-sync",
782            not(feature = "tokio-sync"),
783            not(feature = "wasm-sync")
784        ))]
785        {
786            match self {
787                SharedWriteGuard::StdSync(guard) => guard.deref(),
788                #[allow(unreachable_patterns)]
789                _ => unreachable!(),
790            }
791        }
792
793        #[cfg(feature = "tokio-sync")]
794        {
795            match self {
796                SharedWriteGuard::TokioSync(guard) => guard.deref(),
797                #[allow(unreachable_patterns)]
798                _ => unreachable!(),
799            }
800        }
801
802        #[cfg(any(
803            feature = "wasm-sync",
804            all(
805                target_arch = "wasm32",
806                not(feature = "std-sync"),
807                not(feature = "tokio-sync")
808            )
809        ))]
810        {
811            match self {
812                SharedWriteGuard::Single(borrow) => borrow.deref(),
813                #[allow(unreachable_patterns)]
814                _ => unreachable!(),
815            }
816        }
817    }
818}
819
820impl<'a, T> DerefMut for SharedWriteGuard<'a, T> {
821    fn deref_mut(&mut self) -> &mut Self::Target {
822        #[cfg(all(
823            feature = "std-sync",
824            not(feature = "tokio-sync"),
825            not(feature = "wasm-sync")
826        ))]
827        {
828            match self {
829                SharedWriteGuard::StdSync(guard) => guard.deref_mut(),
830                #[allow(unreachable_patterns)]
831                _ => unreachable!(),
832            }
833        }
834
835        #[cfg(feature = "tokio-sync")]
836        {
837            match self {
838                SharedWriteGuard::TokioSync(guard) => guard.deref_mut(),
839                #[allow(unreachable_patterns)]
840                _ => unreachable!(),
841            }
842        }
843
844        #[cfg(any(
845            feature = "wasm-sync",
846            all(
847                target_arch = "wasm32",
848                not(feature = "std-sync"),
849                not(feature = "tokio-sync")
850            )
851        ))]
852        {
853            match self {
854                SharedWriteGuard::Single(borrow) => borrow.deref_mut(),
855                #[allow(unreachable_patterns)]
856                _ => unreachable!(),
857            }
858        }
859    }
860}
861
862// ============================================================================
863// New 0.3 API - Type-level separation of sync and async
864// ============================================================================
865
866/// Errors that can occur when accessing shared containers.
867#[derive(Debug, Clone, PartialEq, Eq)]
868pub enum AccessError {
869    /// The requested operation is not supported for this container type.
870    ///
871    /// This typically occurs when trying to use synchronous methods on an async container,
872    /// or vice versa.
873    UnsupportedMode,
874
875    /// A borrow conflict occurred (for single-threaded RefCell-based containers).
876    ///
877    /// This happens when trying to acquire a write lock while a read lock exists,
878    /// or when trying to acquire any lock while a write lock exists.
879    BorrowConflict,
880
881    /// The lock was poisoned due to a panic while holding the lock.
882    ///
883    /// This only occurs with multi-threaded RwLock-based containers.
884    Poisoned,
885}
886
887impl std::fmt::Display for AccessError {
888    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
889        match self {
890            AccessError::UnsupportedMode => {
891                write!(f, "operation not supported for this container mode")
892            }
893            AccessError::BorrowConflict => {
894                write!(f, "borrow conflict: lock already held")
895            }
896            AccessError::Poisoned => {
897                write!(f, "lock poisoned by panic")
898            }
899        }
900    }
901}
902
903impl std::error::Error for AccessError {}
904
905/// Trait for synchronous access to shared containers.
906pub trait SyncAccess<T> {
907    /// Acquires a read lock on the container.
908    fn read(&self) -> Result<SyncReadGuard<'_, T>, AccessError>;
909
910    /// Acquires a write lock on the container.
911    fn write(&self) -> Result<SyncWriteGuard<'_, T>, AccessError>;
912
913    /// Gets a clone of the contained value.
914    fn get_cloned(&self) -> Result<T, AccessError>
915    where
916        T: Clone;
917}
918
919/// Trait for asynchronous access to shared containers.
920#[cfg(feature = "async")]
921pub trait AsyncAccess<T> {
922    /// Asynchronously acquires a read lock on the container.
923    fn read_async<'a>(&'a self) -> impl std::future::Future<Output = AsyncReadGuard<'a, T>> + Send
924    where
925        T: 'a;
926
927    /// Asynchronously acquires a write lock on the container.
928    fn write_async<'a>(
929        &'a self,
930    ) -> impl std::future::Future<Output = AsyncWriteGuard<'a, T>> + Send
931    where
932        T: 'a;
933
934    /// Asynchronously gets a clone of the contained value.
935    fn get_cloned_async(&self) -> impl std::future::Future<Output = T> + Send
936    where
937        T: Clone;
938}
939
940/// Read guard for synchronous access.
941#[derive(Debug)]
942pub enum SyncReadGuard<'a, T> {
943    #[cfg(not(target_arch = "wasm32"))]
944    Std(std::sync::RwLockReadGuard<'a, T>),
945    #[cfg(target_arch = "wasm32")]
946    Wasm(Ref<'a, T>),
947}
948
949impl<'a, T> Deref for SyncReadGuard<'a, T> {
950    type Target = T;
951
952    fn deref(&self) -> &Self::Target {
953        match self {
954            #[cfg(not(target_arch = "wasm32"))]
955            SyncReadGuard::Std(guard) => guard.deref(),
956            #[cfg(target_arch = "wasm32")]
957            SyncReadGuard::Wasm(guard) => guard.deref(),
958        }
959    }
960}
961
962/// Write guard for synchronous access.
963#[derive(Debug)]
964pub enum SyncWriteGuard<'a, T> {
965    #[cfg(not(target_arch = "wasm32"))]
966    Std(std::sync::RwLockWriteGuard<'a, T>),
967    #[cfg(target_arch = "wasm32")]
968    Wasm(RefMut<'a, T>),
969}
970
971impl<'a, T> Deref for SyncWriteGuard<'a, T> {
972    type Target = T;
973
974    fn deref(&self) -> &Self::Target {
975        match self {
976            #[cfg(not(target_arch = "wasm32"))]
977            SyncWriteGuard::Std(guard) => guard.deref(),
978            #[cfg(target_arch = "wasm32")]
979            SyncWriteGuard::Wasm(guard) => guard.deref(),
980        }
981    }
982}
983
984impl<'a, T> DerefMut for SyncWriteGuard<'a, T> {
985    fn deref_mut(&mut self) -> &mut Self::Target {
986        match self {
987            #[cfg(not(target_arch = "wasm32"))]
988            SyncWriteGuard::Std(guard) => guard.deref_mut(),
989            #[cfg(target_arch = "wasm32")]
990            SyncWriteGuard::Wasm(guard) => guard.deref_mut(),
991        }
992    }
993}
994
995/// Read guard for asynchronous access.
996#[cfg(feature = "async")]
997#[derive(Debug)]
998pub struct AsyncReadGuard<'a, T>(tokio::sync::RwLockReadGuard<'a, T>);
999
1000#[cfg(feature = "async")]
1001impl<'a, T> Deref for AsyncReadGuard<'a, T> {
1002    type Target = T;
1003
1004    fn deref(&self) -> &Self::Target {
1005        self.0.deref()
1006    }
1007}
1008
1009/// Write guard for asynchronous access.
1010#[cfg(feature = "async")]
1011#[derive(Debug)]
1012pub struct AsyncWriteGuard<'a, T>(tokio::sync::RwLockWriteGuard<'a, T>);
1013
1014#[cfg(feature = "async")]
1015impl<'a, T> Deref for AsyncWriteGuard<'a, T> {
1016    type Target = T;
1017
1018    fn deref(&self) -> &Self::Target {
1019        self.0.deref()
1020    }
1021}
1022
1023#[cfg(feature = "async")]
1024impl<'a, T> DerefMut for AsyncWriteGuard<'a, T> {
1025    fn deref_mut(&mut self) -> &mut Self::Target {
1026        self.0.deref_mut()
1027    }
1028}
1029
1030/// A synchronous shared container that works across platforms.
1031///
1032/// On wasm32 targets: uses `Rc<RefCell<T>>`
1033/// On other targets: uses `Arc<RwLock<T>>`
1034#[derive(Debug)]
1035pub struct Shared<T> {
1036    #[cfg(target_arch = "wasm32")]
1037    inner: Rc<RefCell<T>>,
1038
1039    #[cfg(not(target_arch = "wasm32"))]
1040    inner: std::sync::Arc<std::sync::RwLock<T>>,
1041}
1042
1043/// A weak reference to a `Shared<T>`.
1044#[derive(Debug)]
1045pub struct WeakShared<T> {
1046    #[cfg(target_arch = "wasm32")]
1047    inner: RcWeak<RefCell<T>>,
1048
1049    #[cfg(not(target_arch = "wasm32"))]
1050    inner: std::sync::Weak<std::sync::RwLock<T>>,
1051}
1052
1053/// An asynchronous shared container using tokio primitives.
1054///
1055/// Only available with the `async` feature flag.
1056#[cfg(feature = "async")]
1057#[derive(Debug)]
1058pub struct AsyncShared<T> {
1059    inner: Arc<tokio::sync::RwLock<T>>,
1060}
1061
1062#[cfg(feature = "async")]
1063unsafe impl<T: Send> Send for AsyncShared<T> {}
1064
1065#[cfg(feature = "async")]
1066unsafe impl<T: Send + Sync> Sync for AsyncShared<T> {}
1067
1068/// A weak reference to an `AsyncShared<T>`.
1069#[cfg(feature = "async")]
1070#[derive(Debug)]
1071pub struct WeakAsyncShared<T> {
1072    inner: Weak<tokio::sync::RwLock<T>>,
1073}
1074
1075/// A universal container that can hold either sync or async variants.
1076///
1077/// This enum allows writing generic code that works with both sync and async containers,
1078/// but requires explicit handling of the mode mismatch via `Result`.
1079#[derive(Debug)]
1080pub enum SharedAny<T> {
1081    Sync(Shared<T>),
1082    #[cfg(feature = "async")]
1083    Async(AsyncShared<T>),
1084}
1085
1086/// A weak reference to a `SharedAny<T>`.
1087#[derive(Debug)]
1088pub enum WeakSharedAny<T> {
1089    Sync(WeakShared<T>),
1090    #[cfg(feature = "async")]
1091    Async(WeakAsyncShared<T>),
1092}
1093
1094// ============================================================================
1095// Basic constructors and conversions
1096// ============================================================================
1097
1098impl<T> Shared<T> {
1099    /// Creates a new synchronous shared container.
1100    pub fn new(value: T) -> Self {
1101        #[cfg(target_arch = "wasm32")]
1102        {
1103            Shared {
1104                inner: Rc::new(RefCell::new(value)),
1105            }
1106        }
1107
1108        #[cfg(not(target_arch = "wasm32"))]
1109        {
1110            Shared {
1111                inner: std::sync::Arc::new(std::sync::RwLock::new(value)),
1112            }
1113        }
1114    }
1115
1116    /// Creates a weak reference to this container.
1117    pub fn downgrade(&self) -> WeakShared<T> {
1118        #[cfg(target_arch = "wasm32")]
1119        {
1120            WeakShared {
1121                inner: Rc::downgrade(&self.inner),
1122            }
1123        }
1124
1125        #[cfg(not(target_arch = "wasm32"))]
1126        {
1127            WeakShared {
1128                inner: std::sync::Arc::downgrade(&self.inner),
1129            }
1130        }
1131    }
1132}
1133
1134impl<T> Clone for Shared<T> {
1135    fn clone(&self) -> Self {
1136        #[cfg(target_arch = "wasm32")]
1137        {
1138            Shared {
1139                inner: Rc::clone(&self.inner),
1140            }
1141        }
1142
1143        #[cfg(not(target_arch = "wasm32"))]
1144        {
1145            Shared {
1146                inner: std::sync::Arc::clone(&self.inner),
1147            }
1148        }
1149    }
1150}
1151
1152impl<T> WeakShared<T> {
1153    /// Attempts to upgrade the weak reference to a strong reference.
1154    pub fn upgrade(&self) -> Option<Shared<T>> {
1155        #[cfg(target_arch = "wasm32")]
1156        {
1157            self.inner.upgrade().map(|inner| Shared { inner })
1158        }
1159
1160        #[cfg(not(target_arch = "wasm32"))]
1161        {
1162            self.inner.upgrade().map(|inner| Shared { inner })
1163        }
1164    }
1165}
1166
1167impl<T> Clone for WeakShared<T> {
1168    fn clone(&self) -> Self {
1169        WeakShared {
1170            inner: self.inner.clone(),
1171        }
1172    }
1173}
1174
1175// ============================================================================
1176// SyncAccess implementation for Shared<T>
1177// ============================================================================
1178
1179impl<T> SyncAccess<T> for Shared<T> {
1180    fn read(&self) -> Result<SyncReadGuard<'_, T>, AccessError> {
1181        #[cfg(not(target_arch = "wasm32"))]
1182        {
1183            self.inner
1184                .read()
1185                .map(SyncReadGuard::Std)
1186                .map_err(|_| AccessError::Poisoned)
1187        }
1188
1189        #[cfg(target_arch = "wasm32")]
1190        {
1191            self.inner
1192                .try_borrow()
1193                .map(SyncReadGuard::Wasm)
1194                .map_err(|_| AccessError::BorrowConflict)
1195        }
1196    }
1197
1198    fn write(&self) -> Result<SyncWriteGuard<'_, T>, AccessError> {
1199        #[cfg(not(target_arch = "wasm32"))]
1200        {
1201            self.inner
1202                .write()
1203                .map(SyncWriteGuard::Std)
1204                .map_err(|_| AccessError::Poisoned)
1205        }
1206
1207        #[cfg(target_arch = "wasm32")]
1208        {
1209            self.inner
1210                .try_borrow_mut()
1211                .map(SyncWriteGuard::Wasm)
1212                .map_err(|_| AccessError::BorrowConflict)
1213        }
1214    }
1215
1216    fn get_cloned(&self) -> Result<T, AccessError>
1217    where
1218        T: Clone,
1219    {
1220        let guard = self.read()?;
1221        Ok((*guard).clone())
1222    }
1223}
1224
1225#[cfg(feature = "async")]
1226impl<T> AsyncShared<T> {
1227    /// Creates a new asynchronous shared container.
1228    pub fn new(value: T) -> Self {
1229        AsyncShared {
1230            inner: Arc::new(tokio::sync::RwLock::new(value)),
1231        }
1232    }
1233
1234    /// Creates a weak reference to this container.
1235    pub fn downgrade(&self) -> WeakAsyncShared<T> {
1236        WeakAsyncShared {
1237            inner: Arc::downgrade(&self.inner),
1238        }
1239    }
1240}
1241
1242#[cfg(feature = "async")]
1243impl<T> Clone for AsyncShared<T> {
1244    fn clone(&self) -> Self {
1245        AsyncShared {
1246            inner: Arc::clone(&self.inner),
1247        }
1248    }
1249}
1250
1251#[cfg(feature = "async")]
1252impl<T> WeakAsyncShared<T> {
1253    /// Attempts to upgrade the weak reference to a strong reference.
1254    pub fn upgrade(&self) -> Option<AsyncShared<T>> {
1255        self.inner.upgrade().map(|inner| AsyncShared { inner })
1256    }
1257}
1258
1259#[cfg(feature = "async")]
1260impl<T> Clone for WeakAsyncShared<T> {
1261    fn clone(&self) -> Self {
1262        WeakAsyncShared {
1263            inner: self.inner.clone(),
1264        }
1265    }
1266}
1267
1268// ============================================================================
1269// AsyncAccess implementation for AsyncShared<T>
1270// ============================================================================
1271
1272#[cfg(feature = "async")]
1273impl<T: Send + Sync> AsyncAccess<T> for AsyncShared<T> {
1274    async fn read_async<'a>(&'a self) -> AsyncReadGuard<'a, T>
1275    where
1276        T: 'a,
1277    {
1278        AsyncReadGuard(self.inner.read().await)
1279    }
1280
1281    async fn write_async<'a>(&'a self) -> AsyncWriteGuard<'a, T>
1282    where
1283        T: 'a,
1284    {
1285        AsyncWriteGuard(self.inner.write().await)
1286    }
1287
1288    async fn get_cloned_async(&self) -> T
1289    where
1290        T: Clone,
1291    {
1292        let guard = self.inner.read().await;
1293        (*guard).clone()
1294    }
1295}
1296
1297// ============================================================================
1298// Conversions for SharedAny
1299// ============================================================================
1300
1301// Conversions for SharedAny
1302impl<T> From<Shared<T>> for SharedAny<T> {
1303    fn from(shared: Shared<T>) -> Self {
1304        SharedAny::Sync(shared)
1305    }
1306}
1307
1308#[cfg(feature = "async")]
1309impl<T> From<AsyncShared<T>> for SharedAny<T> {
1310    fn from(shared: AsyncShared<T>) -> Self {
1311        SharedAny::Async(shared)
1312    }
1313}
1314
1315impl<T> Clone for SharedAny<T> {
1316    fn clone(&self) -> Self {
1317        match self {
1318            SharedAny::Sync(s) => SharedAny::Sync(s.clone()),
1319            #[cfg(feature = "async")]
1320            SharedAny::Async(a) => SharedAny::Async(a.clone()),
1321        }
1322    }
1323}
1324
1325impl<T> SharedAny<T> {
1326    /// Creates a weak reference to this container.
1327    pub fn downgrade(&self) -> WeakSharedAny<T> {
1328        match self {
1329            SharedAny::Sync(s) => WeakSharedAny::Sync(s.downgrade()),
1330            #[cfg(feature = "async")]
1331            SharedAny::Async(a) => WeakSharedAny::Async(a.downgrade()),
1332        }
1333    }
1334}
1335
1336impl<T> WeakSharedAny<T> {
1337    /// Attempts to upgrade the weak reference to a strong reference.
1338    pub fn upgrade(&self) -> Option<SharedAny<T>> {
1339        match self {
1340            WeakSharedAny::Sync(w) => w.upgrade().map(SharedAny::Sync),
1341            #[cfg(feature = "async")]
1342            WeakSharedAny::Async(w) => w.upgrade().map(SharedAny::Async),
1343        }
1344    }
1345}
1346
1347impl<T> Clone for WeakSharedAny<T> {
1348    fn clone(&self) -> Self {
1349        match self {
1350            WeakSharedAny::Sync(w) => WeakSharedAny::Sync(w.clone()),
1351            #[cfg(feature = "async")]
1352            WeakSharedAny::Async(w) => WeakSharedAny::Async(w.clone()),
1353        }
1354    }
1355}
1356
1357// ============================================================================
1358// Trait implementations for SharedAny<T>
1359// ============================================================================
1360
1361impl<T> SyncAccess<T> for SharedAny<T> {
1362    fn read(&self) -> Result<SyncReadGuard<'_, T>, AccessError> {
1363        match self {
1364            SharedAny::Sync(s) => s.read(),
1365            #[cfg(feature = "async")]
1366            SharedAny::Async(_) => Err(AccessError::UnsupportedMode),
1367        }
1368    }
1369
1370    fn write(&self) -> Result<SyncWriteGuard<'_, T>, AccessError> {
1371        match self {
1372            SharedAny::Sync(s) => s.write(),
1373            #[cfg(feature = "async")]
1374            SharedAny::Async(_) => Err(AccessError::UnsupportedMode),
1375        }
1376    }
1377
1378    fn get_cloned(&self) -> Result<T, AccessError>
1379    where
1380        T: Clone,
1381    {
1382        match self {
1383            SharedAny::Sync(s) => s.get_cloned(),
1384            #[cfg(feature = "async")]
1385            SharedAny::Async(_) => Err(AccessError::UnsupportedMode),
1386        }
1387    }
1388}
1389
1390#[cfg(feature = "async")]
1391impl<T: Send + Sync> AsyncAccess<T> for SharedAny<T> {
1392    async fn read_async<'a>(&'a self) -> AsyncReadGuard<'a, T>
1393    where
1394        T: 'a,
1395    {
1396        match self {
1397            SharedAny::Async(a) => a.read_async().await,
1398            SharedAny::Sync(_) => {
1399                // This branch should not be reachable in normal usage,
1400                // as the type system should prevent it. However, we need
1401                // to provide a return value for the compiler.
1402                unreachable!("Cannot call async methods on sync container")
1403            }
1404        }
1405    }
1406
1407    async fn write_async<'a>(&'a self) -> AsyncWriteGuard<'a, T>
1408    where
1409        T: 'a,
1410    {
1411        match self {
1412            SharedAny::Async(a) => a.write_async().await,
1413            SharedAny::Sync(_) => {
1414                unreachable!("Cannot call async methods on sync container")
1415            }
1416        }
1417    }
1418
1419    async fn get_cloned_async(&self) -> T
1420    where
1421        T: Clone,
1422    {
1423        match self {
1424            SharedAny::Async(a) => a.get_cloned_async().await,
1425            SharedAny::Sync(_) => {
1426                unreachable!("Cannot call async methods on sync container")
1427            }
1428        }
1429    }
1430}
1431
1432#[cfg(test)]
1433mod tests {
1434
1435    #[derive(Debug, Clone, PartialEq)]
1436    #[allow(dead_code)]
1437    struct TestStruct {
1438        value: i32,
1439    }
1440
1441    // Skip synchronous tests when tokio-sync is enabled
1442    #[cfg(not(feature = "tokio-sync"))]
1443    mod sync_tests {
1444        use super::*;
1445        use crate::SharedContainer;
1446
1447        #[test]
1448        fn test_read_access() {
1449            let container = SharedContainer::new(TestStruct { value: 42 });
1450
1451            // Read access
1452            let guard = container.read().unwrap();
1453            assert_eq!(guard.value, 42);
1454        }
1455
1456        #[test]
1457        fn test_write_access() {
1458            let container = SharedContainer::new(TestStruct { value: 42 });
1459
1460            // Write access
1461            {
1462                let mut guard = container.write().unwrap();
1463                guard.value = 100;
1464            }
1465
1466            // Verify change
1467            let guard = container.read().unwrap();
1468            assert_eq!(guard.value, 100);
1469        }
1470
1471        #[test]
1472        fn test_clone_container() {
1473            let container1 = SharedContainer::new(TestStruct { value: 42 });
1474            let container2 = container1.clone();
1475
1476            // Modify through container2
1477            {
1478                let mut guard = container2.write().unwrap();
1479                guard.value = 100;
1480            }
1481
1482            // Verify change visible through container1
1483            let guard = container1.read().unwrap();
1484            assert_eq!(guard.value, 100);
1485        }
1486
1487        #[test]
1488        fn test_get_cloned() {
1489            let container = SharedContainer::new(TestStruct { value: 42 });
1490            let cloned = container.get_cloned().unwrap();
1491            assert_eq!(cloned, TestStruct { value: 42 });
1492
1493            // Modify original
1494            {
1495                let mut guard = container.write().unwrap();
1496                guard.value = 100;
1497            }
1498
1499            // Cloned value should not change
1500            assert_eq!(cloned, TestStruct { value: 42 });
1501
1502            // And we can get a new clone with updated value
1503            let new_clone = container.get_cloned().unwrap();
1504            assert_eq!(new_clone, TestStruct { value: 100 });
1505        }
1506
1507        #[test]
1508        fn test_weak_ref() {
1509            let container = SharedContainer::new(TestStruct { value: 42 });
1510
1511            // Create a weak reference
1512            let weak = container.downgrade();
1513
1514            // Weak reference can be upgraded to a strong reference
1515            let container2 = weak.upgrade().unwrap();
1516
1517            // Both containers point to the same data
1518            {
1519                let mut guard = container2.write().unwrap();
1520                guard.value = 100;
1521            }
1522
1523            // Change visible through first container
1524            {
1525                let guard = container.read().unwrap();
1526                assert_eq!(guard.value, 100);
1527            }
1528            // Drop all strong references
1529            drop(container);
1530            drop(container2);
1531
1532            // Weak reference can no longer be upgraded
1533            assert!(weak.upgrade().is_none());
1534        }
1535
1536        #[test]
1537        fn test_weak_clone() {
1538            let container = SharedContainer::new(TestStruct { value: 42 });
1539
1540            // Create a weak reference and clone it
1541            let weak1 = container.downgrade();
1542            let weak2 = weak1.clone();
1543
1544            // Both weak references can be upgraded
1545            let container1 = weak1.upgrade().unwrap();
1546            let container2 = weak2.upgrade().unwrap();
1547
1548            // Modify through container2
1549            {
1550                let mut guard = container2.write().unwrap();
1551                guard.value = 100;
1552            }
1553
1554            // Change visible through container1
1555            {
1556                let guard = container1.read().unwrap();
1557                assert_eq!(guard.value, 100);
1558            }
1559
1560            // Drop all strong references
1561            drop(container);
1562            drop(container1);
1563            drop(container2);
1564
1565            // Neither weak reference can be upgraded
1566            assert!(weak1.upgrade().is_none());
1567            assert!(weak2.upgrade().is_none());
1568        }
1569    }
1570}
1571
1572// Tests specifically for the tokio async implementation
1573#[cfg(test)]
1574#[cfg(feature = "tokio-sync")]
1575mod tokio_tests {
1576    use super::*;
1577    use tokio::runtime::Runtime;
1578
1579    #[derive(Debug, Clone, PartialEq)]
1580    struct TestStruct {
1581        value: i32,
1582    }
1583
1584    #[test]
1585    fn test_tokio_read_access() {
1586        let rt = Runtime::new().unwrap();
1587        rt.block_on(async {
1588            let container = SharedContainer::new(TestStruct { value: 42 });
1589
1590            // Synchronous read should return None with tokio-sync
1591            assert!(container.read().is_none());
1592
1593            // Async read access
1594            let guard = container.read_async().await;
1595            assert_eq!(guard.value, 42);
1596        });
1597    }
1598
1599    #[test]
1600    fn test_tokio_write_access() {
1601        let rt = Runtime::new().unwrap();
1602        rt.block_on(async {
1603            let container = SharedContainer::new(TestStruct { value: 42 });
1604
1605            // Synchronous write should return None with tokio-sync
1606            assert!(container.write().is_none());
1607
1608            // Async write access
1609            {
1610                let mut guard = container.write_async().await;
1611                guard.value = 100;
1612            }
1613
1614            // Verify change
1615            let guard = container.read_async().await;
1616            assert_eq!(guard.value, 100);
1617        });
1618    }
1619
1620    #[test]
1621    fn test_tokio_clone_container() {
1622        let rt = Runtime::new().unwrap();
1623        rt.block_on(async {
1624            let container1 = SharedContainer::new(TestStruct { value: 42 });
1625            let container2 = container1.clone();
1626
1627            // Modify through container2
1628            {
1629                let mut guard = container2.write_async().await;
1630                guard.value = 100;
1631            }
1632
1633            // Verify change visible through container1
1634            let guard = container1.read_async().await;
1635            assert_eq!(guard.value, 100);
1636        });
1637    }
1638
1639    #[test]
1640    fn test_tokio_weak_ref() {
1641        let rt = Runtime::new().unwrap();
1642        rt.block_on(async {
1643            let container = SharedContainer::new(TestStruct { value: 42 });
1644
1645            // Create a weak reference
1646            let weak = container.downgrade();
1647
1648            // Weak reference can be upgraded to a strong reference
1649            let container2 = weak.upgrade().unwrap();
1650
1651            // Both containers point to the same data
1652            {
1653                let mut guard = container2.write_async().await;
1654                guard.value = 100;
1655            }
1656
1657            // Change visible through first container
1658            {
1659                let guard = container.read_async().await;
1660                assert_eq!(guard.value, 100);
1661            }
1662
1663            // Drop all strong references
1664            drop(container);
1665            drop(container2);
1666
1667            // Weak reference can no longer be upgraded
1668            assert!(weak.upgrade().is_none());
1669        });
1670    }
1671}
1672
1673// Tests specifically for the WebAssembly implementation
1674// These tests can be run on any platform by enabling the force-wasm-impl feature
1675#[cfg(test)]
1676#[cfg(any(target_arch = "wasm32", feature = "force-wasm-impl"))]
1677mod wasm_tests {
1678    use super::*;
1679
1680    #[derive(Debug, Clone, PartialEq)]
1681    struct TestStruct {
1682        value: i32,
1683    }
1684
1685    #[test]
1686    fn test_wasm_read_access() {
1687        let container = SharedContainer::new(TestStruct { value: 42 });
1688
1689        // Read access
1690        let guard = container.read().unwrap();
1691        assert_eq!(guard.value, 42);
1692    }
1693
1694    #[test]
1695    fn test_wasm_write_access() {
1696        let container = SharedContainer::new(TestStruct { value: 42 });
1697
1698        // Write access
1699        {
1700            let mut guard = container.write().unwrap();
1701            guard.value = 100;
1702        }
1703
1704        // Verify change
1705        let guard = container.read().unwrap();
1706        assert_eq!(guard.value, 100);
1707    }
1708
1709    #[test]
1710    fn test_wasm_borrow_conflict() {
1711        let container = SharedContainer::new(TestStruct { value: 42 });
1712
1713        // Get a read borrow
1714        let _guard = container.read().unwrap();
1715
1716        // Trying to get a write borrow while a read borrow exists should fail
1717        assert!(container.write().is_none());
1718    }
1719
1720    #[test]
1721    fn test_wasm_multiple_reads() {
1722        let container = SharedContainer::new(TestStruct { value: 42 });
1723
1724        // Multiple read borrows should work
1725        let _guard1 = container.read().unwrap();
1726        let guard2 = container.read().unwrap();
1727
1728        assert_eq!(guard2.value, 42);
1729    }
1730
1731    #[test]
1732    fn test_wasm_weak_ref() {
1733        let container = SharedContainer::new(TestStruct { value: 42 });
1734        let weak = container.downgrade();
1735
1736        // Upgrade should work
1737        let container2 = weak.upgrade().unwrap();
1738        assert_eq!(container2.read().unwrap().value, 42);
1739
1740        // After dropping all strong references, upgrade should fail
1741        drop(container);
1742        drop(container2);
1743        assert!(weak.upgrade().is_none());
1744    }
1745}