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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use hecs::TypeInfo;
use smallvec::smallvec;
use std::any::type_name;

use crate::borrow::{Borrows, ComponentBorrow};

#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq)]
/// Describes how a type is accessed.
pub struct Access {
    pub(crate) name: &'static str,
    pub(crate) info: TypeInfo,
    pub(crate) exclusive: bool,
}

impl std::fmt::Debug for Access {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if self.exclusive {
            write!(f, "mut {}", self.name)
        } else {
            write!(f, "{}", self.name)
        }
    }
}

impl Access {
    /// Creates a new access from a known  type
    pub fn new<T: IntoAccess>() -> Self {
        T::access()
    }

    /// Get a reference to the access's id.
    #[inline]
    pub fn info(&self) -> TypeInfo {
        self.info
    }

    /// Get a reference to the access's exclusive.
    #[inline]
    pub fn exclusive(&self) -> bool {
        self.exclusive
    }

    pub(crate) fn id(&self) -> std::any::TypeId {
        self.info.id()
    }

    pub(crate) fn name(&self) -> &'static str {
        self.name
    }
}

/// Convert a type into the correspodning access.
pub trait IntoAccess {
    /// Performs the conversion.
    fn access() -> Access;
    /// Check if the borrow is compatible with another borrow.
    fn compatible<U: IntoAccess>() -> bool;
}

impl<T: 'static> IntoAccess for &T {
    fn access() -> Access {
        Access {
            info: TypeInfo::of::<T>(),
            exclusive: false,
            name: type_name::<T>(),
        }
    }

    fn compatible<U: IntoAccess>() -> bool {
        let l = Self::access();
        let r = U::access();

        l.info == r.info && !r.exclusive
    }
}

impl<T: 'static> IntoAccess for &mut T {
    fn access() -> Access {
        Access {
            info: TypeInfo::of::<T>(),
            exclusive: true,
            name: type_name::<T>(),
        }
    }

    fn compatible<U: IntoAccess>() -> bool {
        let l = Self::access();
        let r = U::access();

        l.info == r.info
    }
}

/// Marker type for a subworld which has access to the whole world
pub struct AllAccess;

///Declare subset relations between tuples
pub trait Subset: ComponentBorrow {
    /// Returns true if U is a subset of Self
    fn is_subset<U: ComponentBorrow>() -> bool;
}

impl<A: IntoAccess> Subset for A {
    fn is_subset<U: ComponentBorrow>() -> bool {
        U::has::<A>()
    }
}

impl<A: IntoAccess> ComponentBorrow for A {
    fn borrows() -> Borrows {
        smallvec![A::access()]
    }
    fn has<U: IntoAccess>() -> bool {
        A::compatible::<U>()
    }
}

impl ComponentBorrow for AllAccess {
    fn borrows() -> Borrows {
        smallvec![]
    }

    // Has everything
    fn has<U: IntoAccess>() -> bool {
        true
    }
}