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 80 81 82 83 84 85
use serde::Serializer;
#[cfg(doc)]
use super::Ui;
const JSON_SKIP_MESSAGE: &str = "UI_INTERNAL_SKIP";
/// A typed object that can be either printed as a human-readable message or serialized as JSON.
///
/// The [`TypedMessage`][crate::components::TypedMessage] and [`Status`][crate::components::Status]
/// structs are the most frequently used kinds of messages.
pub trait Message {
// NOTE: The `print_*` low-level methods functions are doc hidden,
// because they are not considered stable.
/// 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()
}
#[doc(hidden)]
fn print_text(self)
where
Self: Sized,
{
let text = self.text();
if !text.is_empty() {
println!("{text}");
}
}
/// 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(JSON_SKIP_MESSAGE))
}
#[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() != JSON_SKIP_MESSAGE {
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
}
}