use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::format;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use alloc::borrow::Cow;
use crate::rustc_error_messages::{
DiagArgMap, DiagArgName, IntoDiagArg, render_message, try_render_message,
};
use tracing::trace;
use crate::rustc_errors::{DiagMessage, Style};
pub fn format_diag_messages(
messages: &[(DiagMessage, Style)],
args: &DiagArgMap,
) -> Cow<'static, str> {
Cow::Owned(messages.iter().map(|(m, _)| format_diag_message(m, args)).collect::<String>())
}
pub fn format_diag_message<'a>(message: &'a DiagMessage, args: &DiagArgMap) -> Cow<'a, str> {
match message {
DiagMessage::Str(msg) => Cow::Borrowed(msg),
DiagMessage::Inline(msg) => format_template(msg, args),
}
}
fn format_template(message: &str, args: &DiagArgMap) -> Cow<'static, str> {
trace!(?message, ?args);
render_message(message, args)
}
pub fn try_format_diag_message<'a>(
message: &'a DiagMessage,
args: &DiagArgMap,
) -> Option<Cow<'a, str>> {
match message {
DiagMessage::Str(msg) => Some(Cow::Borrowed(msg)),
DiagMessage::Inline(msg) => try_render_message(msg, args).map(Cow::Owned),
}
}
pub fn diag_message_source<'a>(message: &'a DiagMessage) -> &'a str {
match message {
DiagMessage::Str(msg) | DiagMessage::Inline(msg) => msg,
}
}
pub trait DiagMessageAddArg {
fn arg(self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) -> EagerDiagMessageBuilder;
}
pub struct EagerDiagMessageBuilder {
template: Cow<'static, str>,
args: DiagArgMap,
}
impl DiagMessageAddArg for EagerDiagMessageBuilder {
fn arg(
mut self,
name: impl Into<DiagArgName>,
arg: impl IntoDiagArg,
) -> EagerDiagMessageBuilder {
let name = name.into();
let value = arg.into_diag_arg(&mut None);
debug_assert!(
!self.args.contains_key(&name) || self.args.get(&name) == Some(&value),
"arg {} already exists",
name
);
self.args.insert(name, value);
self
}
}
impl DiagMessageAddArg for DiagMessage {
fn arg(self, name: impl Into<DiagArgName>, arg: impl IntoDiagArg) -> EagerDiagMessageBuilder {
let DiagMessage::Inline(template) = self else {
panic!("Tried to eagerly format an already formatted message")
};
EagerDiagMessageBuilder { template, args: Default::default() }.arg(name, arg)
}
}
impl EagerDiagMessageBuilder {
pub fn format(self) -> DiagMessage {
DiagMessage::Str(format_template(&self.template, &self.args))
}
}