use std::fmt::Display;
trait MessageType {
const PREFIX: &'static str;
const TO_STDERR: bool = false;
}
struct Error;
struct Warning;
struct Success;
impl MessageType for Error {
const PREFIX: &'static str = "🚨 ERROR";
const TO_STDERR: bool = true;
}
impl MessageType for Warning {
const PREFIX: &'static str = "⚠️ WARNING";
}
impl MessageType for Success {
const PREFIX: &'static str = "✅ SUCCESS";
}
fn format_message<T: MessageType>(title: &str, details: &str) -> String {
format!("{}: {title}\n\n{details}", T::PREFIX)
}
fn format_message_with_suggestion<T: MessageType>(
title: &str,
details: &str,
suggestion: &str,
) -> String {
format!("{}\n\n{suggestion}", format_message::<T>(title, details))
}
fn print_message<T: MessageType>(title: &str, details: &str) {
let message = format_message::<T>(title, details);
if T::TO_STDERR {
eprintln!("{message}");
} else {
println!("{message}");
}
}
fn print_message_with_suggestion<T: MessageType>(title: &str, details: &str, suggestion: &str) {
let message = format_message_with_suggestion::<T>(title, details, suggestion);
if T::TO_STDERR {
eprintln!("{message}");
} else {
println!("{message}");
}
}
pub fn print_error(title: &str, details: &str, suggestion: &str) {
print_message_with_suggestion::<Error>(title, details, suggestion);
}
pub fn print_warning(title: &str, details: &str) {
print_message::<Warning>(title, details);
}
pub fn print_success(title: &str, details: &str) {
print_message::<Success>(title, details);
}
pub fn format_list<T: Display>(items: &[T]) -> String {
items
.iter()
.map(|item| format!(" - {item}"))
.collect::<Vec<_>>()
.join("\n")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_format_message() {
let title = "Test Title";
let details = "Test Details";
let error_msg = format_message::<Error>(title, details);
assert!(error_msg.contains("🚨 ERROR"));
assert!(error_msg.contains(title));
assert!(error_msg.contains(details));
let warning_msg = format_message::<Warning>(title, details);
assert!(warning_msg.contains("⚠️ WARNING"));
assert!(warning_msg.contains(title));
assert!(warning_msg.contains(details));
let success_msg = format_message::<Success>(title, details);
assert!(success_msg.contains("✅ SUCCESS"));
assert!(success_msg.contains(title));
assert!(success_msg.contains(details));
}
#[test]
fn test_format_message_with_suggestion() {
let title = "Test Title";
let details = "Test Details";
let suggestion = "Test Suggestion";
let error_msg = format_message_with_suggestion::<Error>(title, details, suggestion);
assert!(error_msg.contains("🚨 ERROR"));
assert!(error_msg.contains(title));
assert!(error_msg.contains(details));
assert!(error_msg.contains(suggestion));
let warning_msg = format_message_with_suggestion::<Warning>(title, details, suggestion);
assert!(warning_msg.contains("⚠️ WARNING"));
assert!(warning_msg.contains(title));
assert!(warning_msg.contains(details));
assert!(warning_msg.contains(suggestion));
let success_msg = format_message_with_suggestion::<Success>(title, details, suggestion);
assert!(success_msg.contains("✅ SUCCESS"));
assert!(success_msg.contains(title));
assert!(success_msg.contains(details));
assert!(success_msg.contains(suggestion));
}
#[test]
fn test_format_list() {
let empty_list: Vec<String> = vec![];
assert_eq!(format_list(&empty_list), "");
let single_item = vec!["item1".to_string()];
assert_eq!(format_list(&single_item), " - item1");
let multiple_items = vec!["item1".to_string(), "item2".to_string()];
let formatted = format_list(&multiple_items);
assert!(formatted.contains(" - item1"));
assert!(formatted.contains(" - item2"));
}
}