Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wiggle/test-helpers/examples/tracing.rs
1692 views
1
use anyhow::Result;
2
use wiggle::GuestMemory;
3
use wiggle_test::{HostMemory, WasiCtx, impl_errno};
4
5
/// The `errors` argument to the wiggle gives us a hook to map a rich error
6
/// type like this one (typical of wiggle use cases in wasi-common and beyond)
7
/// down to the flat error enums that witx can specify.
8
#[derive(Debug, thiserror::Error)]
9
pub enum RichError {
10
#[error("Invalid argument: {0}")]
11
InvalidArg(String),
12
#[error("Won't cross picket line: {0}")]
13
PicketLine(String),
14
}
15
16
// Define an errno with variants corresponding to RichError. Use it in a
17
// trivial function.
18
wiggle::from_witx!({
19
tracing: true disable_for {
20
one_error_conversion::foo,
21
},
22
witx_literal: "
23
(typename $errno (enum (@witx tag u8) $ok $invalid_arg $picket_line))
24
(typename $s (record (field $f1 (@witx usize)) (field $f2 (@witx pointer u8))))
25
(typename $t (record (field $f1 u32) (field $f2 f32)))
26
(module $one_error_conversion
27
(@interface func (export \"foo\")
28
(param $strike u32)
29
(param $s $s)
30
(result $err (expected $t (error $errno)))))
31
",
32
errors: { errno => RichError },
33
});
34
35
impl_errno!(types::Errno);
36
37
/// When the `errors` mapping in witx is non-empty, we need to impl the
38
/// types::UserErrorConversion trait that wiggle generates from that mapping.
39
impl<'a> types::UserErrorConversion for WasiCtx<'a> {
40
fn errno_from_rich_error(&mut self, e: RichError) -> Result<types::Errno> {
41
wiggle::tracing::debug!(
42
rich_error = wiggle::tracing::field::debug(&e),
43
"error conversion"
44
);
45
// WasiCtx can collect a Vec<String> log so we can test this. We're
46
// logging the Display impl that `thiserror::Error` provides us.
47
self.log.borrow_mut().push(e.to_string());
48
// Then do the trivial mapping down to the flat enum.
49
match e {
50
RichError::InvalidArg { .. } => Ok(types::Errno::InvalidArg),
51
RichError::PicketLine { .. } => Ok(types::Errno::PicketLine),
52
}
53
}
54
}
55
56
impl<'a> one_error_conversion::OneErrorConversion for WasiCtx<'a> {
57
fn foo(
58
&mut self,
59
_: &mut GuestMemory<'_>,
60
strike: u32,
61
_s: &types::S,
62
) -> Result<types::T, RichError> {
63
// We use the argument to this function to exercise all of the
64
// possible error cases we could hit here
65
match strike {
66
0 => Ok(types::T {
67
f1: 123,
68
f2: 456.78,
69
}),
70
1 => Err(RichError::PicketLine(format!("I'm not a scab"))),
71
_ => Err(RichError::InvalidArg(format!("out-of-bounds: {strike}"))),
72
}
73
}
74
}
75
76
fn main() {
77
if std::env::var("RUST_LOG").is_err() {
78
// with no RUST_LOG env variable: use the tracing subscriber.
79
let subscriber = tracing_subscriber::fmt()
80
// all spans/events with a level equal to or higher than TRACE (e.g, trace, debug, info, warn, etc.)
81
// will be written to stdout.
82
.with_max_level(tracing::Level::TRACE)
83
// builds the subscriber.
84
.finish();
85
tracing::subscriber::set_global_default(subscriber).expect("set global tracing subscriber");
86
} else {
87
// with RUST_LOG set: use the env_logger backend to tracing.
88
env_logger::init();
89
}
90
91
let mut ctx = WasiCtx::new();
92
let mut host_memory = HostMemory::new();
93
let mut memory = host_memory.guest_memory();
94
95
// Exercise each of the branches in `foo`.
96
// Start with the success case:
97
let r0 = one_error_conversion::foo(&mut ctx, &mut memory, 0, 0, 8).unwrap();
98
assert_eq!(
99
r0,
100
types::Errno::Ok as i32,
101
"Expected return value for strike=0"
102
);
103
assert!(ctx.log.borrow().is_empty(), "No error log for strike=0");
104
105
// First error case:
106
let r1 = one_error_conversion::foo(&mut ctx, &mut memory, 1, 0, 8).unwrap();
107
assert_eq!(
108
r1,
109
types::Errno::PicketLine as i32,
110
"Expected return value for strike=1"
111
);
112
assert_eq!(
113
ctx.log.borrow_mut().pop().expect("one log entry"),
114
"Won't cross picket line: I'm not a scab",
115
"Expected log entry for strike=1",
116
);
117
118
// Second error case:
119
let r2 = one_error_conversion::foo(&mut ctx, &mut memory, 2, 0, 8).unwrap();
120
assert_eq!(
121
r2,
122
types::Errno::InvalidArg as i32,
123
"Expected return value for strike=2"
124
);
125
assert_eq!(
126
ctx.log.borrow_mut().pop().expect("one log entry"),
127
"Invalid argument: out-of-bounds: 2",
128
"Expected log entry for strike=2",
129
);
130
}
131
132