use std::collections::HashMap;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
use anyhow::Error as AnyError;
use crate::version::Version;
pub const DEFAULT_OPTION_NAME: &str = "--features";
pub const DEFAULT_PREFIX: &str = "Features: ";
#[derive(Debug)]
#[non_exhaustive]
pub enum CalcResult {
Null,
Bool(bool),
Version(Version),
}
pub trait Calculable: Debug {
fn get_value(&self, features: &HashMap<String, Version>) -> Result<CalcResult, ParseError>;
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Mode {
List,
Single(Box<dyn Calculable + 'static>),
Simple(Box<dyn Calculable + 'static>),
}
#[derive(Debug)]
#[non_exhaustive]
pub struct Config {
pub option_name: String,
pub prefix: String,
pub program: String,
pub mode: Mode,
}
impl Default for Config {
#[inline]
fn default() -> Self {
Self {
option_name: DEFAULT_OPTION_NAME.to_owned(),
prefix: DEFAULT_PREFIX.to_owned(),
program: String::new(),
mode: Mode::List,
}
}
}
impl Config {
#[inline]
#[must_use]
pub fn with_option_name(self, option_name: String) -> Self {
Self {
option_name,
..self
}
}
#[inline]
#[must_use]
pub fn with_prefix(self, prefix: String) -> Self {
Self { prefix, ..self }
}
#[inline]
#[must_use]
pub fn with_program(self, program: String) -> Self {
Self { program, ..self }
}
#[inline]
#[must_use]
pub fn with_mode(self, mode: Mode) -> Self {
Self { mode, ..self }
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ParseError {
CannotCompare(String, String),
InvalidComparisonOperator(String),
Uncomparable(String, String),
ParseFailure(String, AnyError),
ParseLeftovers(String, usize),
}
impl Display for ParseError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match *self {
Self::CannotCompare(ref left, ref right) => {
write!(f, "Cannot compare {left} to {right}")
}
Self::InvalidComparisonOperator(ref value) => {
write!(f, "Invalid comparison operator '{value}'")
}
Self::Uncomparable(ref left, ref right) => write!(
f,
"Don't know how to compare {left} to anything, including {right}"
),
Self::ParseFailure(ref value, _) => {
write!(f, "Could not parse '{value}' as a valid expression")
}
Self::ParseLeftovers(ref value, ref count) => {
write!(
f,
"Could not parse '{value}' as a valid expression: {count} bytes left over"
)
}
}
}
}
impl Error for ParseError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::CannotCompare(_, _)
| Self::InvalidComparisonOperator(_)
| Self::Uncomparable(_, _)
| Self::ParseLeftovers(_, _) => None,
Self::ParseFailure(_, ref err) => Some(err.as_ref()),
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum ObtainError {
DecodeOutput(String, AnyError),
RunProgram(String, AnyError),
Parse(ParseError),
}
impl Display for ObtainError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
match *self {
Self::DecodeOutput(ref prog, _) => write!(
f,
"Could not decode the {prog} program's output as valid UTF-8"
),
Self::RunProgram(ref prog, _) => write!(f, "Could not execute the {prog} program"),
Self::Parse(_) => write!(f, "Parse error"),
}
}
}
impl Error for ObtainError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::DecodeOutput(_, ref err) | Self::RunProgram(_, ref err) => Some(err.as_ref()),
Self::Parse(ref err) => Some(err),
}
}
}
#[derive(Debug)]
#[non_exhaustive]
pub enum Obtained {
Failed(ObtainError),
NotSupported,
Features(HashMap<String, Version>),
}