#[derive(Copy, Clone)]
pub struct AssertOptions {
pub expand: ExpansionFormat,
pub color: bool,
}
impl AssertOptions {
pub fn get() -> AssertOptions {
use std::sync::RwLock;
static STYLE: RwLock<Option<AssertOptions>> = RwLock::new(None);
loop {
if let Some(style) = *STYLE.read().unwrap() {
return style;
}
match STYLE.try_write() {
Err(_) => continue,
Ok(mut style) => {
let style = style.get_or_insert_with(AssertOptions::from_env);
if style.color {
yansi::whenever(yansi::Condition::ALWAYS)
} else {
yansi::whenever(yansi::Condition::NEVER)
}
return *style;
}
}
}
}
fn from_env() -> Self {
let format = std::env::var_os("ASSERT2");
let format = format.as_ref().and_then(|x| x.to_str()).unwrap_or("");
let mut output = Self {
expand: ExpansionFormat::Auto,
color: should_color(),
};
for word in format.split(',') {
let word = word.trim();
if word.eq_ignore_ascii_case("pretty") {
output.expand = ExpansionFormat::Pretty;
} else if word.eq_ignore_ascii_case("compact") {
output.expand = ExpansionFormat::Compact;
} else if word.eq_ignore_ascii_case("color") {
output.color = true;
} else if word.eq_ignore_ascii_case("no-color") {
output.color = false;
}
}
output
}
}
#[derive(Copy, Clone, Eq, PartialEq)]
pub enum ExpansionFormat {
Auto,
Pretty,
Compact,
}
impl ExpansionFormat {
pub fn force_pretty(self) -> bool {
self == Self::Pretty
}
pub fn force_compact(self) -> bool {
self == Self::Compact
}
pub fn expand_all<const N: usize>(self, values: [&dyn std::fmt::Debug; N]) -> [String; N] {
if !self.force_pretty() {
let expanded = values.map(|x| format!("{x:?}"));
if self.force_compact() || Self::is_compact_good(&expanded) {
return expanded;
}
}
values.map(|x| format!("{x:#?}"))
}
pub fn is_compact_good(expanded: &[impl AsRef<str>]) -> bool {
for value in expanded {
if value.as_ref().len() > 40 {
return false;
}
}
for value in expanded {
if value.as_ref().contains('\n') {
return false;
}
}
true
}
}
fn should_color() -> bool {
use std::ffi::OsStr;
fn is_false(value: impl AsRef<OsStr>) -> bool {
let value = value.as_ref();
value == "0" || value.eq_ignore_ascii_case("false") || value.eq_ignore_ascii_case("no")
}
fn is_true(value: impl AsRef<OsStr>) -> bool {
let value = value.as_ref();
value == "1" || value.eq_ignore_ascii_case("true") || value.eq_ignore_ascii_case("yes")
}
#[allow(clippy::if_same_then_else)] if std::env::var_os("NO_COLOR").map(is_true).unwrap_or_default() {
false
} else if std::env::var_os("CLICOLOR").map(is_false).unwrap_or_default() {
false
} else if std::env::var_os("CLICOLOR_FORCE").map(is_true).unwrap_or_default() {
true
} else {
std::io::IsTerminal::is_terminal(&std::io::stderr())
}
}