Skip to main content

kprint/
backend.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5unsafe extern "C" {
6    pub fn printf(format: *const core::ffi::c_char, ...) -> core::ffi::c_int;
7
8    pub fn snprintf(
9        str: *mut core::ffi::c_char,
10        size: usize,
11        format: *const core::ffi::c_char,
12        ...
13    ) -> core::ffi::c_int;
14}
15
16/// Trait implemented by types that can be formatted as a string slice (`%.*s`).
17pub trait AsKPrintStr {
18    fn kprint_len(&self) -> core::ffi::c_int;
19    fn kprint_ptr(&self) -> *const core::ffi::c_char;
20}
21
22impl AsKPrintStr for &str {
23    #[inline(always)]
24    fn kprint_len(&self) -> core::ffi::c_int {
25        self.len() as core::ffi::c_int
26    }
27    #[inline(always)]
28    fn kprint_ptr(&self) -> *const core::ffi::c_char {
29        self.as_ptr() as *const core::ffi::c_char
30    }
31}
32
33impl AsKPrintStr for str {
34    #[inline(always)]
35    fn kprint_len(&self) -> core::ffi::c_int {
36        self.len() as core::ffi::c_int
37    }
38    #[inline(always)]
39    fn kprint_ptr(&self) -> *const core::ffi::c_char {
40        self.as_ptr() as *const core::ffi::c_char
41    }
42}
43
44impl AsKPrintStr for &[u8] {
45    #[inline(always)]
46    fn kprint_len(&self) -> core::ffi::c_int {
47        self.len() as core::ffi::c_int
48    }
49    #[inline(always)]
50    fn kprint_ptr(&self) -> *const core::ffi::c_char {
51        self.as_ptr() as *const core::ffi::c_char
52    }
53}
54
55impl AsKPrintStr for [u8] {
56    #[inline(always)]
57    fn kprint_len(&self) -> core::ffi::c_int {
58        self.len() as core::ffi::c_int
59    }
60    #[inline(always)]
61    fn kprint_ptr(&self) -> *const core::ffi::c_char {
62        self.as_ptr() as *const core::ffi::c_char
63    }
64}
65
66impl<const N: usize> AsKPrintStr for [u8; N] {
67    #[inline(always)]
68    fn kprint_len(&self) -> core::ffi::c_int {
69        self.len() as core::ffi::c_int
70    }
71    #[inline(always)]
72    fn kprint_ptr(&self) -> *const core::ffi::c_char {
73        self.as_ptr() as *const core::ffi::c_char
74    }
75}
76
77impl<const N: usize> AsKPrintStr for &[u8; N] {
78    #[inline(always)]
79    fn kprint_len(&self) -> core::ffi::c_int {
80        self.len() as core::ffi::c_int
81    }
82    #[inline(always)]
83    fn kprint_ptr(&self) -> *const core::ffi::c_char {
84        self.as_ptr() as *const core::ffi::c_char
85    }
86}
87
88impl AsKPrintStr for &core::ffi::CStr {
89    #[inline(always)]
90    fn kprint_len(&self) -> core::ffi::c_int {
91        self.to_bytes().len() as core::ffi::c_int
92    }
93    #[inline(always)]
94    fn kprint_ptr(&self) -> *const core::ffi::c_char {
95        self.as_ptr()
96    }
97}
98
99impl AsKPrintStr for core::ffi::CStr {
100    #[inline(always)]
101    fn kprint_len(&self) -> core::ffi::c_int {
102        self.to_bytes().len() as core::ffi::c_int
103    }
104    #[inline(always)]
105    fn kprint_ptr(&self) -> *const core::ffi::c_char {
106        self.as_ptr()
107    }
108}
109
110/// Trait implemented by types that can be formatted as a null-terminated C string (`%s`).
111pub trait AsKPrintCString {
112    fn as_c_ptr(&self) -> *const core::ffi::c_char;
113}
114
115impl AsKPrintCString for *const i8 {
116    #[inline(always)]
117    fn as_c_ptr(&self) -> *const core::ffi::c_char {
118        *self as *const core::ffi::c_char
119    }
120}
121
122impl AsKPrintCString for *mut i8 {
123    #[inline(always)]
124    fn as_c_ptr(&self) -> *const core::ffi::c_char {
125        *self as *const core::ffi::c_char
126    }
127}
128
129impl AsKPrintCString for *const u8 {
130    #[inline(always)]
131    fn as_c_ptr(&self) -> *const core::ffi::c_char {
132        *self as *const core::ffi::c_char
133    }
134}
135
136impl AsKPrintCString for *mut u8 {
137    #[inline(always)]
138    fn as_c_ptr(&self) -> *const core::ffi::c_char {
139        *self as *const core::ffi::c_char
140    }
141}
142
143impl AsKPrintCString for &core::ffi::CStr {
144    #[inline(always)]
145    fn as_c_ptr(&self) -> *const core::ffi::c_char {
146        self.as_ptr()
147    }
148}
149
150impl AsKPrintCString for core::ffi::CStr {
151    #[inline(always)]
152    fn as_c_ptr(&self) -> *const core::ffi::c_char {
153        self.as_ptr()
154    }
155}
156
157/// Trait implemented by signed integer types formatted with `%lld`.
158pub trait AsKPrintSignedInt {
159    fn as_c_longlong(&self) -> core::ffi::c_longlong;
160}
161
162macro_rules! impl_signed_int {
163    ($($t:ty),*) => {
164        $(
165            impl AsKPrintSignedInt for $t {
166                #[inline(always)]
167                fn as_c_longlong(&self) -> core::ffi::c_longlong {
168                    *self as core::ffi::c_longlong
169                }
170            }
171            impl AsKPrintSignedInt for &$t {
172                #[inline(always)]
173                fn as_c_longlong(&self) -> core::ffi::c_longlong {
174                    **self as core::ffi::c_longlong
175                }
176            }
177        )*
178    };
179}
180
181impl_signed_int!(i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, bool, char);
182
183/// Trait implemented by unsigned integer types formatted with `%llu`, `%llx`, `%llo`.
184pub trait AsKPrintUnsignedInt {
185    fn as_c_ulonglong(&self) -> core::ffi::c_ulonglong;
186}
187
188macro_rules! impl_unsigned_int {
189    ($($t:ty => $ut:ty),*) => {
190        $(
191            impl AsKPrintUnsignedInt for $t {
192                #[inline(always)]
193                fn as_c_ulonglong(&self) -> core::ffi::c_ulonglong {
194                    (*self as $ut) as core::ffi::c_ulonglong
195                }
196            }
197            impl AsKPrintUnsignedInt for &$t {
198                #[inline(always)]
199                fn as_c_ulonglong(&self) -> core::ffi::c_ulonglong {
200                    (**self as $ut) as core::ffi::c_ulonglong
201                }
202            }
203        )*
204    };
205}
206
207impl_unsigned_int!(
208    u8 => u8,
209    u16 => u16,
210    u32 => u32,
211    u64 => u64,
212    usize => usize,
213    i8 => u8,
214    i16 => u16,
215    i32 => u32,
216    i64 => u64,
217    isize => usize,
218    bool => u8
219);
220
221/// Computes the field width for the `"0x"` prefix in space-padded
222/// alternate hex formatting (`%*s%llx`) so that the total output width
223/// (leading spaces + 2-byte prefix + hex digits) is at least `width`.
224#[inline(always)]
225pub const fn hex_alt_prefix_width(val: core::ffi::c_ulonglong, width: usize) -> core::ffi::c_int {
226    let digits = (core::ffi::c_ulonglong::BITS - (val | 1).leading_zeros()).div_ceil(4) as usize;
227    width.saturating_sub(digits) as core::ffi::c_int
228}
229
230/// Trait implemented by pointer types formatted with `{:p}` / `{:#p}`.
231pub trait AsKPrintPointer {
232    fn as_c_ptr_void(&self) -> *const core::ffi::c_void;
233}
234
235impl<T: ?Sized> AsKPrintPointer for *const T {
236    #[inline(always)]
237    fn as_c_ptr_void(&self) -> *const core::ffi::c_void {
238        *self as *const core::ffi::c_void
239    }
240}
241
242impl<T: ?Sized> AsKPrintPointer for *mut T {
243    #[inline(always)]
244    fn as_c_ptr_void(&self) -> *const core::ffi::c_void {
245        *self as *const core::ffi::c_void
246    }
247}
248
249impl<T: ?Sized> AsKPrintPointer for &T {
250    #[inline(always)]
251    fn as_c_ptr_void(&self) -> *const core::ffi::c_void {
252        *self as *const T as *const core::ffi::c_void
253    }
254}
255
256impl<T: ?Sized> AsKPrintPointer for &mut T {
257    #[inline(always)]
258    fn as_c_ptr_void(&self) -> *const core::ffi::c_void {
259        *self as *const T as *const core::ffi::c_void
260    }
261}
262
263impl AsKPrintPointer for usize {
264    #[inline(always)]
265    fn as_c_ptr_void(&self) -> *const core::ffi::c_void {
266        *self as *const core::ffi::c_void
267    }
268}
269
270/// Trait implemented by types that can be formatted as a character (`{:c}`).
271pub trait AsKPrintChar {
272    fn kprint_encode_char(&self, buf: &mut [u8; 4])
273    -> (core::ffi::c_int, *const core::ffi::c_char);
274}
275
276impl AsKPrintChar for char {
277    #[inline(always)]
278    fn kprint_encode_char(
279        &self,
280        buf: &mut [u8; 4],
281    ) -> (core::ffi::c_int, *const core::ffi::c_char) {
282        let s = self.encode_utf8(buf);
283        (s.len() as core::ffi::c_int, s.as_ptr() as *const core::ffi::c_char)
284    }
285}
286
287impl AsKPrintChar for &char {
288    #[inline(always)]
289    fn kprint_encode_char(
290        &self,
291        buf: &mut [u8; 4],
292    ) -> (core::ffi::c_int, *const core::ffi::c_char) {
293        (*self).kprint_encode_char(buf)
294    }
295}
296
297impl AsKPrintChar for u8 {
298    #[inline(always)]
299    fn kprint_encode_char(
300        &self,
301        buf: &mut [u8; 4],
302    ) -> (core::ffi::c_int, *const core::ffi::c_char) {
303        buf[0] = *self;
304        (1, buf.as_ptr() as *const core::ffi::c_char)
305    }
306}
307
308impl AsKPrintChar for &u8 {
309    #[inline(always)]
310    fn kprint_encode_char(
311        &self,
312        buf: &mut [u8; 4],
313    ) -> (core::ffi::c_int, *const core::ffi::c_char) {
314        (*self).kprint_encode_char(buf)
315    }
316}