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
128
129
130
131
132
133
134
135
136
use super::{Sealed, Ty, TyEnd};

use core::any::Any;

/// The ContainsMut trait marks a map as containing at least one instance of a given type that can be mutated
///
/// ```
/// use typemap_core::{typemap, TypeMapGet, ContainsMut};
/// fn modifies_u32<Opts: ContainsMut<u32>>(opts: &mut Opts) {
///     opts.set::<u32>(1337);
/// }
///
/// let mut map = typemap!(u32 = 42u32);
/// modifies_u32(&mut map);
/// println!("{}", map.get::<u32>());
/// ```
///
/// On nightly, this trait functions as intended with the help of an unstable feature.
/// Unfortunately, it cannot be implemented as intended on stable at the moment,
/// so it is given a blanket implementation to ensure that bounds that work on nightly
/// do not cause errors on stable.
// Each implementation of ContainsMut corresponds with an implementation of TypeMapSet
#[cfg_attr(nightly, marker)]
pub trait ContainsMut<T>: TypeMapSet {}

// TODO: more fleshed out trait documentation
/// The TypeMapSet trait allows for setting values of types in a typemap.
pub trait TypeMapSet: Sealed {
    /// Attempts to mutably set a value of a given type in the map.
    ///
    /// This is mainly intended for the case where you don't require a type to be present,
    /// but would like to act on it if it is.
    /// Returns [`false`] if the type is not present in the map.
    /// On nightly, this should only occur if [`ContainsMut<T>`] is not implemented.
    ///
    /// ```
    /// use typemap_core::{typemap, TypeMapGet, TypeMapSet};
    ///
    /// let mut map = typemap!(u32 = 13u32);
    /// assert!(map.try_set(42u32));
    /// assert_eq!(map.get::<u32>(), &42);
    ///
    /// // type is not present in map
    /// assert!(!map.try_set(1u128));
    /// ```
    fn try_set<T: 'static>(&mut self, value: T) -> bool;

    /// Mutable sets a value of a given type in the map.
    ///
    /// On nightly, you can only call this method if the type is actually present.
    /// (i.e. the map implements implements [`ContainsMut<T>`])
    ///
    /// # Panics
    ///
    /// This function panics if [`try_set`] would return [`false`].
    /// This should only be possible on stable,
    /// so you can weed out potential panics by occasionally checking against nightly.
    ///
    /// ```
    /// use typemap_core::{typemap, TypeMapGet, TypeMapSet};
    ///
    /// let mut map = typemap!(&str = "");
    /// map.set("Hello, world!");
    /// println!("{}", map.get::<&str>());
    /// ```
    ///
    /// [`try_set`]: #tymethod.try_set
    fn set<T: 'static>(&mut self, value: T)
    where
        Self: ContainsMut<T>,
    {
        assert!(
            self.try_set(value),
            "Cannot set type! Check for errors at compile-time by using nightly."
        )
    }
}

// # Terminating Impls -- You can't set any items on or beyond these types.

impl TypeMapSet for TyEnd {
    fn try_set<T: 'static>(&mut self, _value: T) -> bool {
        false
    }
}

impl<V: 'static, R: TypeMapSet> TypeMapSet for &Ty<V, R> {
    fn try_set<T: 'static>(&mut self, _value: T) -> bool {
        false
    }
}

// # End terminating impls
// # Recursive Impl -- We are either setting the current item or delegating to the inner type.

// on nightly, when ContainsMut<T> is implemented, TypeMapSet::try_set should never return false
#[cfg(nightly)]
mod nightly_impls {
    use super::{ContainsMut, Ty, TypeMapSet};

    impl<A: 'static, R: TypeMapSet> ContainsMut<A> for Ty<A, R> {}
    // TODO: use BorrowMut?
    impl<A: 'static, B: 'static, R: ContainsMut<B>> ContainsMut<B> for Ty<A, R> {}
}

// on stable, we can't properly constrain the trait, so we just do a blanket impl and let it panic at runtime.
#[cfg(not(nightly))]
impl<A: 'static, B: 'static, R: TypeMapSet> ContainsMut<A> for Ty<B, R> {}

// TODO: use BorrowMut?
impl<V: 'static, R: TypeMapSet> TypeMapSet for Ty<V, R> {
    fn try_set<T: 'static>(&mut self, value: T) -> bool {
        if let Some(val) = Any::downcast_mut(&mut self.val) {
            *val = value;
            true
        } else {
            self.rest.try_set(value)
        }
    }
}

// # End impls on Ty<V, R>
// # Reference Impl -- Thin shim that delegates to the Recursive Impl for mutable references

impl<A: 'static, B: 'static, R: TypeMapSet> ContainsMut<A> for &mut Ty<B, R> where
    Ty<B, R>: TypeMapSet + ContainsMut<A>
{
}

impl<V: 'static, R: TypeMapSet> TypeMapSet for &mut Ty<V, R> {
    fn try_set<T: 'static>(&mut self, value: T) -> bool {
        (**self).try_set(value)
    }
}

// # End Reference Impl