use std::{
borrow::Cow,
fmt::{Display, Write},
ops::ControlFlow,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[non_exhaustive]
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize)]
pub enum StatusType {
#[default]
Uninitialized,
Initialized,
StepType,
Success,
Failed,
Custom,
}
impl Display for StatusType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Uninitialized => "Uninitialized",
Self::Initialized => "Initialized",
Self::StepType => "Step",
Self::Success => "Success",
Self::Failed => "Failed",
Self::Custom => "Message",
}
)
}
}
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
pub struct StatusMessage {
pub status_type: StatusType,
#[serde(default, with = "optional_cow_static_str")]
pub text: Option<Cow<'static, str>>,
}
impl StatusMessage {
pub fn reset(&mut self) {
self.status_type = StatusType::Uninitialized;
self.text = None;
}
pub fn uninitialize(&mut self) {
self.reset()
}
pub fn initialize(&mut self) {
self.reset();
self.status_type = StatusType::Initialized;
}
pub fn set_initialized(mut self) -> Self {
self.initialize();
self
}
pub fn initialize_with_message(&mut self, message: impl Into<Cow<'static, str>>) {
self.initialize();
self.text = Some(message.into());
}
pub fn set_initialized_with_message(mut self, message: impl Into<Cow<'static, str>>) -> Self {
self.initialize_with_message(message);
self
}
pub fn step(&mut self) {
self.reset();
self.status_type = StatusType::StepType;
}
pub fn set_step(mut self) -> Self {
self.step();
self
}
pub fn step_with_message(&mut self, message: impl Into<Cow<'static, str>>) {
self.step();
self.text = Some(message.into());
}
pub fn set_step_with_message(mut self, message: impl Into<Cow<'static, str>>) -> Self {
self.step_with_message(message);
self
}
pub fn succeed(&mut self) {
self.reset();
self.status_type = StatusType::Success;
}
pub fn set_success(mut self) -> Self {
self.succeed();
self
}
pub fn succeed_with_message(&mut self, message: impl Into<Cow<'static, str>>) {
self.succeed();
self.text = Some(message.into());
}
pub fn set_success_with_message(mut self, message: impl Into<Cow<'static, str>>) -> Self {
self.succeed_with_message(message);
self
}
pub fn fail(&mut self) {
self.reset();
self.status_type = StatusType::Failed;
}
pub fn set_failed(mut self) -> Self {
self.fail();
self
}
pub fn fail_with_message(&mut self, message: impl Into<Cow<'static, str>>) {
self.fail();
self.text = Some(message.into());
}
pub fn set_failed_with_message(mut self, message: impl Into<Cow<'static, str>>) -> Self {
self.fail_with_message(message);
self
}
pub fn custom(&mut self, message: impl Into<Cow<'static, str>>) {
self.reset();
self.status_type = StatusType::Custom;
self.text = Some(message.into());
}
pub fn custom_with_message(&mut self, message: impl Into<Cow<'static, str>>) {
self.custom(message);
}
pub fn set_custom(mut self, message: impl Into<Cow<'static, str>>) -> Self {
self.custom(message);
self
}
pub fn text(&self) -> Option<&str> {
self.text.as_deref()
}
pub fn text_or_empty(&self) -> &str {
self.text().unwrap_or("")
}
pub const fn success(&self) -> bool {
matches!(self.status_type, StatusType::Success)
}
}
impl Display for StatusMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.text() {
Some(text) if !text.is_empty() => write!(f, "{}: {}", self.status_type, text),
_ => write!(f, "{}", self.status_type),
}
}
}
mod optional_cow_static_str {
use super::*;
pub fn serialize<S>(text: &Option<Cow<'static, str>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
text.as_deref().unwrap_or("").serialize(serializer)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Cow<'static, str>>, D::Error>
where
D: Deserializer<'de>,
{
Option::<String>::deserialize(deserializer).map(|text| text.map(Cow::Owned))
}
}
pub trait Status: Clone + Default {
fn reset(&mut self);
fn success(&self) -> bool {
self.message().success()
}
fn message(&self) -> &StatusMessage;
fn set_message(&mut self) -> &mut StatusMessage;
fn check_invariants(&mut self) -> ControlFlow<()> {
ControlFlow::Continue(())
}
}
pub trait ProgressStatus: Status {
fn write_progress(&self, out: &mut String) -> std::fmt::Result {
write!(out, "status={}", self.message())
}
}