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
//! A no_std typemap with trait-based value-presence guarantees (on nightly)
//!
//! aka: A map from a type to a value of that type, without needing std/alloc
//!
//! # Example
//!
//! ```
//! use typemap_core::{typemap, Contains, TypeMapGet};
//!
//! fn uses_options<Opts: Contains<&'static str> + Contains<u32>>(opts: &Opts) {
//!     println!("str: \"{}\", u32: {}", opts.get::<&str>(), opts.get::<u32>());
//! }
//!
//! let options = typemap!(u128 = 34u128, &str = "Hello, world!", u32 = 45u32);
//! uses_options(&options);
//! ```
//!
//! # Nightly
//! Nightly is not required to use this library, but it is reccomended to at least check your code on nightly
//! occasionally given the nature of the [`Contains<T>`] and [`ContainsMut<T>`] traits.
//! On nightly, these traits ensure that you can only call the methods that panic
//! when they are guaranteed not to panic.
//! On stable, we can't implement it properly, so it merely has a blanket impl so that your trait bounds
//! setup for nightly do not cause issues on stable.
#![no_std]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![cfg_attr(nightly, feature(marker_trait_attr))]
#![doc(html_root_url = "https://docs.rs/typemap_core/0.1.0")]

#[macro_use]
mod macros;

mod private {
    use super::{Ty, TyEnd};

    pub trait Sealed {}
    impl<T: 'static, R> Sealed for Ty<T, R> {}
    impl<T: 'static, R> Sealed for &Ty<T, R> {}
    impl<T: 'static, R> Sealed for &mut Ty<T, R> {}
    impl Sealed for TyEnd {}
}

mod get;
mod set;

use private::Sealed;

pub use {
    get::{Contains, TypeMapGet},
    set::{ContainsMut, TypeMapSet},
};

/// A type-level linked-list implementation of a typemap
///
/// The generic arguments can be treated as if this were a cons cell. i.e.
/// ```
/// use typemap_core::{Ty, TyEnd};
/// type Example = Ty<u32, Ty<u16, Ty<u8, TyEnd>>>;
/// ```
/// is akin to `(cons u32 (cons u16 (cons u8 nil)))` at the type level,
/// and creates a storage capable of holding a u32, a u16, and a u8.
///
/// A couple of helper macros, [`typemap_ty!()`] and [`typemap!()`] exist, for ease of definition.
/// ```
/// use typemap_core::{typemap, typemap_ty};
/// type Example = typemap_ty!(u32, u16, u8);
/// let example: Example = typemap!(u32 = 0u32, u16 = 1337u16, u8 = 255u8);
/// ```
///
/// As a linked list, it is fairly easy to prepend additional items:
/// ```
/// # use typemap_core::typemap;
/// # let example = typemap!(u32 = 0u32, u16 = 1337u16, u8 = 255u8);
/// let extended = typemap!(&str = "Hello!", ..example);
/// ```
///
/// Which also allows you to "override" existing values temporarilly.
/// ```
/// use typemap_core::{typemap, TypeMapGet};
/// let greeting_options = typemap!(&str = "Hello!");
/// let rude_greeting = typemap!(&str = "Go away.", ..&greeting_options);
/// assert_eq!(rude_greeting.get::<&str>(), &"Go away.");
/// drop(rude_greeting);
/// assert_eq!(greeting_options.get::<&str>(), &"Hello!");
/// ```
///
/// See the [`TypeMapGet`] and [`TypeMapSet`] traits for more details.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub struct Ty<V: 'static, R> {
    val: V,
    rest: R,
}

/// The end of a typemap.
///
/// Following the analogy of [`Ty`] to a cons cell, [`TyEnd`] is akin to nil.
///s
/// See [`Ty`] for more details.
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default)]
pub struct TyEnd;

impl<V: 'static, R> Ty<V, R> {
    /// Construct a node of a typemap
    pub const fn new(val: V, rest: R) -> Self {
        Ty { val, rest }
    }
}

#[cfg(test)]
mod tests {
    use super::{TypeMapGet, TypeMapSet};

    #[test]
    fn test_set_get() {
        let mut test = typemap!(u32 = 32u32, u64 = 64u64);
        assert_eq!(test.get::<u32>(), &32);
        assert_eq!(test.get::<u64>(), &64);

        test.set(1u32);
        test.set(2u64);
        assert_eq!(test.get::<u32>(), &1);
        assert_eq!(test.get::<u64>(), &2);
    }
}