Skip to content

Commit e32ccb7

Browse files
committed
Using a Display argument for lazy evaluation
1 parent be69bd4 commit e32ccb7

File tree

2 files changed

+27
-22
lines changed

2 files changed

+27
-22
lines changed

libbpf-rs/src/print.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::*;
22
use std::io::{self, Write};
33
use std::os::raw::c_char;
44
use std::sync::atomic::{AtomicPtr, Ordering};
5+
use std::fmt;
56

67
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
78
#[repr(u32)]
@@ -23,16 +24,31 @@ impl From<libbpf_sys::libbpf_print_level> for PrintLevel {
2324
}
2425
}
2526

26-
pub type PrintCallback = fn(PrintLevel, &str);
27+
pub type PrintCallback = fn(PrintLevel, &dyn fmt::Display);
28+
29+
struct Vsprintf {
30+
fmtstr: *const c_char,
31+
va_list: *mut libbpf_sys::__va_list_tag,
32+
}
33+
34+
impl fmt::Display for Vsprintf {
35+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36+
let msg = match unsafe { vsprintf::vsprintf(self.fmtstr, self.va_list) } {
37+
Ok(s) => s,
38+
Err(e) => format!("Failed to parse libbpf output: {}", e),
39+
};
40+
f.write_str(&msg)
41+
}
42+
}
2743

2844
/// Mimic the default print functionality of libbpf. This way if the user calls `set_print` when no
2945
/// previous callback had been set and then tries to restore it, it will appear to work correctly.
30-
fn default_callback(lvl: PrintLevel, msg: &str) {
46+
fn default_callback(lvl: PrintLevel, msg: &dyn fmt::Display) {
3147
if lvl == PrintLevel::Debug {
3248
return;
3349
}
3450

35-
let _ = io::stderr().write(msg.as_bytes());
51+
let _ = io::stderr().write(msg.to_string().as_bytes());
3652
}
3753

3854
fn from_ptr(ptr: *mut ()) -> PrintCallback {
@@ -42,27 +58,15 @@ fn from_ptr(ptr: *mut ()) -> PrintCallback {
4258
// There is no AtomicFnPtr. This is a workaround.
4359
static PRINT_CB: AtomicPtr<()> = AtomicPtr::new(default_callback as *mut ());
4460

45-
/// libbpf's default cb uses vfprintf's return code...which is ignored everywhere. Mimic that for
46-
/// completeness
4761
extern "C" fn outer_print_cb(
4862
level: libbpf_sys::libbpf_print_level,
4963
fmtstr: *const c_char,
5064
va_list: *mut libbpf_sys::__va_list_tag,
5165
) -> i32 {
5266
let cb = from_ptr(PRINT_CB.load(Ordering::Relaxed));
53-
match unsafe { vsprintf::vsprintf(fmtstr, va_list) } {
54-
Ok(s) => {
55-
cb(level.into(), &s);
56-
s.len() as i32
57-
}
58-
Err(e) => {
59-
cb(
60-
PrintLevel::Warn,
61-
&format!("Failed to parse libbpf output: {}", e),
62-
);
63-
-1
64-
}
65-
}
67+
let msg = Vsprintf { fmtstr, va_list };
68+
cb(level.into(), &msg);
69+
1 // return value is ignored by libbpf
6670
}
6771

6872
/// Set a callback to receive log messages from libbpf, instead of printing them to stderr. Returns

libbpf-rs/tests/test_print.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,20 @@
88
use libbpf_rs::{set_print, ObjectBuilder, PrintLevel};
99
use serial_test::serial;
1010
use std::sync::atomic::{AtomicBool, Ordering};
11+
use std::fmt::Display;
1112

1213
#[test]
1314
#[serial]
1415
fn test_set_print() {
1516
static CORRECT_LEVEL: AtomicBool = AtomicBool::new(false);
1617
static CORRECT_MESSAGE: AtomicBool = AtomicBool::new(false);
1718

18-
fn callback(level: PrintLevel, msg: &str) {
19+
fn callback(level: PrintLevel, msg: &dyn Display) {
1920
if level == PrintLevel::Warn {
2021
CORRECT_LEVEL.store(true, Ordering::Relaxed);
2122
}
2223

23-
if msg.starts_with("libbpf: ") {
24+
if msg.to_string().starts_with("libbpf: ") {
2425
CORRECT_MESSAGE.store(true, Ordering::Relaxed);
2526
}
2627
}
@@ -39,10 +40,10 @@ fn test_set_print() {
3940
#[test]
4041
#[serial]
4142
fn test_set_restore_print() {
42-
fn callback1(_: PrintLevel, _: &str) {
43+
fn callback1(_: PrintLevel, _: &dyn Display) {
4344
println!("one");
4445
}
45-
fn callback2(_: PrintLevel, _: &str) {
46+
fn callback2(_: PrintLevel, _: &dyn Display) {
4647
println!("two");
4748
}
4849

0 commit comments

Comments
 (0)