Skip to main content

goud_engine/ecs/
resource.rs

1//! Resource system for the ECS.
2//!
3//! Resources are singleton data that exists outside the entity-component model.
4//! Unlike components, resources are not attached to entities - they are globally
5//! accessible within the World.
6//!
7//! # Examples of Resources
8//!
9//! - **Time**: Delta time, total elapsed time, frame count
10//! - **Input State**: Keyboard, mouse, and gamepad state
11//! - **Asset Manager**: Loaded textures, sounds, and other assets
12//! - **Configuration**: Game settings, debug flags
13//!
14//! # Resource vs Component
15//!
16//! | Aspect | Resource | Component |
17//! |--------|----------|-----------|
18//! | Cardinality | One per type | Many per type |
19//! | Ownership | Owned by World | Attached to Entity |
20//! | Access | `Res<T>`, `ResMut<T>` | `Query<&T>`, `Query<&mut T>` |
21//! | Use Case | Global state | Per-entity state |
22//!
23//! # Usage
24//!
25//! ```ignore
26//! use goud_engine::ecs::{World, Resource};
27//!
28//! // Define a resource
29//! struct Time {
30//!     delta: f32,
31//!     total: f32,
32//! }
33//! impl Resource for Time {}
34//!
35//! // Insert resource into World
36//! let mut world = World::new();
37//! world.insert_resource(Time { delta: 0.016, total: 0.0 });
38//!
39//! // Access resource (immutably)
40//! let time = world.get_resource::<Time>().unwrap();
41//! println!("Delta: {}", time.delta);
42//!
43//! // Access resource (mutably)
44//! let time = world.get_resource_mut::<Time>().unwrap();
45//! time.total += time.delta;
46//! ```
47//!
48//! # System Parameters
49//!
50//! In systems, use `Res<T>` and `ResMut<T>` for resource access:
51//!
52//! ```ignore
53//! fn update_system(time: Res<Time>, mut query: Query<&mut Position>) {
54//!     for mut pos in query.iter_mut() {
55//!         pos.x += time.delta * 10.0;
56//!     }
57//! }
58//! ```
59//!
60//! # Thread Safety
61//!
62//! Resources must be `Send + Sync` for use in parallel systems. For resources
63//! that are not thread-safe (e.g., window handles), use non-send resources
64//! (future: `NonSend<T>`, `NonSendMut<T>`).
65
66use std::any::{Any, TypeId};
67use std::collections::HashMap;
68use std::fmt;
69use std::ops::{Deref, DerefMut};
70
71// =============================================================================
72// Resource Trait
73// =============================================================================
74
75/// Marker trait for types that can be used as resources.
76///
77/// Resources are singleton data stored in the [`World`](crate::ecs::World).
78/// To make a type usable as a resource, implement this trait:
79///
80/// ```ignore
81/// use goud_engine::ecs::Resource;
82///
83/// struct GameConfig {
84///     difficulty: u8,
85///     sound_volume: f32,
86/// }
87///
88/// impl Resource for GameConfig {}
89/// ```
90///
91/// # Requirements
92///
93/// Resources must be:
94/// - `Send + Sync` for parallel system execution
95/// - `'static` for type erasure in storage
96///
97/// Unlike [`Component`](crate::ecs::Component), `Resource` does NOT require
98/// explicit opt-in - any compatible type can be a resource.
99pub trait Resource: Send + Sync + 'static {}
100
101// Blanket implementation: any Send + Sync + 'static type can be a resource
102impl<T: Send + Sync + 'static> Resource for T {}
103
104// =============================================================================
105// ResourceId
106// =============================================================================
107
108/// Unique identifier for a resource type.
109///
110/// `ResourceId` wraps a `TypeId` to identify resource types at runtime.
111/// This is used internally for resource storage and access conflict detection.
112///
113/// # Example
114///
115/// ```
116/// use goud_engine::ecs::resource::ResourceId;
117///
118/// struct MyResource { value: i32 }
119///
120/// let id = ResourceId::of::<MyResource>();
121/// let id2 = ResourceId::of::<MyResource>();
122///
123/// assert_eq!(id, id2);
124/// ```
125#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
126pub struct ResourceId(TypeId);
127
128impl ResourceId {
129    /// Returns the `ResourceId` for a specific type.
130    ///
131    /// # Example
132    ///
133    /// ```
134    /// use goud_engine::ecs::resource::ResourceId;
135    ///
136    /// struct Time { delta: f32 }
137    /// let id = ResourceId::of::<Time>();
138    /// ```
139    #[inline]
140    pub fn of<T: 'static>() -> Self {
141        Self(TypeId::of::<T>())
142    }
143
144    /// Returns the underlying `TypeId`.
145    #[inline]
146    pub fn type_id(&self) -> TypeId {
147        self.0
148    }
149}
150
151impl fmt::Debug for ResourceId {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153        write!(f, "ResourceId({:?})", self.0)
154    }
155}
156
157// =============================================================================
158// Resources Container
159// =============================================================================
160
161/// Storage container for all resources in a World.
162///
163/// `Resources` stores type-erased resource data and provides type-safe
164/// access through generic methods.
165///
166/// # Thread Safety
167///
168/// The container itself is not thread-safe. Use external synchronization
169/// or the scheduler for parallel access.
170#[derive(Default)]
171pub struct Resources {
172    /// Type-erased resource storage.
173    data: HashMap<ResourceId, Box<dyn Any + Send + Sync>>,
174}
175
176impl Resources {
177    /// Creates an empty resources container.
178    #[inline]
179    pub fn new() -> Self {
180        Self {
181            data: HashMap::new(),
182        }
183    }
184
185    /// Inserts a resource into the container.
186    ///
187    /// If a resource of this type already exists, it is replaced and the
188    /// old value is returned.
189    ///
190    /// # Arguments
191    ///
192    /// * `resource` - The resource to insert
193    ///
194    /// # Returns
195    ///
196    /// `Some(T)` if a resource of this type was replaced, `None` otherwise.
197    ///
198    /// # Example
199    ///
200    /// ```
201    /// use goud_engine::ecs::resource::Resources;
202    ///
203    /// struct Score(u32);
204    ///
205    /// let mut resources = Resources::new();
206    /// assert!(resources.insert(Score(0)).is_none());
207    /// assert!(resources.insert(Score(100)).is_some()); // Replaced
208    /// ```
209    #[inline]
210    pub fn insert<T: Resource>(&mut self, resource: T) -> Option<T> {
211        let id = ResourceId::of::<T>();
212        let old = self.data.insert(id, Box::new(resource));
213        old.and_then(|boxed| boxed.downcast::<T>().ok().map(|b| *b))
214    }
215
216    /// Removes a resource from the container.
217    ///
218    /// # Returns
219    ///
220    /// `Some(T)` if the resource existed, `None` otherwise.
221    ///
222    /// # Example
223    ///
224    /// ```
225    /// use goud_engine::ecs::resource::Resources;
226    ///
227    /// struct Score(u32);
228    ///
229    /// let mut resources = Resources::new();
230    /// resources.insert(Score(100));
231    ///
232    /// let score = resources.remove::<Score>();
233    /// assert!(score.is_some());
234    /// assert_eq!(score.unwrap().0, 100);
235    ///
236    /// assert!(resources.remove::<Score>().is_none()); // Already removed
237    /// ```
238    #[inline]
239    pub fn remove<T: Resource>(&mut self) -> Option<T> {
240        let id = ResourceId::of::<T>();
241        self.data
242            .remove(&id)
243            .and_then(|boxed| boxed.downcast::<T>().ok().map(|b| *b))
244    }
245
246    /// Returns an immutable reference to a resource.
247    ///
248    /// # Returns
249    ///
250    /// `Some(&T)` if the resource exists, `None` otherwise.
251    ///
252    /// # Example
253    ///
254    /// ```
255    /// use goud_engine::ecs::resource::Resources;
256    ///
257    /// struct Score(u32);
258    ///
259    /// let mut resources = Resources::new();
260    /// resources.insert(Score(100));
261    ///
262    /// let score = resources.get::<Score>().unwrap();
263    /// assert_eq!(score.0, 100);
264    /// ```
265    #[inline]
266    pub fn get<T: Resource>(&self) -> Option<&T> {
267        let id = ResourceId::of::<T>();
268        self.data.get(&id).and_then(|boxed| boxed.downcast_ref())
269    }
270
271    /// Returns a mutable reference to a resource.
272    ///
273    /// # Returns
274    ///
275    /// `Some(&mut T)` if the resource exists, `None` otherwise.
276    ///
277    /// # Example
278    ///
279    /// ```
280    /// use goud_engine::ecs::resource::Resources;
281    ///
282    /// struct Score(u32);
283    ///
284    /// let mut resources = Resources::new();
285    /// resources.insert(Score(100));
286    ///
287    /// let score = resources.get_mut::<Score>().unwrap();
288    /// score.0 += 50;
289    /// assert_eq!(resources.get::<Score>().unwrap().0, 150);
290    /// ```
291    #[inline]
292    pub fn get_mut<T: Resource>(&mut self) -> Option<&mut T> {
293        let id = ResourceId::of::<T>();
294        self.data
295            .get_mut(&id)
296            .and_then(|boxed| boxed.downcast_mut())
297    }
298
299    /// Returns `true` if a resource of the specified type exists.
300    ///
301    /// # Example
302    ///
303    /// ```
304    /// use goud_engine::ecs::resource::Resources;
305    ///
306    /// struct Score(u32);
307    /// struct Health(f32);
308    ///
309    /// let mut resources = Resources::new();
310    /// resources.insert(Score(100));
311    ///
312    /// assert!(resources.contains::<Score>());
313    /// assert!(!resources.contains::<Health>());
314    /// ```
315    #[inline]
316    pub fn contains<T: Resource>(&self) -> bool {
317        self.data.contains_key(&ResourceId::of::<T>())
318    }
319
320    /// Returns the number of resources in the container.
321    #[inline]
322    pub fn len(&self) -> usize {
323        self.data.len()
324    }
325
326    /// Returns `true` if there are no resources.
327    #[inline]
328    pub fn is_empty(&self) -> bool {
329        self.data.is_empty()
330    }
331
332    /// Removes all resources from the container.
333    #[inline]
334    pub fn clear(&mut self) {
335        self.data.clear();
336    }
337}
338
339impl fmt::Debug for Resources {
340    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
341        f.debug_struct("Resources")
342            .field("count", &self.data.len())
343            .finish()
344    }
345}
346
347// =============================================================================
348// Res<T> - Immutable Resource Access
349// =============================================================================
350
351/// Immutable access to a resource of type `T`.
352///
353/// `Res<T>` provides read-only access to a resource stored in the World.
354/// It implements `Deref`, so you can access the inner value directly.
355///
356/// # Panics
357///
358/// Operations on `Res<T>` will panic if the resource doesn't exist.
359/// Use `Option<Res<T>>` for optional access (future).
360///
361/// # Example
362///
363/// ```ignore
364/// fn print_time(time: Res<Time>) {
365///     println!("Delta: {}, Total: {}", time.delta, time.total);
366/// }
367/// ```
368///
369/// # Thread Safety
370///
371/// Multiple `Res<T>` instances can coexist, as they only provide read access.
372/// They conflict with `ResMut<T>` on the same resource type.
373pub struct Res<'w, T: Resource> {
374    value: &'w T,
375}
376
377impl<'w, T: Resource> Res<'w, T> {
378    /// Creates a new `Res` from a reference.
379    ///
380    /// This is primarily used internally by the system parameter infrastructure.
381    #[inline]
382    pub fn new(value: &'w T) -> Self {
383        Self { value }
384    }
385
386    /// Returns a reference to the inner value.
387    #[inline]
388    pub fn into_inner(self) -> &'w T {
389        self.value
390    }
391}
392
393impl<T: Resource> Deref for Res<'_, T> {
394    type Target = T;
395
396    #[inline]
397    fn deref(&self) -> &Self::Target {
398        self.value
399    }
400}
401
402impl<T: Resource + fmt::Debug> fmt::Debug for Res<'_, T> {
403    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
404        f.debug_tuple("Res").field(&self.value).finish()
405    }
406}
407
408// Clone for Res - it's just a reference, so this is cheap
409impl<T: Resource> Clone for Res<'_, T> {
410    #[inline]
411    fn clone(&self) -> Self {
412        *self
413    }
414}
415
416impl<T: Resource> Copy for Res<'_, T> {}
417
418// =============================================================================
419// ResMut<T> - Mutable Resource Access
420// =============================================================================
421
422/// Mutable access to a resource of type `T`.
423///
424/// `ResMut<T>` provides read-write access to a resource stored in the World.
425/// It implements `Deref` and `DerefMut`, so you can access the inner value directly.
426///
427/// # Panics
428///
429/// Operations on `ResMut<T>` will panic if the resource doesn't exist.
430/// Use `Option<ResMut<T>>` for optional access (future).
431///
432/// # Example
433///
434/// ```ignore
435/// fn update_time(mut time: ResMut<Time>, delta: f32) {
436///     time.delta = delta;
437///     time.total += delta;
438/// }
439/// ```
440///
441/// # Thread Safety
442///
443/// Only one `ResMut<T>` can exist at a time for a given resource type.
444/// It conflicts with both `Res<T>` and `ResMut<T>` on the same type.
445pub struct ResMut<'w, T: Resource> {
446    value: &'w mut T,
447}
448
449impl<'w, T: Resource> ResMut<'w, T> {
450    /// Creates a new `ResMut` from a mutable reference.
451    ///
452    /// This is primarily used internally by the system parameter infrastructure.
453    #[inline]
454    pub fn new(value: &'w mut T) -> Self {
455        Self { value }
456    }
457
458    /// Returns a mutable reference to the inner value.
459    #[inline]
460    pub fn into_inner(self) -> &'w mut T {
461        self.value
462    }
463}
464
465impl<T: Resource> Deref for ResMut<'_, T> {
466    type Target = T;
467
468    #[inline]
469    fn deref(&self) -> &Self::Target {
470        self.value
471    }
472}
473
474impl<T: Resource> DerefMut for ResMut<'_, T> {
475    #[inline]
476    fn deref_mut(&mut self) -> &mut Self::Target {
477        self.value
478    }
479}
480
481impl<T: Resource + fmt::Debug> fmt::Debug for ResMut<'_, T> {
482    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
483        f.debug_tuple("ResMut").field(&self.value).finish()
484    }
485}
486
487// =============================================================================
488// Non-Send Resources
489// =============================================================================
490
491/// Marker trait for types that can be used as non-send resources.
492///
493/// Non-send resources are resources that cannot be safely sent between threads.
494/// Unlike regular [`Resource`], non-send resources only require `'static`.
495///
496/// # Use Cases
497///
498/// Non-send resources are useful for:
499///
500/// - **Raw pointers**: Window handles, OpenGL contexts, etc.
501/// - **Thread-local data**: Data bound to a specific thread
502/// - **Rc/RefCell types**: Reference-counted non-atomic types
503/// - **Platform-specific handles**: OS handles that are thread-affine
504///
505/// # Example
506///
507/// ```
508/// use goud_engine::ecs::resource::NonSendResource;
509/// use std::rc::Rc;
510/// use std::cell::RefCell;
511///
512/// // This type is NOT Send because of Rc
513/// struct WindowHandle {
514///     id: Rc<RefCell<u32>>,
515/// }
516///
517/// // Explicit implementation required
518/// impl NonSendResource for WindowHandle {}
519/// ```
520///
521/// # Thread Safety
522///
523/// Non-send resources must only be accessed from the main thread.
524/// The scheduler ensures non-send systems run on the main thread.
525///
526/// # Differences from Resource
527///
528/// | Aspect | Resource | NonSendResource |
529/// |--------|----------|-----------------|
530/// | Thread-safe | Yes (Send + Sync) | No |
531/// | System access | Any thread | Main thread only |
532/// | Storage | `Resources` | `NonSendResources` |
533/// | Wrapper | `Res<T>`, `ResMut<T>` | `NonSend<T>`, `NonSendMut<T>` |
534pub trait NonSendResource: 'static {}
535
536// NOTE: No blanket implementation - types must explicitly opt-in to non-send
537// resources. This is intentional to prevent accidentally using non-thread-safe
538// types as regular resources.
539
540// =============================================================================
541// NonSendResourceId
542// =============================================================================
543
544/// Unique identifier for a non-send resource type.
545///
546/// Like [`ResourceId`] but for non-send resources. Used internally
547/// for storage and access conflict detection.
548#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
549pub struct NonSendResourceId(TypeId);
550
551impl NonSendResourceId {
552    /// Returns the `NonSendResourceId` for a specific type.
553    #[inline]
554    pub fn of<T: 'static>() -> Self {
555        Self(TypeId::of::<T>())
556    }
557
558    /// Returns the underlying `TypeId`.
559    #[inline]
560    pub fn type_id(&self) -> TypeId {
561        self.0
562    }
563}
564
565impl fmt::Debug for NonSendResourceId {
566    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
567        write!(f, "NonSendResourceId({:?})", self.0)
568    }
569}
570
571// =============================================================================
572// NonSendResources Container
573// =============================================================================
574
575/// Marker type that prevents a struct from implementing `Send` or `Sync`.
576///
577/// This is used to ensure `NonSendResources` cannot be sent between threads.
578/// The `*const ()` raw pointer makes the containing type `!Send` and `!Sync`.
579pub struct NonSendMarker(std::marker::PhantomData<*const ()>);
580
581// Safety: NonSendMarker is intentionally NOT Send or Sync.
582// This is a marker type used to "infect" containing types.
583
584impl Default for NonSendMarker {
585    fn default() -> Self {
586        Self(std::marker::PhantomData)
587    }
588}
589
590impl fmt::Debug for NonSendMarker {
591    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
592        write!(f, "NonSendMarker")
593    }
594}
595
596/// Storage container for non-send resources.
597///
598/// Unlike [`Resources`], this container stores resources that are NOT `Send + Sync`.
599/// These resources must only be accessed from the thread they were created on
600/// (typically the main thread).
601///
602/// # Thread Safety
603///
604/// This container is NOT `Send` or `Sync`. It must remain on the main thread.
605/// The scheduler ensures that systems using non-send resources run on the main thread.
606///
607/// # Example
608///
609/// ```
610/// use goud_engine::ecs::resource::{NonSendResources, NonSendResource};
611/// use std::rc::Rc;
612///
613/// struct RawPointerResource {
614///     ptr: *mut u32,
615/// }
616/// impl NonSendResource for RawPointerResource {}
617///
618/// let mut resources = NonSendResources::new();
619///
620/// let mut value = 42u32;
621/// resources.insert(RawPointerResource { ptr: &mut value as *mut u32 });
622///
623/// assert!(resources.contains::<RawPointerResource>());
624/// ```
625#[derive(Default)]
626pub struct NonSendResources {
627    /// Type-erased non-send resource storage.
628    /// Note: Uses `Box<dyn Any>` NOT `Box<dyn Any + Send + Sync>`.
629    data: HashMap<NonSendResourceId, Box<dyn Any>>,
630    /// Marker to make this type !Send and !Sync.
631    _marker: NonSendMarker,
632}
633
634impl NonSendResources {
635    /// Creates an empty non-send resources container.
636    #[inline]
637    pub fn new() -> Self {
638        Self {
639            data: HashMap::new(),
640            _marker: NonSendMarker::default(),
641        }
642    }
643
644    /// Inserts a non-send resource into the container.
645    ///
646    /// If a resource of this type already exists, it is replaced and the
647    /// old value is returned.
648    ///
649    /// # Arguments
650    ///
651    /// * `resource` - The resource to insert
652    ///
653    /// # Returns
654    ///
655    /// `Some(T)` if a resource of this type was replaced, `None` otherwise.
656    #[inline]
657    pub fn insert<T: NonSendResource>(&mut self, resource: T) -> Option<T> {
658        let id = NonSendResourceId::of::<T>();
659        let old = self.data.insert(id, Box::new(resource));
660        old.and_then(|boxed| boxed.downcast::<T>().ok().map(|b| *b))
661    }
662
663    /// Removes a non-send resource from the container.
664    ///
665    /// # Returns
666    ///
667    /// `Some(T)` if the resource existed, `None` otherwise.
668    #[inline]
669    pub fn remove<T: NonSendResource>(&mut self) -> Option<T> {
670        let id = NonSendResourceId::of::<T>();
671        self.data
672            .remove(&id)
673            .and_then(|boxed| boxed.downcast::<T>().ok().map(|b| *b))
674    }
675
676    /// Returns an immutable reference to a non-send resource.
677    ///
678    /// # Returns
679    ///
680    /// `Some(&T)` if the resource exists, `None` otherwise.
681    #[inline]
682    pub fn get<T: NonSendResource>(&self) -> Option<&T> {
683        let id = NonSendResourceId::of::<T>();
684        self.data.get(&id).and_then(|boxed| boxed.downcast_ref())
685    }
686
687    /// Returns a mutable reference to a non-send resource.
688    ///
689    /// # Returns
690    ///
691    /// `Some(&mut T)` if the resource exists, `None` otherwise.
692    #[inline]
693    pub fn get_mut<T: NonSendResource>(&mut self) -> Option<&mut T> {
694        let id = NonSendResourceId::of::<T>();
695        self.data
696            .get_mut(&id)
697            .and_then(|boxed| boxed.downcast_mut())
698    }
699
700    /// Returns `true` if a non-send resource of the specified type exists.
701    #[inline]
702    pub fn contains<T: NonSendResource>(&self) -> bool {
703        self.data.contains_key(&NonSendResourceId::of::<T>())
704    }
705
706    /// Returns the number of non-send resources in the container.
707    #[inline]
708    pub fn len(&self) -> usize {
709        self.data.len()
710    }
711
712    /// Returns `true` if there are no non-send resources.
713    #[inline]
714    pub fn is_empty(&self) -> bool {
715        self.data.is_empty()
716    }
717
718    /// Removes all non-send resources from the container.
719    #[inline]
720    pub fn clear(&mut self) {
721        self.data.clear();
722    }
723}
724
725impl fmt::Debug for NonSendResources {
726    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
727        f.debug_struct("NonSendResources")
728            .field("count", &self.data.len())
729            .finish()
730    }
731}
732
733// NonSendResources is NOT Send or Sync due to NonSendMarker containing *const ()
734// This is verified by compile-time tests in the tests module.
735
736// =============================================================================
737// NonSend<T> - Immutable Non-Send Resource Access
738// =============================================================================
739
740/// Immutable access to a non-send resource of type `T`.
741///
742/// `NonSend<T>` provides read-only access to a non-send resource stored in the World.
743/// It implements `Deref`, so you can access the inner value directly.
744///
745/// # Thread Safety
746///
747/// Systems using `NonSend<T>` are constrained to run on the main thread.
748/// This is enforced by the scheduler at runtime.
749///
750/// # Example
751///
752/// ```ignore
753/// fn print_window_info(window: NonSend<WindowHandle>) {
754///     println!("Window handle: {:?}", window.id);
755/// }
756/// ```
757///
758/// # Panics
759///
760/// Operations on `NonSend<T>` will panic if the resource doesn't exist.
761/// Use `Option<NonSend<T>>` for optional access.
762pub struct NonSend<'w, T: NonSendResource> {
763    value: &'w T,
764}
765
766impl<'w, T: NonSendResource> NonSend<'w, T> {
767    /// Creates a new `NonSend` from a reference.
768    #[inline]
769    pub fn new(value: &'w T) -> Self {
770        Self { value }
771    }
772
773    /// Returns a reference to the inner value.
774    #[inline]
775    pub fn into_inner(self) -> &'w T {
776        self.value
777    }
778}
779
780impl<T: NonSendResource> Deref for NonSend<'_, T> {
781    type Target = T;
782
783    #[inline]
784    fn deref(&self) -> &Self::Target {
785        self.value
786    }
787}
788
789impl<T: NonSendResource + fmt::Debug> fmt::Debug for NonSend<'_, T> {
790    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
791        f.debug_tuple("NonSend").field(&self.value).finish()
792    }
793}
794
795// Clone for NonSend - it's just a reference, so this is cheap
796impl<T: NonSendResource> Clone for NonSend<'_, T> {
797    #[inline]
798    fn clone(&self) -> Self {
799        *self
800    }
801}
802
803impl<T: NonSendResource> Copy for NonSend<'_, T> {}
804
805// =============================================================================
806// NonSendMut<T> - Mutable Non-Send Resource Access
807// =============================================================================
808
809/// Mutable access to a non-send resource of type `T`.
810///
811/// `NonSendMut<T>` provides read-write access to a non-send resource stored in the World.
812/// It implements `Deref` and `DerefMut`, so you can access the inner value directly.
813///
814/// # Thread Safety
815///
816/// Systems using `NonSendMut<T>` are constrained to run on the main thread.
817/// This is enforced by the scheduler at runtime.
818///
819/// # Example
820///
821/// ```ignore
822/// fn update_window(mut window: NonSendMut<WindowHandle>) {
823///     window.update_title("New Title");
824/// }
825/// ```
826///
827/// # Panics
828///
829/// Operations on `NonSendMut<T>` will panic if the resource doesn't exist.
830/// Use `Option<NonSendMut<T>>` for optional access.
831pub struct NonSendMut<'w, T: NonSendResource> {
832    value: &'w mut T,
833}
834
835impl<'w, T: NonSendResource> NonSendMut<'w, T> {
836    /// Creates a new `NonSendMut` from a mutable reference.
837    #[inline]
838    pub fn new(value: &'w mut T) -> Self {
839        Self { value }
840    }
841
842    /// Returns a mutable reference to the inner value.
843    #[inline]
844    pub fn into_inner(self) -> &'w mut T {
845        self.value
846    }
847}
848
849impl<T: NonSendResource> Deref for NonSendMut<'_, T> {
850    type Target = T;
851
852    #[inline]
853    fn deref(&self) -> &Self::Target {
854        self.value
855    }
856}
857
858impl<T: NonSendResource> DerefMut for NonSendMut<'_, T> {
859    #[inline]
860    fn deref_mut(&mut self) -> &mut Self::Target {
861        self.value
862    }
863}
864
865impl<T: NonSendResource + fmt::Debug> fmt::Debug for NonSendMut<'_, T> {
866    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
867        f.debug_tuple("NonSendMut").field(&self.value).finish()
868    }
869}
870
871// =============================================================================
872// Tests
873// =============================================================================
874
875#[cfg(test)]
876mod tests {
877    use super::*;
878
879    // Test resources
880    #[derive(Debug)]
881    struct Time {
882        delta: f32,
883        total: f32,
884    }
885
886    #[derive(Debug)]
887    struct Score(u32);
888
889    #[derive(Debug)]
890    struct Config {
891        debug: bool,
892        volume: f32,
893    }
894
895    // =========================================================================
896    // Resource Trait Tests
897    // =========================================================================
898
899    mod resource_trait {
900        use super::*;
901
902        #[test]
903        fn test_resource_auto_impl() {
904            // Any Send + Sync + 'static type should be a Resource
905            fn requires_resource<T: Resource>() {}
906
907            requires_resource::<Time>();
908            requires_resource::<Score>();
909            requires_resource::<i32>();
910            requires_resource::<String>();
911            requires_resource::<Vec<u8>>();
912        }
913
914        #[test]
915        fn test_resource_is_send() {
916            fn requires_send<T: Send>() {}
917            requires_send::<Time>();
918            requires_send::<Score>();
919        }
920
921        #[test]
922        fn test_resource_is_sync() {
923            fn requires_sync<T: Sync>() {}
924            requires_sync::<Time>();
925            requires_sync::<Score>();
926        }
927    }
928
929    // =========================================================================
930    // ResourceId Tests
931    // =========================================================================
932
933    mod resource_id {
934        use super::*;
935
936        #[test]
937        fn test_resource_id_of() {
938            let id1 = ResourceId::of::<Time>();
939            let id2 = ResourceId::of::<Time>();
940            assert_eq!(id1, id2);
941        }
942
943        #[test]
944        fn test_resource_id_different_types() {
945            let id1 = ResourceId::of::<Time>();
946            let id2 = ResourceId::of::<Score>();
947            assert_ne!(id1, id2);
948        }
949
950        #[test]
951        fn test_resource_id_type_id() {
952            let id = ResourceId::of::<Time>();
953            assert_eq!(id.type_id(), TypeId::of::<Time>());
954        }
955
956        #[test]
957        fn test_resource_id_hash() {
958            use std::collections::HashSet;
959            let mut set = HashSet::new();
960            set.insert(ResourceId::of::<Time>());
961            set.insert(ResourceId::of::<Score>());
962            assert_eq!(set.len(), 2);
963
964            // Same type should not add again
965            set.insert(ResourceId::of::<Time>());
966            assert_eq!(set.len(), 2);
967        }
968
969        #[test]
970        fn test_resource_id_ord() {
971            use std::collections::BTreeSet;
972            let mut set = BTreeSet::new();
973            set.insert(ResourceId::of::<Time>());
974            set.insert(ResourceId::of::<Score>());
975            assert_eq!(set.len(), 2);
976        }
977
978        #[test]
979        fn test_resource_id_debug() {
980            let id = ResourceId::of::<Time>();
981            let debug_str = format!("{:?}", id);
982            assert!(debug_str.contains("ResourceId"));
983        }
984
985        #[test]
986        fn test_resource_id_clone() {
987            let id1 = ResourceId::of::<Time>();
988            let id2 = id1;
989            assert_eq!(id1, id2);
990        }
991    }
992
993    // =========================================================================
994    // Resources Container Tests
995    // =========================================================================
996
997    mod resources_container {
998        use super::*;
999
1000        #[test]
1001        fn test_resources_new() {
1002            let resources = Resources::new();
1003            assert!(resources.is_empty());
1004            assert_eq!(resources.len(), 0);
1005        }
1006
1007        #[test]
1008        fn test_resources_default() {
1009            let resources = Resources::default();
1010            assert!(resources.is_empty());
1011        }
1012
1013        #[test]
1014        fn test_resources_insert() {
1015            let mut resources = Resources::new();
1016            let old = resources.insert(Score(100));
1017            assert!(old.is_none());
1018            assert_eq!(resources.len(), 1);
1019        }
1020
1021        #[test]
1022        fn test_resources_insert_replace() {
1023            let mut resources = Resources::new();
1024            resources.insert(Score(100));
1025            let old = resources.insert(Score(200));
1026            assert!(old.is_some());
1027            assert_eq!(old.unwrap().0, 100);
1028            assert_eq!(resources.get::<Score>().unwrap().0, 200);
1029        }
1030
1031        #[test]
1032        fn test_resources_remove() {
1033            let mut resources = Resources::new();
1034            resources.insert(Score(100));
1035
1036            let removed = resources.remove::<Score>();
1037            assert!(removed.is_some());
1038            assert_eq!(removed.unwrap().0, 100);
1039            assert!(resources.is_empty());
1040        }
1041
1042        #[test]
1043        fn test_resources_remove_nonexistent() {
1044            let mut resources = Resources::new();
1045            let removed = resources.remove::<Score>();
1046            assert!(removed.is_none());
1047        }
1048
1049        #[test]
1050        fn test_resources_get() {
1051            let mut resources = Resources::new();
1052            resources.insert(Score(100));
1053
1054            let score = resources.get::<Score>();
1055            assert!(score.is_some());
1056            assert_eq!(score.unwrap().0, 100);
1057        }
1058
1059        #[test]
1060        fn test_resources_get_nonexistent() {
1061            let resources = Resources::new();
1062            assert!(resources.get::<Score>().is_none());
1063        }
1064
1065        #[test]
1066        fn test_resources_get_mut() {
1067            let mut resources = Resources::new();
1068            resources.insert(Score(100));
1069
1070            let score = resources.get_mut::<Score>().unwrap();
1071            score.0 += 50;
1072
1073            assert_eq!(resources.get::<Score>().unwrap().0, 150);
1074        }
1075
1076        #[test]
1077        fn test_resources_get_mut_nonexistent() {
1078            let mut resources = Resources::new();
1079            assert!(resources.get_mut::<Score>().is_none());
1080        }
1081
1082        #[test]
1083        fn test_resources_contains() {
1084            let mut resources = Resources::new();
1085            assert!(!resources.contains::<Score>());
1086
1087            resources.insert(Score(100));
1088            assert!(resources.contains::<Score>());
1089
1090            resources.remove::<Score>();
1091            assert!(!resources.contains::<Score>());
1092        }
1093
1094        #[test]
1095        fn test_resources_multiple_types() {
1096            let mut resources = Resources::new();
1097            resources.insert(Score(100));
1098            resources.insert(Time {
1099                delta: 0.016,
1100                total: 0.0,
1101            });
1102            resources.insert(Config {
1103                debug: true,
1104                volume: 0.8,
1105            });
1106
1107            assert_eq!(resources.len(), 3);
1108            assert_eq!(resources.get::<Score>().unwrap().0, 100);
1109            assert_eq!(resources.get::<Time>().unwrap().delta, 0.016);
1110            assert!(resources.get::<Config>().unwrap().debug);
1111        }
1112
1113        #[test]
1114        fn test_resources_clear() {
1115            let mut resources = Resources::new();
1116            resources.insert(Score(100));
1117            resources.insert(Time {
1118                delta: 0.016,
1119                total: 0.0,
1120            });
1121
1122            resources.clear();
1123            assert!(resources.is_empty());
1124            assert_eq!(resources.len(), 0);
1125        }
1126
1127        #[test]
1128        fn test_resources_debug() {
1129            let mut resources = Resources::new();
1130            resources.insert(Score(100));
1131
1132            let debug_str = format!("{:?}", resources);
1133            assert!(debug_str.contains("Resources"));
1134            assert!(debug_str.contains("count"));
1135        }
1136    }
1137
1138    // =========================================================================
1139    // Res<T> Tests
1140    // =========================================================================
1141
1142    mod res_tests {
1143        use super::*;
1144
1145        #[test]
1146        fn test_res_new() {
1147            let time = Time {
1148                delta: 0.016,
1149                total: 1.0,
1150            };
1151            let res = Res::new(&time);
1152            assert_eq!(res.delta, 0.016);
1153            assert_eq!(res.total, 1.0);
1154        }
1155
1156        #[test]
1157        fn test_res_deref() {
1158            let score = Score(100);
1159            let res = Res::new(&score);
1160            assert_eq!(res.0, 100);
1161        }
1162
1163        #[test]
1164        fn test_res_into_inner() {
1165            let score = Score(100);
1166            let res = Res::new(&score);
1167            let inner = res.into_inner();
1168            assert_eq!(inner.0, 100);
1169        }
1170
1171        #[test]
1172        fn test_res_debug() {
1173            let score = Score(100);
1174            let res = Res::new(&score);
1175            let debug_str = format!("{:?}", res);
1176            assert!(debug_str.contains("Res"));
1177        }
1178
1179        #[test]
1180        fn test_res_clone() {
1181            let score = Score(100);
1182            let res = Res::new(&score);
1183            let cloned = res;
1184            assert_eq!(cloned.0, 100);
1185        }
1186
1187        #[test]
1188        fn test_res_copy() {
1189            let score = Score(100);
1190            let res = Res::new(&score);
1191            let copied = res;
1192            // Both still valid
1193            assert_eq!(res.0, 100);
1194            assert_eq!(copied.0, 100);
1195        }
1196    }
1197
1198    // =========================================================================
1199    // ResMut<T> Tests
1200    // =========================================================================
1201
1202    mod res_mut_tests {
1203        use super::*;
1204
1205        #[test]
1206        fn test_res_mut_new() {
1207            let mut time = Time {
1208                delta: 0.016,
1209                total: 1.0,
1210            };
1211            let res = ResMut::new(&mut time);
1212            assert_eq!(res.delta, 0.016);
1213            assert_eq!(res.total, 1.0);
1214        }
1215
1216        #[test]
1217        fn test_res_mut_deref() {
1218            let mut score = Score(100);
1219            let res = ResMut::new(&mut score);
1220            assert_eq!(res.0, 100);
1221        }
1222
1223        #[test]
1224        fn test_res_mut_deref_mut() {
1225            let mut score = Score(100);
1226            {
1227                let mut res = ResMut::new(&mut score);
1228                res.0 += 50;
1229            }
1230            assert_eq!(score.0, 150);
1231        }
1232
1233        #[test]
1234        fn test_res_mut_into_inner() {
1235            let mut score = Score(100);
1236            let res = ResMut::new(&mut score);
1237            let inner = res.into_inner();
1238            inner.0 += 50;
1239            assert_eq!(score.0, 150);
1240        }
1241
1242        #[test]
1243        fn test_res_mut_debug() {
1244            let mut score = Score(100);
1245            let res = ResMut::new(&mut score);
1246            let debug_str = format!("{:?}", res);
1247            assert!(debug_str.contains("ResMut"));
1248        }
1249
1250        #[test]
1251        fn test_res_mut_modify_complex() {
1252            let mut time = Time {
1253                delta: 0.016,
1254                total: 0.0,
1255            };
1256
1257            {
1258                let mut res = ResMut::new(&mut time);
1259                res.total += res.delta;
1260            }
1261
1262            assert_eq!(time.total, 0.016);
1263        }
1264    }
1265
1266    // =========================================================================
1267    // Integration Tests
1268    // =========================================================================
1269
1270    mod integration {
1271        use super::*;
1272
1273        #[test]
1274        fn test_resources_with_res() {
1275            let mut resources = Resources::new();
1276            resources.insert(Score(100));
1277
1278            let score_ref = resources.get::<Score>().unwrap();
1279            let res = Res::new(score_ref);
1280
1281            assert_eq!(res.0, 100);
1282        }
1283
1284        #[test]
1285        fn test_resources_with_res_mut() {
1286            let mut resources = Resources::new();
1287            resources.insert(Score(100));
1288
1289            {
1290                let score_ref = resources.get_mut::<Score>().unwrap();
1291                let mut res = ResMut::new(score_ref);
1292                res.0 += 50;
1293            }
1294
1295            assert_eq!(resources.get::<Score>().unwrap().0, 150);
1296        }
1297
1298        #[test]
1299        fn test_resource_lifecycle() {
1300            let mut resources = Resources::new();
1301
1302            // Insert
1303            resources.insert(Score(0));
1304            assert!(resources.contains::<Score>());
1305
1306            // Modify
1307            resources.get_mut::<Score>().unwrap().0 = 100;
1308
1309            // Read
1310            assert_eq!(resources.get::<Score>().unwrap().0, 100);
1311
1312            // Replace
1313            resources.insert(Score(200));
1314            assert_eq!(resources.get::<Score>().unwrap().0, 200);
1315
1316            // Remove
1317            let removed = resources.remove::<Score>();
1318            assert_eq!(removed.unwrap().0, 200);
1319            assert!(!resources.contains::<Score>());
1320        }
1321    }
1322
1323    // =========================================================================
1324    // Thread Safety Tests
1325    // =========================================================================
1326
1327    mod thread_safety {
1328        use super::*;
1329
1330        #[test]
1331        fn test_resources_is_send() {
1332            fn requires_send<T: Send>() {}
1333            requires_send::<Resources>();
1334        }
1335
1336        #[test]
1337        fn test_res_is_send() {
1338            fn requires_send<T: Send>() {}
1339            // Res is Send if T is Send
1340            fn check<T: Resource>() {
1341                // Can't directly check Res<'_, T> for Send due to lifetime
1342                // but the underlying reference is Send if T is Sync
1343            }
1344            check::<Score>();
1345        }
1346
1347        #[test]
1348        fn test_res_mut_is_send() {
1349            fn requires_send<T: Send>() {}
1350            // ResMut is Send if T is Send
1351            fn check<T: Resource>() {
1352                // Can't directly check ResMut<'_, T> for Send due to lifetime
1353            }
1354            check::<Score>();
1355        }
1356    }
1357
1358    // =========================================================================
1359    // Non-Send Resource Tests
1360    // =========================================================================
1361
1362    mod non_send_resources {
1363        use super::*;
1364        use std::cell::RefCell;
1365        use std::rc::Rc;
1366
1367        // Non-send test resources
1368        struct WindowHandle {
1369            id: Rc<u32>,
1370        }
1371        impl NonSendResource for WindowHandle {}
1372
1373        struct OpenGLContext {
1374            ctx: Rc<RefCell<u32>>,
1375        }
1376        impl NonSendResource for OpenGLContext {}
1377
1378        struct RawPointerResource {
1379            ptr: *mut u32,
1380        }
1381        impl NonSendResource for RawPointerResource {}
1382
1383        // =====================================================================
1384        // NonSendResourceId Tests
1385        // =====================================================================
1386
1387        #[test]
1388        fn test_non_send_resource_id_of() {
1389            let id1 = NonSendResourceId::of::<WindowHandle>();
1390            let id2 = NonSendResourceId::of::<WindowHandle>();
1391            assert_eq!(id1, id2);
1392        }
1393
1394        #[test]
1395        fn test_non_send_resource_id_different_types() {
1396            let id1 = NonSendResourceId::of::<WindowHandle>();
1397            let id2 = NonSendResourceId::of::<OpenGLContext>();
1398            assert_ne!(id1, id2);
1399        }
1400
1401        #[test]
1402        fn test_non_send_resource_id_type_id() {
1403            let id = NonSendResourceId::of::<WindowHandle>();
1404            assert_eq!(id.type_id(), TypeId::of::<WindowHandle>());
1405        }
1406
1407        #[test]
1408        fn test_non_send_resource_id_hash() {
1409            use std::collections::HashSet;
1410            let mut set = HashSet::new();
1411            set.insert(NonSendResourceId::of::<WindowHandle>());
1412            set.insert(NonSendResourceId::of::<OpenGLContext>());
1413            assert_eq!(set.len(), 2);
1414        }
1415
1416        #[test]
1417        fn test_non_send_resource_id_ord() {
1418            use std::collections::BTreeSet;
1419            let mut set = BTreeSet::new();
1420            set.insert(NonSendResourceId::of::<WindowHandle>());
1421            set.insert(NonSendResourceId::of::<OpenGLContext>());
1422            assert_eq!(set.len(), 2);
1423        }
1424
1425        #[test]
1426        fn test_non_send_resource_id_debug() {
1427            let id = NonSendResourceId::of::<WindowHandle>();
1428            let debug_str = format!("{:?}", id);
1429            assert!(debug_str.contains("NonSendResourceId"));
1430        }
1431
1432        // =====================================================================
1433        // NonSendResources Container Tests
1434        // =====================================================================
1435
1436        #[test]
1437        fn test_non_send_resources_new() {
1438            let resources = NonSendResources::new();
1439            assert!(resources.is_empty());
1440            assert_eq!(resources.len(), 0);
1441        }
1442
1443        #[test]
1444        fn test_non_send_resources_default() {
1445            let resources = NonSendResources::default();
1446            assert!(resources.is_empty());
1447        }
1448
1449        #[test]
1450        fn test_non_send_resources_insert() {
1451            let mut resources = NonSendResources::new();
1452            let old = resources.insert(WindowHandle { id: Rc::new(42) });
1453            assert!(old.is_none());
1454            assert_eq!(resources.len(), 1);
1455        }
1456
1457        #[test]
1458        fn test_non_send_resources_insert_replace() {
1459            let mut resources = NonSendResources::new();
1460            resources.insert(WindowHandle { id: Rc::new(42) });
1461            let old = resources.insert(WindowHandle { id: Rc::new(100) });
1462            assert!(old.is_some());
1463            assert_eq!(*old.unwrap().id, 42);
1464            assert_eq!(*resources.get::<WindowHandle>().unwrap().id, 100);
1465        }
1466
1467        #[test]
1468        fn test_non_send_resources_remove() {
1469            let mut resources = NonSendResources::new();
1470            resources.insert(WindowHandle { id: Rc::new(42) });
1471
1472            let removed = resources.remove::<WindowHandle>();
1473            assert!(removed.is_some());
1474            assert_eq!(*removed.unwrap().id, 42);
1475            assert!(resources.is_empty());
1476        }
1477
1478        #[test]
1479        fn test_non_send_resources_remove_nonexistent() {
1480            let mut resources = NonSendResources::new();
1481            let removed = resources.remove::<WindowHandle>();
1482            assert!(removed.is_none());
1483        }
1484
1485        #[test]
1486        fn test_non_send_resources_get() {
1487            let mut resources = NonSendResources::new();
1488            resources.insert(WindowHandle { id: Rc::new(42) });
1489
1490            let handle = resources.get::<WindowHandle>();
1491            assert!(handle.is_some());
1492            assert_eq!(*handle.unwrap().id, 42);
1493        }
1494
1495        #[test]
1496        fn test_non_send_resources_get_nonexistent() {
1497            let resources = NonSendResources::new();
1498            assert!(resources.get::<WindowHandle>().is_none());
1499        }
1500
1501        #[test]
1502        fn test_non_send_resources_get_mut() {
1503            let mut resources = NonSendResources::new();
1504            resources.insert(OpenGLContext {
1505                ctx: Rc::new(RefCell::new(1)),
1506            });
1507
1508            let ctx = resources.get_mut::<OpenGLContext>().unwrap();
1509            *ctx.ctx.borrow_mut() = 42;
1510
1511            assert_eq!(*resources.get::<OpenGLContext>().unwrap().ctx.borrow(), 42);
1512        }
1513
1514        #[test]
1515        fn test_non_send_resources_contains() {
1516            let mut resources = NonSendResources::new();
1517            assert!(!resources.contains::<WindowHandle>());
1518
1519            resources.insert(WindowHandle { id: Rc::new(42) });
1520            assert!(resources.contains::<WindowHandle>());
1521
1522            resources.remove::<WindowHandle>();
1523            assert!(!resources.contains::<WindowHandle>());
1524        }
1525
1526        #[test]
1527        fn test_non_send_resources_multiple_types() {
1528            let mut resources = NonSendResources::new();
1529            resources.insert(WindowHandle { id: Rc::new(1) });
1530            resources.insert(OpenGLContext {
1531                ctx: Rc::new(RefCell::new(2)),
1532            });
1533
1534            assert_eq!(resources.len(), 2);
1535            assert_eq!(*resources.get::<WindowHandle>().unwrap().id, 1);
1536            assert_eq!(*resources.get::<OpenGLContext>().unwrap().ctx.borrow(), 2);
1537        }
1538
1539        #[test]
1540        fn test_non_send_resources_clear() {
1541            let mut resources = NonSendResources::new();
1542            resources.insert(WindowHandle { id: Rc::new(1) });
1543            resources.insert(OpenGLContext {
1544                ctx: Rc::new(RefCell::new(2)),
1545            });
1546
1547            resources.clear();
1548            assert!(resources.is_empty());
1549            assert_eq!(resources.len(), 0);
1550        }
1551
1552        #[test]
1553        fn test_non_send_resources_debug() {
1554            let mut resources = NonSendResources::new();
1555            resources.insert(WindowHandle { id: Rc::new(42) });
1556
1557            let debug_str = format!("{:?}", resources);
1558            assert!(debug_str.contains("NonSendResources"));
1559            assert!(debug_str.contains("count"));
1560        }
1561
1562        #[test]
1563        fn test_non_send_resources_with_raw_pointer() {
1564            let mut value = 42u32;
1565            let mut resources = NonSendResources::new();
1566            resources.insert(RawPointerResource {
1567                ptr: &mut value as *mut u32,
1568            });
1569
1570            let res = resources.get::<RawPointerResource>().unwrap();
1571            assert!(!res.ptr.is_null());
1572        }
1573
1574        // =====================================================================
1575        // NonSendResources Thread Safety Tests
1576        // =====================================================================
1577
1578        #[test]
1579        fn test_non_send_resources_is_not_send() {
1580            // NonSendResources should NOT implement Send
1581            fn check_not_send<T>() {
1582                // This is a compile-time check - the test passes by compiling
1583                // We can't easily test !Send at runtime
1584            }
1585            check_not_send::<NonSendResources>();
1586            // The actual !Send is enforced by the NonSendMarker containing *const ()
1587        }
1588
1589        #[test]
1590        fn test_non_send_resources_is_not_sync() {
1591            // NonSendResources should NOT implement Sync
1592            fn check_not_sync<T>() {
1593                // This is a compile-time check - the test passes by compiling
1594                // We can't easily test !Sync at runtime
1595            }
1596            check_not_sync::<NonSendResources>();
1597            // The actual !Sync is enforced by the NonSendMarker containing *const ()
1598        }
1599
1600        // =====================================================================
1601        // NonSend<T> and NonSendMut<T> Wrapper Tests
1602        // =====================================================================
1603
1604        #[test]
1605        fn test_non_send_new() {
1606            let handle = WindowHandle { id: Rc::new(42) };
1607            let non_send = NonSend::new(&handle);
1608            assert_eq!(*non_send.id, 42);
1609        }
1610
1611        #[test]
1612        fn test_non_send_deref() {
1613            let handle = WindowHandle { id: Rc::new(42) };
1614            let non_send = NonSend::new(&handle);
1615            assert_eq!(*non_send.id, 42);
1616        }
1617
1618        #[test]
1619        fn test_non_send_into_inner() {
1620            let handle = WindowHandle { id: Rc::new(42) };
1621            let non_send = NonSend::new(&handle);
1622            let inner = non_send.into_inner();
1623            assert_eq!(*inner.id, 42);
1624        }
1625
1626        #[test]
1627        fn test_non_send_clone() {
1628            let handle = WindowHandle { id: Rc::new(42) };
1629            let non_send = NonSend::new(&handle);
1630            let cloned = non_send;
1631            // Both should be valid
1632            assert_eq!(*non_send.id, 42);
1633            assert_eq!(*cloned.id, 42);
1634        }
1635
1636        #[test]
1637        fn test_non_send_copy() {
1638            let handle = WindowHandle { id: Rc::new(42) };
1639            let non_send = NonSend::new(&handle);
1640            let copied = non_send;
1641            // Both should still be valid
1642            assert_eq!(*non_send.id, 42);
1643            assert_eq!(*copied.id, 42);
1644        }
1645
1646        #[test]
1647        fn test_non_send_mut_new() {
1648            let mut ctx = OpenGLContext {
1649                ctx: Rc::new(RefCell::new(1)),
1650            };
1651            let non_send_mut = NonSendMut::new(&mut ctx);
1652            assert_eq!(*non_send_mut.ctx.borrow(), 1);
1653        }
1654
1655        #[test]
1656        fn test_non_send_mut_deref() {
1657            let mut ctx = OpenGLContext {
1658                ctx: Rc::new(RefCell::new(1)),
1659            };
1660            let non_send_mut = NonSendMut::new(&mut ctx);
1661            assert_eq!(*non_send_mut.ctx.borrow(), 1);
1662        }
1663
1664        #[test]
1665        fn test_non_send_mut_deref_mut() {
1666            let mut ctx = OpenGLContext {
1667                ctx: Rc::new(RefCell::new(1)),
1668            };
1669            {
1670                let mut non_send_mut = NonSendMut::new(&mut ctx);
1671                *non_send_mut.ctx.borrow_mut() = 42;
1672            }
1673            assert_eq!(*ctx.ctx.borrow(), 42);
1674        }
1675
1676        #[test]
1677        fn test_non_send_mut_into_inner() {
1678            let mut ctx = OpenGLContext {
1679                ctx: Rc::new(RefCell::new(1)),
1680            };
1681            let non_send_mut = NonSendMut::new(&mut ctx);
1682            let inner = non_send_mut.into_inner();
1683            *inner.ctx.borrow_mut() = 42;
1684            assert_eq!(*ctx.ctx.borrow(), 42);
1685        }
1686
1687        // =====================================================================
1688        // Integration Tests
1689        // =====================================================================
1690
1691        #[test]
1692        fn test_non_send_resource_lifecycle() {
1693            let mut resources = NonSendResources::new();
1694
1695            // Insert
1696            resources.insert(WindowHandle { id: Rc::new(0) });
1697            assert!(resources.contains::<WindowHandle>());
1698
1699            // Modify (via Rc)
1700            let id = resources.get::<WindowHandle>().unwrap().id.clone();
1701            assert_eq!(*id, 0);
1702
1703            // Replace
1704            resources.insert(WindowHandle { id: Rc::new(42) });
1705            assert_eq!(*resources.get::<WindowHandle>().unwrap().id, 42);
1706
1707            // Remove
1708            let removed = resources.remove::<WindowHandle>();
1709            assert_eq!(*removed.unwrap().id, 42);
1710            assert!(!resources.contains::<WindowHandle>());
1711        }
1712    }
1713}