type_cell 0.3.4

Attach values statically to a type using static get/set methods.
Documentation

Macro to 'attach' values statically to a type using static getter and setter methods.

[dependencies]

type_cell = "0.3"

use type_cell::*;

tycell!{
    {String} 
        [nice_str]
        [lazy_str.clone() -> String {"hello"}]
    {bool > Vec<bool>} 
        [is_nice]
    {!Vec<bool>} 
        [are_nice]
}

fn main(){
    String::set_nice_str("world");
    assert_eq!(
        "hello world",
        &format!("{} {}",&String::lazy_str(),String::nice_str())
    );
}

🧱 Basic Usage

  • Use the macro: tycell!{...}
  • Which type should the value be 'attached' on? u32 {...}
  • Which type does the value have? static u32:
    • Which settings will it use? 🌟 once_read Set it once. Get it read-only! (combine with Mutex/RwLock/... for mutability) 🏁 once_write Set it once. Get it mutable, but risk race conditions! (be sure you win the race!) 🦥 lazy_read Like once_read but set lazy inside the macro! 👹 lazy_writeLike once_write but set lazy inside the macro!!
    • examples: static u32: once_read; or static String: lazy_read;
  • What's the name of the default setter method? set_type()
  • What's the name of the default getter method? get_type()
// Basic Usage 
tycell!{ bool {
    static Vec<bool>: once_read;
    set set_vec();
    get vec();
}}
// Set it somewhere once:
bool::set_vec(Vec::from([true,false,true]));
// Get it anywhere afterwards:
assert_eq!(&[true,false,true],bool::vec().as_slice());

The default setter parameter is a dynamic Into<..> and will use .into(). This means in this example you could also set it like this:

bool::set_vec([true,false,true]);
assert_eq!(&[true,false,true],bool::vec().as_slice());

⚗ Advanced Usage

Multiple Setter and Getter with different parameters and return types can be defined! There are two ways of doing it:

  • Methods:
    • Use inline methods for simple conversions!
    • set set_bool(Option<usize>): do.is_some();
    • get get_bool() -> bool: static.clone();
  • Function:
    • Use a function with correct parameters/return types and is accessible in the same file!
    • Use = before the function meta!
    • set =set_base_fn(a:Option<usize>);
    • get =get_base_fn() -> bool;
// Advanced Usage 
fn set_by_function (a:Option<usize>) -> bool {a.is_some()}
fn get_by_function (a:&bool) -> bool {a.clone()}
tycell!{ bool {
    static bool: once_read;
    set set_raw();
    set set_by_methods(Option<usize>): do.is_some();
    set =set_by_function(a:Option<usize>);
    get get_raw();
    get get_by_methods() -> bool: static.clone();
    get =get_by_function() -> bool;
}}
bool::set_by_methods(None);
assert_eq!(false,bool::get_by_methods());

Methods with parameters are supported in two different ways:

  • Constants:
    • Using = before a constant value!
    • set set_number(u32): do.clamp(=0,=100);
    • get get_number() -> bool: static.clamp(=0,=100);
  • Pass Through:
    • Naming the values with its types will pass it into the function!
    • set set_number(u32): do.clamp(min:u32,max:u32);
    • get get_number() -> bool: static.clamp(min:u32,max:u32);
// Advanced Usage 
tycell!{ u32 {
    static u32: once_read;
    set set_raw();
    set set_by_methods(u32): do.clamp(=0,=100);
    set set_pass(u32): do.clamp(min:u32,max:u32);
    get get_raw();
    get get_by_methods() -> u32: static.add(=5);
    get get_pass() -> u32: static.add(val:u32);
}}
// Sets value to 1000.clamp(0,123) = 123
u32::set_pass(1000,0,123); 
// Gets 123.add(5) = 128
assert_eq!(128,u32::get_by_methods());

🧊 Constant

You can also set const values!

// Constant
tycell!{ u32 {
    const u32 = 100;
    get number();
}}
// Gets 10!
assert_eq!(10,u32::number());

👹 Risky Mutable Options

Only use this if you're sure there are no race conditions (or they don't matter) or for debug purposes! To make the static value mutable, use once_write or lazy_write.

// Risky Mutable
tycell!{ u32 {
    static u32: risky_write;
    set set_number();
    get number();
}}
// Set it somewhere once:
u32::set_number(5u32);
// Default getter is mutable already
*u32::number() = 10;
// Gets 10!
assert_eq!(10,*u32::number());

🦥 As Lazy Static

To create a lazy static value, use the lazy_read option and use a block instead of the setter function!

// Lazy Static
tycell!{ u32 {
    static HashMap<u32,String>: lazy_read;
    set {
        let mut map = HashMap::new();
        for i in 0..100 {
            map.insert(i,i.to_string());
        }
        map
    }
    get get_lazy_map();
    get get_lazy() -> Option<&String>: static.get(id:&u32);
}}
// Gets Some("3":&String)
assert_eq!(&"3",&u32::get_lazy(&3).unwrap());

➡ Simple Mapping

If you only need the default getter and setters, there is a short form:

// Simple Usage
tycell!{
    // store a vec of bools on the bool type
    // a single specifier inside [..] will use once_read
    // adding 'mut' before it sets it to once_write
    // adding a block {} after the specifier will use lazy_.. instead of once_..
    bool > Vec<bool>: [bools] [mut more_bools] [lazy_bools{vec![true,false]}];
    // adding '= value' after the specifier will set a constant value
    bool > u32: [number=100];
}
bool::set_bools([true,false]);
bool::set_more_bools([true,false]);

If you only attach values of the same type as their parent:

// Simplest Usage
tycell!{
    // Same as bool > bool: [is_nice];
    bool: [is_nice];
}

If you want to attach a type to its single generic type, e.g. u32 > Vec<u32> you can use !Vec<u32>. Increase the number of ! to set the level, e.g. u32 > Vec<Vec<u32>> <=> !!Vec<Vec<u32>>.

tycell!{
    !Vec<bool>:[is_nice];
}

You can't mix different types of left-handed syntax, unless wrapped in {}

// working
tycell!{
    {!Vec<bool>} [is_nice]
    {bool>Vec<bool>} [is_v_nice]
    {bool} [is_x_nice]
}
// NOT working
tycell!{
    !Vec<bool>: [is_nice];
    bool>Vec<bool>: [is_v_nice];
    bool: [is_x_nice];
}

You can also chain methods for the getter and adjust its return type.

tycell!{
    {String} 
        [clone_str.clone()->String] 
        [clone_lazy_str.clone()->String{"test"}]
}

➡ Simple (Hash)Maps and Vecs

Ease up getting values from a HasmMap-esque types, by using after the name. if no key is provided, the type is set to a Vec<..> instead.

// uses anythng named TyMap for flaxibility
use std::collections::HashMap as TyMap;
tycell!{
    // same as above, but <keytype> after the specifier
    bool > bool: [bools<u8>] [mut more_bools<u8>] [lazy_bools<u8>{[(1,true)]}];
}
bool::set_bools([(1,true)]);
bool::set_more_bools([(1,true)]);

🔗 Related Projects

  • bevy_cell - Attach bevy Handle and Entity to types.

License