1#![no_std]
6
7#[allow(unused_extern_crates)]
8extern crate self as kprint;
9
10pub mod backend;
11
12#[doc(hidden)]
13pub use kprint_macro::{__kformat_internal, __kprint_internal, __kprintln_internal};
14
15#[macro_export]
17macro_rules! kprint {
18 ($($tt:tt)*) => {
19 $crate::__kprint_internal!($crate, $($tt)*)
20 };
21}
22
23#[macro_export]
25macro_rules! kprintln {
26 ($($tt:tt)*) => {
27 $crate::__kprintln_internal!($crate, $($tt)*)
28 };
29}
30
31#[macro_export]
33macro_rules! kformat {
34 ($($tt:tt)*) => {
35 $crate::__kformat_internal!($crate, $($tt)*)
36 };
37}
38
39#[cfg(test)]
40mod tests {
41 #[allow(unused_imports)]
42 use super::*;
43
44 #[test]
45 fn test_signed_integers() {
46 let mut buf = [0u8; 256];
47 assert_eq!(kformat!(&mut buf, "val: {}", -12345), b"val: -12345");
48 assert_eq!(kformat!(&mut buf, "val: {:+d}", 42), b"val: +42");
49 assert_eq!(kformat!(&mut buf, "val: {: d}", 42), b"val: 42");
50 assert_eq!(kformat!(&mut buf, "val: '{:<8d}'", 42), b"val: '42 '");
51 assert_eq!(kformat!(&mut buf, "val: '{:>8d}'", 42), b"val: ' 42'");
52 assert_eq!(kformat!(&mut buf, "val: {:05d}", 42), b"val: 00042");
53
54 let val_i8: i8 = -8;
55 let val_i16: i16 = -16;
56 let val_i32: i32 = -32;
57 let val_i64: i64 = -64;
58 let val_isize: isize = -100;
59 assert_eq!(
60 kformat!(&mut buf, "{} {} {} {} {}", &val_i8, &val_i16, val_i32, val_i64, val_isize),
61 b"-8 -16 -32 -64 -100"
62 );
63 assert_eq!(kformat!(&mut buf, "min i64: {}", i64::MIN), b"min i64: -9223372036854775808");
64 }
65
66 #[test]
67 fn test_unsigned_and_hex() {
68 let mut buf = [0u8; 256];
69 assert_eq!(kformat!(&mut buf, "val: {:u}", 12345u32), b"val: 12345");
70 assert_eq!(kformat!(&mut buf, "val: {:x}", 0xabcd), b"val: abcd");
71 assert_eq!(kformat!(&mut buf, "val: {:X}", 0xabcd), b"val: ABCD");
72 assert_eq!(kformat!(&mut buf, "val: {:#x}", 0), b"val: 0x0");
73 assert_eq!(kformat!(&mut buf, "val: {:#x}", 0x2a), b"val: 0x2a");
74 assert_eq!(kformat!(&mut buf, "val: {:#X}", 0x2a), b"val: 0X2A");
75 assert_eq!(kformat!(&mut buf, "val: {:#08X}", 0x1A), b"val: 0X00001A");
76 assert_eq!(kformat!(&mut buf, "val: {:o}", 64), b"val: 100");
77
78 let val_u8: u8 = 8;
79 let val_u16: u16 = 16;
80 let val_u32: u32 = 32;
81 let val_u64: u64 = 64;
82 let val_usize: usize = 128;
83 assert_eq!(
84 kformat!(
85 &mut buf,
86 "{:u} {:u} {:u} {:u} {:u}",
87 &val_u8,
88 val_u16,
89 val_u32,
90 val_u64,
91 val_usize
92 ),
93 b"8 16 32 64 128"
94 );
95 assert_eq!(kformat!(&mut buf, "max u64: {:u}", u64::MAX), b"max u64: 18446744073709551615");
96 }
97
98 #[test]
99 fn test_strings_and_cstrings() {
100 let mut buf = [0u8; 256];
101 assert_eq!(kformat!(&mut buf, "hello {}", "world"), b"hello world");
102 let s = "fuchsia";
103 assert_eq!(kformat!(&mut buf, "os: {:s}", s), b"os: fuchsia");
104 let sub = "pigweed kernel";
105 assert_eq!(kformat!(&mut buf, "sub: {:s}", &sub[0..7]), b"sub: pigweed");
106 assert_eq!(kformat!(&mut buf, "prec: {:.5s}", "123456789"), b"prec: 12345");
107
108 let byte_slice: &[u8] = b"bytes";
109 assert_eq!(kformat!(&mut buf, "raw: {:s}", byte_slice), b"raw: bytes");
110
111 let fixed_array: [u8; 4] = [b'a', b'b', b'c', b'd'];
112 assert_eq!(kformat!(&mut buf, "arr: {:s}", fixed_array), b"arr: abcd");
113
114 let c_str = c"zircon-cstr";
115 assert_eq!(kformat!(&mut buf, "cstr: {:s}", c_str), b"cstr: zircon-cstr");
116
117 let raw_c_ptr = c"raw-c-ptr".as_ptr();
118 assert_eq!(kformat!(&mut buf, "raw_ptr: {:cs}", raw_c_ptr), b"raw_ptr: raw-c-ptr");
119 assert_eq!(kformat!(&mut buf, "aligned: {:<12cs}!", raw_c_ptr), b"aligned: raw-c-ptr !");
120 }
121
122 #[test]
123 fn test_pointers() {
124 let mut buf = [0u8; 256];
125 let val: i32 = 42;
126 let ptr = &val as *const i32;
127 let res = kformat!(&mut buf, "ptr: {:p}", ptr);
128 assert!(res.starts_with(b"ptr: 0x") || res.starts_with(b"ptr: (nil)"));
129
130 let usize_addr: usize = 0x12345678;
131 let res2 = kformat!(&mut buf, "addr: {:p}", usize_addr);
132 let res2_str = core::str::from_utf8(res2).unwrap();
133 assert!(res2_str.contains("12345678"));
134
135 let null_ptr: *const core::ffi::c_void = core::ptr::null();
136 let res_null = kformat!(&mut buf, "null: {:p}", null_ptr);
137 let res_null_str = core::str::from_utf8(res_null).unwrap();
138 assert!(
139 res_null_str.contains("0x0")
140 || res_null_str.contains("(nil)")
141 || res_null_str.contains("00000000")
142 || res_null_str.contains("0")
143 );
144 }
145
146 #[test]
147 fn test_single_evaluation() {
148 let mut buf = [0u8; 256];
149 let mut eval_count = 0;
150 let mut side_effect_fn = || {
151 eval_count += 1;
152 "single_eval"
153 };
154 let res = kformat!(&mut buf, "result: {:s}", side_effect_fn());
155 assert_eq!(res, b"result: single_eval");
156 assert_eq!(eval_count, 1);
157
158 let mut bool_eval_count = 0;
159 let mut bool_side_effect_fn = || {
160 bool_eval_count += 1;
161 true
162 };
163 let res_b = kformat!(&mut buf, "flag: {:b}", bool_side_effect_fn());
164 assert_eq!(res_b, b"flag: true");
165 assert_eq!(bool_eval_count, 1);
166
167 let mut multi_eval_count = 0;
168 let mut multi_side_effect_fn = || {
169 multi_eval_count += 1;
170 100
171 };
172 let res_multi = kformat!(&mut buf, "{0} + {0} = 200", multi_side_effect_fn());
173 assert_eq!(res_multi, b"100 + 100 = 200");
174 assert_eq!(multi_eval_count, 1);
175 }
176
177 #[test]
178 fn test_concat_format_string() {
179 let mut buf = [0u8; 256];
180 let val = 42;
181 assert_eq!(
182 kformat!(&mut buf, concat!("prefix_", "status: ", "{}"), val),
183 b"prefix_status: 42"
184 );
185 assert_eq!(
186 kformat!(&mut buf, concat!("test_", 1, "_", true, "_", 'c', "={}"), 99),
187 b"test_1_true_c=99"
188 );
189 }
190
191 #[test]
192 fn test_captured_and_named_variables() {
193 let mut buf = [0u8; 256];
194 let user = "alice";
195 let score = 100;
196 assert_eq!(
197 kformat!(&mut buf, "player {user:s} has score {score}"),
198 b"player alice has score 100"
199 );
200 assert_eq!(
201 kformat!(&mut buf, "{greeting:s}, {name:s}!", greeting = "hello", name = "world"),
202 b"hello, world!"
203 );
204 }
205
206 #[test]
207 fn test_positional_arguments() {
208 let mut buf = [0u8; 256];
209 assert_eq!(kformat!(&mut buf, "{0} + {1} = {0}", "a", "b"), b"a + b = a");
210 assert_eq!(kformat!(&mut buf, "{1} {0} {1}", 10, 20), b"20 10 20");
211 }
212
213 #[test]
214 fn test_escapes_and_percent() {
215 let mut buf = [0u8; 256];
216 assert_eq!(kformat!(&mut buf, "{{hello}}"), b"{hello}");
217 assert_eq!(kformat!(&mut buf, "100% completed"), b"100% completed");
218 assert_eq!(kformat!(&mut buf, "{}% done", 75), b"75% done");
219 assert_eq!(kformat!(&mut buf, "{{{}%}}", 50), b"{50%}");
220 }
221
222 #[test]
223 fn test_chars() {
224 let mut buf = [0u8; 256];
225 assert_eq!(kformat!(&mut buf, "char: {}", 'Z'), b"char: Z");
226 let c = '?';
227 assert_eq!(kformat!(&mut buf, "char: {:c}", c), b"char: ?");
228 assert_eq!(kformat!(&mut buf, "ref char: {:c}", &c), b"ref char: ?");
229
230 let byte: u8 = b'A';
232 assert_eq!(kformat!(&mut buf, "byte: {:c}", byte), b"byte: A");
233 assert_eq!(kformat!(&mut buf, "ref byte: {:c}", &byte), b"ref byte: A");
234 assert_eq!(kformat!(&mut buf, "byte lit: {:c}", b'K'), b"byte lit: K");
235 assert_eq!(kformat!(&mut buf, "byte lit auto: {}", b'X'), b"byte lit auto: X");
236
237 assert_eq!(kformat!(&mut buf, "crab: {}", '🦀'), "crab: 🦀".as_bytes());
239 assert_eq!(kformat!(&mut buf, "accent: {:c}", 'é'), "accent: é".as_bytes());
240 }
241
242 #[test]
243 fn test_booleans() {
244 let mut buf = [0u8; 256];
245 assert_eq!(kformat!(&mut buf, "flag: {}", true), b"flag: true");
246 assert_eq!(kformat!(&mut buf, "flag: {:b}", false), b"flag: false");
247 }
248
249 #[test]
250 fn test_floats() {
251 let mut buf = [0u8; 256];
252 assert_eq!(kformat!(&mut buf, "pi: {:.2f}", core::f64::consts::PI), b"pi: 3.14");
253 assert_eq!(kformat!(&mut buf, "float: {:.4f}", 1.23456f32), b"float: 1.2346");
254 let f = 1000.0;
255 let res_e = kformat!(&mut buf, "sci: {:.1e}", f);
256 assert_eq!(res_e, b"sci: 1.0e+03");
257 }
258
259 #[test]
260 fn test_buffer_truncation() {
261 let mut small_buf = [0u8; 8];
262 let res = kformat!(&mut small_buf, "1234567890");
263 assert_eq!(res, b"1234567");
264 assert_eq!(res.len(), 7);
265 }
266
267 #[test]
268 fn test_macro_wrapper_hygiene() {
269 macro_rules! wrapped_kformat {
270 ($buf:expr, $($tt:tt)*) => {
271 kformat!($buf, $($tt)*)
272 };
273 }
274 let mut buf = [0u8; 64];
275 let x = 123;
276 assert_eq!(wrapped_kformat!(&mut buf, "val: {}", x), b"val: 123");
277 }
278
279 #[test]
280 fn test_print_macros() {
281 kprint!("test printf {}", 123);
282 kprint!("100%");
283 kprintln!(" line2");
284 kprintln!("empty without args");
285 kprintln!("{:#x}", 0);
286 kprintln!("crab: {}", '🦀');
287 }
288}