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
#![no_std]
use core::cell::RefCell;
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;

pub trait AddClassList<'a> {
    fn insert_into_list(&'a self, list: &'a ClassList<'a>);
}

impl<'a> AddClassList<'a> for &str {
    fn insert_into_list(&'a self, list: &'a ClassList<'a>) {
        list.classes.borrow_mut().push(self);
    }
}

impl<'a> AddClassList<'a> for Option<&str> {
    fn insert_into_list(&'a self, list: &'a ClassList<'a>) {
        match self {
            Some(t) => list.classes.borrow_mut().push(t),
            None => (),
        };
    }
}

pub struct ClassList<'a> {
    classes: RefCell<Vec<&'a str>>,
}

impl<'a> ClassList<'a> {
    pub fn new() -> ClassList<'a> {
        ClassList {
            classes: RefCell::new(Vec::new()),
        }
    }
    pub fn add<T>(&'a self, item: &'a T)
    where
        T: AddClassList<'a>,
    {
        (&item).insert_into_list(self);
    }
    pub fn to_string(&self) -> String {
        self.classes.borrow_mut().join(" ")
    }
}

#[macro_export]
macro_rules! class_names {
    // `()` indicates that the macro takes no argument.
    ($($element:expr),*) => {
        {
            let class_list = ClassList::new();
            $(
                let e = $element;
                class_list.add(&e);
            )*
            class_list.to_string()
        }
    };
}