1#![no_std]
6
7#[cfg(test)]
8extern crate std;
9
10#[allow(unused_extern_crates)]
11extern crate self as kprint;
12
13pub mod backend;
14
15#[doc(hidden)]
16pub use kprint_macro::{__kformat_internal, __kprint_internal, __kprintln_internal};
17
18#[macro_export]
20macro_rules! kprint {
21 ($($tt:tt)*) => {
22 $crate::__kprint_internal!($crate, $($tt)*)
23 };
24}
25
26#[macro_export]
28macro_rules! kprintln {
29 ($($tt:tt)*) => {
30 $crate::__kprintln_internal!($crate, $($tt)*)
31 };
32}
33
34#[macro_export]
36macro_rules! kformat {
37 ($($tt:tt)*) => {
38 $crate::__kformat_internal!($crate, $($tt)*)
39 };
40}
41
42#[cfg(test)]
43mod tests {
44 #[allow(unused_imports)]
45 use super::*;
46
47 macro_rules! assert_kformat_eq {
50 ($buf:expr, $expected:expr, $($arg:tt)*) => {{
51 let actual = kformat!($buf, $($arg)*);
52 let std_out = std::format!($($arg)*);
53 assert_eq!(actual, $expected);
54 assert_eq!(
55 core::str::from_utf8(actual).unwrap(),
56 std_out.as_str(),
57 );
58 }};
59 }
60
61 #[test]
62 fn test_signed_integers() {
63 let mut buf = [0u8; 256];
64 assert_kformat_eq!(&mut buf, b"val: -12345", "val: {}", -12345);
65 assert_kformat_eq!(&mut buf, b"val: +42", "val: {:+}", 42);
66 assert_eq!(kformat!(&mut buf, "val: {:+d}", 42), std::format!("val: {:+}", 42).as_bytes());
67 assert_eq!(kformat!(&mut buf, "val: {: d}", 42), b"val: 42");
68 assert_kformat_eq!(&mut buf, b"val: '42 '", "val: '{:<8}'", 42);
69 assert_eq!(
70 kformat!(&mut buf, "val: '{:<8d}'", 42),
71 std::format!("val: '{:<8}'", 42).as_bytes()
72 );
73 assert_kformat_eq!(&mut buf, b"val: ' 42'", "val: '{:>8}'", 42);
74 assert_eq!(
75 kformat!(&mut buf, "val: '{:>8d}'", 42),
76 std::format!("val: '{:>8}'", 42).as_bytes()
77 );
78 assert_kformat_eq!(&mut buf, b"val: ' 42'", "val: '{:8}'", 42);
79 assert_kformat_eq!(&mut buf, b"val: ' 42'", "val: '{:-8}'", 42);
80 assert_kformat_eq!(&mut buf, b"val: 00042", "val: {:05}", 42);
81 assert_eq!(
82 kformat!(&mut buf, "val: {:05d}", 42),
83 std::format!("val: {:05}", 42).as_bytes()
84 );
85 assert_kformat_eq!(&mut buf, b"val: -0000042", "val: {:08}", -42);
86 assert_kformat_eq!(&mut buf, b"val: +0000042", "val: {:+08}", 42);
87 assert_kformat_eq!(&mut buf, b"val: 00000042", "val: {:<08}", 42);
88 assert_kformat_eq!(&mut buf, b"val: 00000042", "val: {:0>8}", 42);
89 assert_kformat_eq!(&mut buf, b"val: 42", "val: {:.5}", 42);
90
91 let val_i8: i8 = -8;
92 let val_i16: i16 = -16;
93 let val_i32: i32 = -32;
94 let val_i64: i64 = -64;
95 let val_isize: isize = -100;
96 assert_kformat_eq!(
97 &mut buf,
98 b"-8 -16 -32 -64 -100",
99 "{} {} {} {} {}",
100 &val_i8,
101 &val_i16,
102 val_i32,
103 val_i64,
104 val_isize
105 );
106 assert_kformat_eq!(&mut buf, b"min i64: -9223372036854775808", "min i64: {}", i64::MIN);
107 }
108
109 #[test]
110 fn test_unsigned_and_hex() {
111 let mut buf = [0u8; 256];
112 assert_kformat_eq!(&mut buf, b"val: 12345", "val: {}", 12345u32);
113 assert_eq!(
114 kformat!(&mut buf, "val: {:u}", 12345u32),
115 std::format!("val: {}", 12345u32).as_bytes()
116 );
117 assert_kformat_eq!(&mut buf, b"val: abcd", "val: {:x}", 0xabcd);
118 assert_kformat_eq!(&mut buf, b"val: ABCD", "val: {:X}", 0xabcd);
119 assert_kformat_eq!(&mut buf, b"val: 0x0", "val: {:#x}", 0);
120 assert_kformat_eq!(&mut buf, b"val: 0x2a", "val: {:#x}", 0x2a);
121 assert_kformat_eq!(&mut buf, b"val: 0x2A", "val: {:#X}", 0x2a);
122 assert_kformat_eq!(&mut buf, b"val: 0x00001A", "val: {:#08X}", 0x1A);
123 assert_kformat_eq!(&mut buf, b"val: 0x000000", "val: {:#08x}", 0);
124 assert_kformat_eq!(&mut buf, b"val: 0x1", "val: {:#18x}", 1);
125 assert_kformat_eq!(&mut buf, b"val: 0x0", "val: {:#18x}", 0);
126 assert_kformat_eq!(&mut buf, b"val: 0x2a", "val: {:>#8x}", 0x2a);
127 assert_kformat_eq!(&mut buf, b"val: 0x1A", "val: {:#8X}", 0x1a);
128 assert_kformat_eq!(&mut buf, b"val: 0x12345", "val: {:#6x}", 0x12345);
129 assert_kformat_eq!(&mut buf, b"val: 0xffffffffffffffff", "val: {:#18x}", u64::MAX);
130 assert_kformat_eq!(&mut buf, b"val: '0x2a '", "val: '{:<#10x}'", 0x2a);
131 assert_kformat_eq!(&mut buf, b"val: '0x2A '", "val: '{:<#10X}'", 0x2a);
132 assert_kformat_eq!(&mut buf, b"val: '0x0 '", "val: '{:<#10x}'", 0);
133 assert_kformat_eq!(&mut buf, b"val: 2a", "val: {:.5x}", 0x2a);
134 assert_kformat_eq!(&mut buf, b"val: 100", "val: {:o}", 64);
135
136 assert_kformat_eq!(&mut buf, b"f4", "{:x}", -12i8);
138 assert_kformat_eq!(&mut buf, b"0xf4", "{:#x}", -12i8);
139 assert_kformat_eq!(&mut buf, b"fb2e", "{:x}", -1234i16);
140 assert_kformat_eq!(&mut buf, b"ff439eb2", "{:x}", -12345678i32);
141 assert_kformat_eq!(&mut buf, b"ffffffffffffffff", "{:x}", -1i64);
142
143 let val_u8: u8 = 8;
144 let val_u16: u16 = 16;
145 let val_u32: u32 = 32;
146 let val_u64: u64 = 64;
147 let val_usize: usize = 128;
148 assert_eq!(
149 kformat!(
150 &mut buf,
151 "{:u} {:u} {:u} {:u} {:u}",
152 &val_u8,
153 val_u16,
154 val_u32,
155 val_u64,
156 val_usize
157 ),
158 std::format!("{} {} {} {} {}", &val_u8, val_u16, val_u32, val_u64, val_usize)
159 .as_bytes()
160 );
161 assert_eq!(
162 kformat!(&mut buf, "max u64: {:u}", u64::MAX),
163 std::format!("max u64: {}", u64::MAX).as_bytes()
164 );
165 }
166
167 #[test]
168 fn test_strings_and_cstrings() {
169 let mut buf = [0u8; 256];
170 assert_kformat_eq!(&mut buf, b"hello world", "hello {}", "world");
171 let s = "fuchsia";
172 assert_eq!(kformat!(&mut buf, "os: {:s}", s), std::format!("os: {}", s).as_bytes());
173 let sub = "pigweed kernel";
174 assert_eq!(
175 kformat!(&mut buf, "sub: {:s}", &sub[0..7]),
176 std::format!("sub: {}", &sub[0..7]).as_bytes()
177 );
178 assert_kformat_eq!(&mut buf, b"prec: 12345", "prec: {:.5}", "123456789");
179 assert_eq!(
180 kformat!(&mut buf, "prec: {:.5s}", "123456789"),
181 std::format!("prec: {:.5}", "123456789").as_bytes()
182 );
183
184 assert_kformat_eq!(&mut buf, b"'abc '", "'{:8}'", "abc");
186 assert_kformat_eq!(&mut buf, b"'abc '", "'{:<8}'", "abc");
187 assert_kformat_eq!(&mut buf, b"' abc'", "'{:>8}'", "abc");
188 assert_kformat_eq!(&mut buf, b"'abc '", "'{:08}'", "abc");
189 assert_kformat_eq!(&mut buf, b"'abc '", "'{:8.3}'", "abcdef");
190 assert_kformat_eq!(&mut buf, b"' abc'", "'{:>8.3}'", "abcdef");
191
192 let var_s = "abc";
193 assert_eq!(kformat!(&mut buf, "'{:8s}'", var_s), std::format!("'{:8}'", var_s).as_bytes());
194 assert_eq!(
195 kformat!(&mut buf, "'{:<8s}'", var_s),
196 std::format!("'{:<8}'", var_s).as_bytes()
197 );
198 assert_eq!(
199 kformat!(&mut buf, "'{:>8s}'", var_s),
200 std::format!("'{:>8}'", var_s).as_bytes()
201 );
202 assert_eq!(
203 kformat!(&mut buf, "'{:08s}'", var_s),
204 std::format!("'{:08}'", var_s).as_bytes()
205 );
206
207 let byte_slice: &[u8] = b"bytes";
208 assert_eq!(kformat!(&mut buf, "raw: {:s}", byte_slice), b"raw: bytes");
209
210 let fixed_array: [u8; 4] = [b'a', b'b', b'c', b'd'];
211 assert_eq!(kformat!(&mut buf, "arr: {:s}", fixed_array), b"arr: abcd");
212
213 let c_str = c"zircon-cstr";
214 assert_eq!(kformat!(&mut buf, "cstr: {:s}", c_str), b"cstr: zircon-cstr");
215
216 let raw_c_ptr = c"raw-c-ptr".as_ptr();
217 assert_eq!(kformat!(&mut buf, "raw_ptr: {:cs}", raw_c_ptr), b"raw_ptr: raw-c-ptr");
218 assert_eq!(kformat!(&mut buf, "aligned: {:<12cs}!", raw_c_ptr), b"aligned: raw-c-ptr !");
219 assert_eq!(kformat!(&mut buf, "aligned: {:12cs}!", raw_c_ptr), b"aligned: raw-c-ptr !");
220 assert_eq!(kformat!(&mut buf, "aligned: {:>12cs}!", raw_c_ptr), b"aligned: raw-c-ptr!");
221 }
222
223 #[test]
224 fn test_pointers() {
225 let mut buf = [0u8; 256];
226 let val: i32 = 42;
227 let ptr = &val as *const i32;
228 assert_eq!(kformat!(&mut buf, "ptr: {:p}", ptr), std::format!("ptr: {:p}", ptr).as_bytes());
229 assert_eq!(
230 kformat!(&mut buf, "ptr: {:#p}", ptr),
231 std::format!("ptr: {:#p}", ptr).as_bytes()
232 );
233
234 let usize_addr: usize = 0x12345678;
235 let addr_ptr = usize_addr as *const core::ffi::c_void;
236 assert_kformat_eq!(&mut buf, b"addr: 0x12345678", "addr: {:p}", addr_ptr);
237 assert_eq!(kformat!(&mut buf, "addr: {:p}", usize_addr), b"addr: 0x12345678");
238 assert_kformat_eq!(&mut buf, b"addr: 0x0000000012345678", "addr: {:#p}", addr_ptr);
239 assert_kformat_eq!(&mut buf, b"addr: 0x12345678", "addr: {:14p}", addr_ptr);
240 assert_kformat_eq!(&mut buf, b"addr: 0x12345678 ", "addr: {:<14p}", addr_ptr);
241 assert_kformat_eq!(&mut buf, b"addr: 0x000012345678", "addr: {:014p}", addr_ptr);
242
243 let null_ptr: *const core::ffi::c_void = core::ptr::null();
244 assert_kformat_eq!(&mut buf, b"null: 0x0", "null: {:p}", null_ptr);
245 assert_kformat_eq!(&mut buf, b"null: 0x0000000000000000", "null: {:#p}", null_ptr);
246 }
247
248 #[test]
249 fn test_single_evaluation() {
250 let mut buf = [0u8; 256];
251 let mut eval_count = 0;
252 let mut side_effect_fn = || {
253 eval_count += 1;
254 "single_eval"
255 };
256 let res = kformat!(&mut buf, "result: {:s}", side_effect_fn());
257 assert_eq!(res, std::format!("result: {}", "single_eval").as_bytes());
258 assert_eq!(eval_count, 1);
259
260 let mut bool_eval_count = 0;
261 let mut bool_side_effect_fn = || {
262 bool_eval_count += 1;
263 true
264 };
265 let res_b = kformat!(&mut buf, "flag: {:b}", bool_side_effect_fn());
266 assert_eq!(res_b, std::format!("flag: {}", true).as_bytes());
267 assert_eq!(bool_eval_count, 1);
268
269 let mut multi_eval_count = 0;
270 let mut multi_side_effect_fn = || {
271 multi_eval_count += 1;
272 100
273 };
274 let res_multi = kformat!(&mut buf, "{0} + {0} = 200", multi_side_effect_fn());
275 assert_eq!(res_multi, std::format!("{0} + {0} = 200", 100).as_bytes());
276 assert_eq!(multi_eval_count, 1);
277
278 let mut hex_eval_count = 0;
279 let mut hex_side_effect_fn = || {
280 hex_eval_count += 1;
281 0x2au32
282 };
283 let res_hex = kformat!(&mut buf, "{:#10x}", hex_side_effect_fn());
284 assert_eq!(res_hex, std::format!("{:#10x}", 0x2au32).as_bytes());
285 assert_eq!(hex_eval_count, 1);
286 }
287
288 #[test]
289 fn test_concat_format_string() {
290 let mut buf = [0u8; 256];
291 let val = 42;
292 assert_kformat_eq!(
293 &mut buf,
294 b"prefix_status: 42",
295 concat!("prefix_", "status: ", "{}"),
296 val
297 );
298 assert_kformat_eq!(
299 &mut buf,
300 b"test_1_true_c=99",
301 concat!("test_", 1, "_", true, "_", 'c', "={}"),
302 99
303 );
304 }
305
306 #[test]
307 fn test_captured_and_named_variables() {
308 let mut buf = [0u8; 256];
309 let user = "alice";
310 let score = 100;
311 assert_eq!(
312 kformat!(&mut buf, "player {user:s} has score {score}"),
313 std::format!("player {user} has score {score}").as_bytes()
314 );
315 assert_eq!(
316 kformat!(&mut buf, "{greeting:s}, {name:s}!", greeting = "hello", name = "world"),
317 std::format!("{greeting}, {name}!", greeting = "hello", name = "world").as_bytes()
318 );
319 }
320
321 #[test]
322 fn test_positional_arguments() {
323 let mut buf = [0u8; 256];
324 assert_kformat_eq!(&mut buf, b"a + b = a", "{0} + {1} = {0}", "a", "b");
325 assert_kformat_eq!(&mut buf, b"20 10 20", "{1} {0} {1}", 10, 20);
326 }
327
328 #[test]
329 fn test_escapes_and_percent() {
330 let mut buf = [0u8; 256];
331 assert_kformat_eq!(&mut buf, b"{hello}", "{{hello}}");
332 assert_kformat_eq!(&mut buf, b"100% completed", "100% completed");
333 assert_kformat_eq!(&mut buf, b"75% done", "{}% done", 75);
334 assert_kformat_eq!(&mut buf, b"{50%}", "{{{}%}}", 50);
335 }
336
337 #[test]
338 fn test_chars() {
339 let mut buf = [0u8; 256];
340 assert_kformat_eq!(&mut buf, b"char: Z", "char: {}", 'Z');
341 let c = '?';
342 assert_eq!(kformat!(&mut buf, "char: {:c}", c), std::format!("char: {}", c).as_bytes());
343 assert_eq!(
344 kformat!(&mut buf, "ref char: {:c}", &c),
345 std::format!("ref char: {}", &c).as_bytes()
346 );
347
348 assert_kformat_eq!(&mut buf, b"'a '", "'{:6}'", 'a');
350 assert_kformat_eq!(&mut buf, b"'a '", "'{:<6}'", 'a');
351 assert_kformat_eq!(&mut buf, b"' a'", "'{:>6}'", 'a');
352 assert_kformat_eq!(&mut buf, b"'a '", "'{:06}'", 'a');
353 assert_kformat_eq!(&mut buf, b"''", "'{:.0}'", 'a');
354 assert_kformat_eq!(&mut buf, b"'a'", "'{:.5}'", 'a');
355
356 assert_eq!(kformat!(&mut buf, "'{:6c}'", c), std::format!("'{:6}'", c).as_bytes());
357 assert_eq!(kformat!(&mut buf, "'{:>6c}'", c), std::format!("'{:>6}'", c).as_bytes());
358 assert_eq!(kformat!(&mut buf, "'{:.0c}'", c), std::format!("'{:.0}'", c).as_bytes());
359
360 let byte: u8 = b'A';
362 assert_kformat_eq!(&mut buf, b"byte lit auto: 88", "byte lit auto: {}", b'X');
363 assert_eq!(kformat!(&mut buf, "byte: {:c}", byte), b"byte: A");
364 assert_eq!(kformat!(&mut buf, "ref byte: {:c}", &byte), b"ref byte: A");
365 assert_eq!(kformat!(&mut buf, "byte lit: {:c}", b'K'), b"byte lit: K");
366
367 assert_kformat_eq!(&mut buf, "crab: 🦀".as_bytes(), "crab: {}", '🦀');
369 assert_eq!(kformat!(&mut buf, "accent: {:c}", 'é'), "accent: é".as_bytes());
370 }
371
372 #[test]
373 fn test_booleans() {
374 let mut buf = [0u8; 256];
375 assert_kformat_eq!(&mut buf, b"flag: true", "flag: {}", true);
376 assert_kformat_eq!(&mut buf, b"flag: false", "flag: {}", false);
377 assert_kformat_eq!(&mut buf, b"'true '", "'{:8}'", true);
378 assert_kformat_eq!(&mut buf, b"' true'", "'{:>8}'", true);
379 assert_kformat_eq!(&mut buf, b"'true '", "'{:08}'", true);
380 assert_kformat_eq!(&mut buf, b"'tru'", "'{:.3}'", true);
381
382 let f = false;
383 assert_eq!(kformat!(&mut buf, "flag: {:b}", f), std::format!("flag: {}", f).as_bytes());
384 assert_eq!(kformat!(&mut buf, "'{:8b}'", f), std::format!("'{:8}'", f).as_bytes());
385 assert_eq!(kformat!(&mut buf, "'{:>8b}'", f), std::format!("'{:>8}'", f).as_bytes());
386 assert_eq!(kformat!(&mut buf, "'{:.3b}'", f), std::format!("'{:.3}'", f).as_bytes());
387 }
388
389 #[test]
390 fn test_floats() {
391 let mut buf = [0u8; 256];
392 assert_eq!(
393 kformat!(&mut buf, "pi: {:.2f}", core::f64::consts::PI),
394 std::format!("pi: {:.2}", core::f64::consts::PI).as_bytes()
395 );
396 assert_kformat_eq!(&mut buf, b"float: 1.2346", "float: {:.4}", 1.23456f32);
397 assert_eq!(
398 kformat!(&mut buf, "float: {:.4f}", 1.23456f32),
399 std::format!("float: {:.4}", 1.23456f32).as_bytes()
400 );
401 assert_kformat_eq!(&mut buf, b"' 1.25'", "'{:10.2}'", 1.25f64);
402 assert_kformat_eq!(&mut buf, b"'1.25 '", "'{:<10.2}'", 1.25f64);
403 assert_kformat_eq!(&mut buf, b"'-000001.25'", "'{:010.2}'", -1.25f64);
404 assert_kformat_eq!(&mut buf, b"'+000001.25'", "'{:+010.2}'", 1.25f64);
405 let f = 1000.0;
406 let res_e = kformat!(&mut buf, "sci: {:.1e}", f);
407 assert_eq!(res_e, b"sci: 1.0e+03");
408 }
409
410 #[test]
411 fn test_buffer_truncation() {
412 let mut small_buf = [0u8; 8];
413 let res = kformat!(&mut small_buf, "1234567890");
414 assert_eq!(res, b"1234567");
415 assert_eq!(res.len(), 7);
416 }
417
418 #[test]
419 fn test_macro_wrapper_hygiene() {
420 macro_rules! wrapped_kformat {
421 ($buf:expr, $($tt:tt)*) => {
422 kformat!($buf, $($tt)*)
423 };
424 }
425 let mut buf = [0u8; 64];
426 let x = 123;
427 assert_eq!(wrapped_kformat!(&mut buf, "val: {}", x), b"val: 123");
428 assert_eq!(wrapped_kformat!(&mut buf, "val: {}", x), std::format!("val: {}", x).as_bytes());
429 }
430
431 #[test]
432 fn test_print_macros() {
433 kprint!("test printf {}", 123);
434 kprint!("100%");
435 kprintln!(" line2");
436 kprintln!("empty without args");
437 kprintln!("{:#x}", 0);
438 kprintln!("crab: {}", '🦀');
439 }
440}