1use crate::{PrintfArgument, PrintfFmt};
8use libc::{c_char, c_int};
9
10macro_rules! tuple_impl {
11 ($num:tt, $p_name:ident, $snp_name:ident, ( $($t:ident),* ), ( $($var:ident),* )) => {
12 #[doc = concat!("A safe wrapper around [`printf`](libc::printf) for ", stringify!($num), " argument(s).")]
13 #[inline]
14 pub fn $p_name<$($t),*>(fmt: PrintfFmt<($($t,)*)>, $($var: $t),*) -> c_int
15 where $($t: PrintfArgument),* {
16
17 unsafe {
18 libc::printf(fmt.as_ptr() $(, $var.as_c_val())* )
19 }
20 }
21
22 #[doc = concat!("A safe wrapper around [`snprintf`](libc::snprintf) for ", stringify!($num), " argument(s).")]
23 #[inline]
24 pub fn $snp_name<$($t),*>(dst: &mut [u8], fmt: PrintfFmt<($($t,)*)>, $($var: $t),*) -> c_int
25 where $($t: PrintfArgument),* {
26
27 unsafe {
28 libc::snprintf(
29 dst.as_mut_ptr() as *mut c_char,
30 dst.len(),
31 fmt.as_ptr()
32 $(, $var.as_c_val())*
33 )
34 }
35 }
36 };
37}
38
39tuple_impl!(0, printf0, snprintf0, (), ());
40tuple_impl!(1, printf1, snprintf1, (A), (a));
41tuple_impl!(2, printf2, snprintf2, (A, B), (a, b));
42tuple_impl!(3, printf3, snprintf3, (A, B, C), (a, b, c));
43tuple_impl!(4, printf4, snprintf4, (A, B, C, D), (a, b, c, d));
44tuple_impl!(5, printf5, snprintf5, (A, B, C, D, E), (a, b, c, d, e));
45tuple_impl!(6, printf6, snprintf6, (A, B, C, D, E, F), (a, b, c, d, e, f));
46tuple_impl!(7, printf7, snprintf7, (A, B, C, D, E, F, G), (a, b, c, d, e, f, g));
47tuple_impl!(8, printf8, snprintf8, (A, B, C, D, E, F, G, H), (a, b, c, d, e, f, g, h));
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::PrintfFmt;
53
54 #[test]
55 fn snprintf_test_invocation() {
56 let mut x: [u8; 12] = [5u8; 12];
57
58 assert_eq!(
59 snprintf2(&mut x[..], PrintfFmt::new("X %u Y %c\0").unwrap(), 15u32, b'Z'),
60 8,
61 "snprintf2 return value should be 8"
62 );
63 assert_eq!(&x, b"X 15 Y Z\0\x05\x05\x05", "contents of x");
64 }
65
66 #[test]
67 fn snprintf_no_buffer_overflow() {
68 let mut x: [u8; 8] = [5u8; 8];
69 assert_eq!(
70 snprintf1(&mut x[..4], PrintfFmt::new("a%d \0").unwrap(), -100),
71 6,
72 "snprintf1 return value should be 6"
73 );
74 assert_eq!(&x[4..], [5u8; 4], "only 4 bytes should have been written by snprintf1");
75 }
76}