#![doc = include_str!("../docs/main.md")]
#[cfg(feature = "proc_macro")]
pub use compare_variables_macro::compare_variables;
#[derive(Clone)]
pub struct Comparison<T: PartialOrd> {
first_val: ComparisonValue<T>,
comp_first_to_second: ComparisonOperator,
second_val: ComparisonValue<T>,
comp_second_to_third: ComparisonOperator,
third_val: Option<ComparisonValue<T>>,
is_true: bool,
}
impl<T: PartialOrd> Comparison<T> {
pub fn new(
first_val: ComparisonValue<T>,
comp_first_to_second: ComparisonOperator,
second_val: ComparisonValue<T>,
comp_second_to_third: ComparisonOperator,
third_val: Option<ComparisonValue<T>>,
) -> Self {
let mut is_true = true;
if !comp_first_to_second.is_true(&first_val.value, &second_val.value) {
is_true = false;
}
if let Some(third_val) = third_val.as_ref() {
if !comp_second_to_third.is_true(&second_val.value, &third_val.value) {
is_true = false;
}
};
return Self {
first_val,
comp_first_to_second,
second_val,
comp_second_to_third,
third_val,
is_true,
};
}
pub fn new_checked(
first_val: ComparisonValue<T>,
comp_first_to_second: ComparisonOperator,
second_val: ComparisonValue<T>,
comp_second_to_third: ComparisonOperator,
third_val: Option<ComparisonValue<T>>,
) -> Result<Self, Self> {
let this = Self::new(
first_val,
comp_first_to_second,
second_val,
comp_second_to_third,
third_val,
);
if this.is_true() {
return Ok(this);
} else {
return Err(this);
}
}
pub fn first_val(&self) -> &ComparisonValue<T> {
return &self.first_val;
}
pub fn second_val(&self) -> &ComparisonValue<T> {
return &self.second_val;
}
pub fn third_val(&self) -> Option<&ComparisonValue<T>> {
return self.third_val.as_ref();
}
pub fn comp_first_to_second(&self) -> ComparisonOperator {
return self.comp_first_to_second;
}
pub fn comp_second_to_third(&self) -> ComparisonOperator {
return self.comp_second_to_third;
}
pub fn is_true(&self) -> bool {
self.is_true
}
}
impl<T: PartialOrd + std::fmt::Debug> std::error::Error for Comparison<T> {}
impl<T: PartialOrd + std::fmt::Debug> std::fmt::Debug for Comparison<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return std::fmt::Display::fmt(self, f);
}
}
impl<T: PartialOrd + std::fmt::Debug> std::fmt::Display for Comparison<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"`{} {} {}",
self.first_val, self.comp_first_to_second, self.second_val
)?;
if let Some(third_val) = self.third_val.as_ref() {
write!(f, " {} {}", self.comp_second_to_third, third_val)?;
}
if self.is_true() {
write!(f, "` is true")
} else {
write!(f, "` is false")
}
}
}
#[derive(Debug, Clone)]
pub struct ComparisonValue<T: PartialOrd> {
pub value: T,
pub variable_name: Option<&'static str>,
}
impl<T: PartialOrd> ComparisonValue<T> {
pub fn new(value: T, variable_name: Option<&'static str>) -> Self {
return Self {
value,
variable_name,
};
}
}
impl<T: PartialOrd + std::fmt::Debug> std::fmt::Display for ComparisonValue<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(name) = self.variable_name.as_ref() {
write!(f, "{name} (value: ")?;
write!(f, "{:?})", self.value)?;
} else {
write!(f, "{:?}", self.value)?;
}
return Ok(());
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy)]
pub enum ComparisonOperator {
Lesser,
LesserOrEqual,
Equal,
Inequal,
GreaterOrEqual,
Greater,
}
impl ComparisonOperator {
pub fn as_str(&self) -> &'static str {
match self {
ComparisonOperator::Lesser => "<",
ComparisonOperator::LesserOrEqual => "<=",
ComparisonOperator::Equal => "==",
ComparisonOperator::Inequal => "!=",
ComparisonOperator::GreaterOrEqual => ">=",
ComparisonOperator::Greater => ">",
}
}
pub fn is_true<T: PartialOrd>(&self, first_val: &T, second_val: &T) -> bool {
match self {
ComparisonOperator::Lesser => return first_val < second_val,
ComparisonOperator::LesserOrEqual => return first_val <= second_val,
ComparisonOperator::Equal => return first_val == second_val,
ComparisonOperator::Inequal => return first_val != second_val,
ComparisonOperator::GreaterOrEqual => return first_val >= second_val,
ComparisonOperator::Greater => return first_val > second_val,
}
}
}
impl From<&ComparisonOperator> for &'static str {
fn from(value: &ComparisonOperator) -> Self {
return value.as_str();
}
}
impl AsRef<str> for ComparisonOperator {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl std::fmt::Display for ComparisonOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
pub trait ComparisonErrorTrait: std::error::Error + Sync + Send + std::any::Any {
fn fmt_first_val(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
fn fmt_second_val(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
fn fmt_third_val(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result;
fn comp_first_to_second(&self) -> ComparisonOperator;
fn comp_second_to_third(&self) -> ComparisonOperator;
}
impl<T: PartialOrd + std::fmt::Debug + Sync + Send + 'static> ComparisonErrorTrait
for Comparison<T>
{
fn fmt_first_val(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return std::fmt::Display::fmt(self.first_val(), f);
}
fn fmt_second_val(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return std::fmt::Display::fmt(self.second_val(), f);
}
fn fmt_third_val(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.third_val() {
Some(v) => return std::fmt::Display::fmt(v, f),
None => return Err(std::fmt::Error),
}
}
fn comp_first_to_second(&self) -> ComparisonOperator {
return self.comp_first_to_second;
}
fn comp_second_to_third(&self) -> ComparisonOperator {
return self.comp_second_to_third;
}
}