Skip to main content

islet_rmm/
macro.rs

1// TODO: Expands to cover args, ret
2#[macro_export]
3macro_rules! define_interface {
4    (command {$($variant:ident = $val:expr),*,}) => {
5        $(pub const $variant: usize = $val;)*
6        pub fn to_str(code: usize) ->  alloc::string::String {
7            use alloc::string::ToString;
8            use alloc::format;
9            match code {
10                $($variant => stringify!($variant).to_string()),*,
11                _ =>  format!("Undefined {}", code)
12            }
13        }
14    };
15}
16
17#[macro_export]
18macro_rules! print {
19    ($($arg:tt)*) => {
20        let buffer = alloc::format!($($arg)*);
21        let _ = io::stdout().write_all(buffer.as_bytes());
22    };
23}
24
25#[macro_export]
26macro_rules! println {
27    () => {crate::print!("\n")};
28    ($fmt:expr) => {crate::print!(concat!($fmt, "\n"))};
29    ($fmt:expr, $($arg:tt)*) => {crate::print!(concat!($fmt, "\n"), $($arg)*)};
30}
31
32#[macro_export]
33macro_rules! eprint {
34    ($fmt:expr) => {
35        let buffer = concat!("\x1b[0;31m", $fmt, "\x1b[0m");
36        let _ = io::stdout().write_all(buffer.as_bytes());
37    };
38    ($fmt:expr, $($arg:tt)*) => {{
39        let buffer = alloc::format!(concat!("\x1b[0;31m", $fmt, "\x1b[0m"), $($arg)*);
40        let _ = io::stdout().write_all(buffer.as_bytes());
41    }};
42}
43
44#[macro_export]
45macro_rules! eprintln {
46    () => {crate::eprint!("\n")};
47    ($fmt:expr) => {crate::eprint!(concat!($fmt, "\n"))};
48    ($fmt:expr, $($arg:tt)*) => {crate::eprint!(concat!($fmt, "\n"), $($arg)*)};
49}
50
51#[macro_export]
52macro_rules! const_assert {
53    ($cond:expr) => {
54        // Causes overflow if condition is false
55        let _ = [(); 0 - (!($cond) as usize)];
56    };
57}
58
59#[macro_export]
60macro_rules! const_assert_eq {
61    ($left:expr, $right:expr) => {
62        const _: () = {
63            crate::const_assert!($left == $right);
64        };
65    };
66}
67
68#[macro_export]
69macro_rules! const_assert_size {
70    ($struct:ty, $size:expr) => {
71        crate::const_assert_eq!(core::mem::size_of::<$struct>(), ($size));
72    };
73}
74
75#[cfg(test)]
76mod test {
77    extern crate alloc;
78
79    use crate::{eprintln, println};
80    use alloc::boxed::Box;
81    use alloc::string::String;
82    use alloc::vec::Vec;
83    use core::cell::RefCell;
84    use io::{stdout, Write as IoWrite};
85    use io::{ConsoleWriter, Device, Result, Write};
86
87    pub struct MockDevice {
88        buffer: RefCell<Vec<u8>>,
89        ready: bool,
90    }
91
92    impl MockDevice {
93        pub const fn new() -> Self {
94            MockDevice {
95                buffer: RefCell::new(Vec::new()),
96                ready: false,
97            }
98        }
99
100        pub fn output(&self) -> String {
101            String::from_utf8(self.buffer.borrow().to_vec()).unwrap()
102        }
103    }
104
105    impl Device for MockDevice {
106        fn initialize(&mut self) -> Result<()> {
107            self.ready = true;
108            Ok(())
109        }
110
111        fn initialized(&self) -> bool {
112            self.ready
113        }
114    }
115
116    impl Write for MockDevice {
117        fn write_all(&mut self, buf: &[u8]) -> Result<()> {
118            self.buffer.borrow_mut().extend_from_slice(buf);
119            Ok(())
120        }
121    }
122
123    impl ConsoleWriter for MockDevice {}
124
125    #[test]
126    fn println_without_arg() {
127        let mock = Box::new(MockDevice::new());
128        let mock_ptr = mock.as_ref() as *const MockDevice;
129        stdout().attach(mock).ok().unwrap();
130
131        println!();
132
133        assert_eq!(unsafe { (*mock_ptr).output() }, "\n");
134    }
135
136    #[test]
137    fn println_without_format() {
138        let mock = Box::new(MockDevice::new());
139        let mock_ptr = mock.as_ref() as *const MockDevice;
140        stdout().attach(mock).ok().unwrap();
141
142        println!("hello");
143        assert_eq!(unsafe { (*mock_ptr).output() }, "hello\n");
144    }
145
146    #[test]
147    fn println_with_format() {
148        let mock = Box::new(MockDevice::new());
149        let mock_ptr = mock.as_ref() as *const MockDevice;
150        stdout().attach(mock).ok().unwrap();
151
152        println!("number {}", 1234);
153        assert_eq!(unsafe { (*mock_ptr).output() }, "number 1234\n");
154    }
155
156    #[test]
157    fn eprintln_without_arg() {
158        let mock = Box::new(MockDevice::new());
159        let mock_ptr = mock.as_ref() as *const MockDevice;
160        stdout().attach(mock).ok().unwrap();
161
162        eprintln!();
163        assert_eq!(unsafe { (*mock_ptr).output() }, "\x1b[0;31m\n\x1b[0m");
164    }
165
166    #[test]
167    fn eprintln_without_format() {
168        let mock = Box::new(MockDevice::new());
169        let mock_ptr = mock.as_ref() as *const MockDevice;
170        stdout().attach(mock).ok().unwrap();
171
172        eprintln!("hello");
173        assert_eq!(unsafe { (*mock_ptr).output() }, "\x1b[0;31mhello\n\x1b[0m");
174    }
175
176    #[test]
177    fn eprintln_with_format() {
178        let mock = Box::new(MockDevice::new());
179        let mock_ptr = mock.as_ref() as *const MockDevice;
180        stdout().attach(mock).ok().unwrap();
181
182        eprintln!("number {}", 4321);
183        assert_eq!(
184            unsafe { (*mock_ptr).output() },
185            "\x1b[0;31mnumber 4321\n\x1b[0m"
186        );
187    }
188
189    #[test]
190    fn set_of_const_assert() {
191        const_assert!(1 != 2);
192        const_assert!(true);
193
194        const_assert_eq!(1, 1);
195        const_assert_eq!(false, false);
196
197        const_assert_size!(u32, 4);
198        const_assert_size!(u64, 8);
199    }
200}