1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use serde::Serializer;
#[cfg(doc)]
use super::Ui;
pub trait Message {
/// Return textual representation of this message.
///
/// Default implementation returns empty string, making [`Ui`] skip printing this message.
fn text(self) -> String
where
Self: Sized,
{
String::new()
}
/// Serialize this structured message to a serializer which is routed to [`Ui`] output stream.
///
/// Default implementation does not serialize anything, making [`Ui`] skip printing
/// this message.
fn structured<S: Serializer>(self, ser: S) -> Result<S::Ok, S::Error>
where
Self: Sized,
{
// Silence unused warning without using underscore in variable name,
// so that it will not be populated by editors.
let _ = ser;
Err(serde::ser::Error::custom("UI_INTERNAL_SKIP"))
}
// NOTE: These two most low-level functions are doc hidden,
// because they are not considered stable.
#[doc(hidden)]
fn print_text(self)
where
Self: Sized,
{
let text = self.text();
if !text.is_empty() {
println!("{text}");
}
}
#[doc(hidden)]
fn print_json(self)
where
Self: Sized,
{
let mut buf = Vec::with_capacity(128);
let mut serializer = serde_json::Serializer::new(&mut buf);
match self.structured(&mut serializer) {
Ok(_) => {
let string = unsafe {
// UNSAFE: JSON is always UTF-8 encoded.
String::from_utf8_unchecked(buf)
};
println!("{string}");
}
Err(err) => {
if err.to_string() != "UI_INTERNAL_SKIP" {
panic!("JSON serialization of UI message must not fail: {err}")
}
}
}
}
}
impl Message for &str {
fn text(self) -> String {
self.to_string()
}
}
impl Message for String {
fn text(self) -> String {
self
}
}