summaryrefslogtreecommitdiff
path: root/ecs/src/sole.rs
blob: 82e5e0f712cfb825beb755120efa1687dc0e30ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
use std::any::{Any, type_name};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;

use crate::World;
use crate::lock::{Lock, WriteGuard};
use crate::system::{Metadata as SystemMetadata, Param as SystemParam};

/// A type which has a single instance and is shared globally.
pub trait Sole: Any
{
    fn drop_last(&self) -> bool;

    fn as_any_mut(&mut self) -> &mut dyn Any;

    fn as_any(&self) -> &dyn Any;
}

impl dyn Sole
{
    pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real>
    {
        self.as_any_mut().downcast_mut()
    }

    pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real>
    {
        self.as_any().downcast_ref()
    }
}

impl Debug for dyn Sole
{
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
    {
        formatter.debug_struct("Sole").finish_non_exhaustive()
    }
}

/// Holds a reference to a globally shared singleton value.
#[derive(Debug)]
pub struct Single<'world, SoleT: Sole>
{
    sole: WriteGuard<'world, Box<dyn Sole>>,
    _ph: PhantomData<SoleT>,
}

impl<'world, SoleT> Single<'world, SoleT>
where
    SoleT: Sole,
{
    pub(crate) fn new(sole: &'world Arc<Lock<Box<dyn Sole>>>) -> Self
    {
        Self {
            sole: sole.write_nonblock().unwrap_or_else(|_| {
                panic!(
                    "Failed to aquire read-write lock to single component {}",
                    type_name::<SoleT>()
                )
            }),
            _ph: PhantomData,
        }
    }
}

impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT>
where
    SoleT: Sole,
{
    type Input = ();

    fn new(world: &'world World, _system_metadata: &SystemMetadata) -> Self
    {
        let sole = world.data.sole_storage.get::<SoleT>().unwrap_or_else(|| {
            panic!("Sole {} was not found in world", type_name::<SoleT>())
        });

        Self::new(sole)
    }
}

impl<SoleT> Deref for Single<'_, SoleT>
where
    SoleT: Sole,
{
    type Target = SoleT;

    fn deref(&self) -> &Self::Target
    {
        self.sole.downcast_ref().unwrap()
    }
}

impl<SoleT> DerefMut for Single<'_, SoleT>
where
    SoleT: Sole,
{
    fn deref_mut(&mut self) -> &mut Self::Target
    {
        self.sole.downcast_mut().unwrap()
    }
}