use clap::ValueEnum;
use core::fmt;
use serde::Serialize;
use std::process::{ExitCode, Termination};
use thiserror::Error;
use crate::results;
#[derive(Error, Debug)]
pub(crate) enum ApplicationError {
#[error("Invalid input (expected {expected:?}, got {found:?}")]
InvalidArgument { expected: String, found: String },
#[error("Failed to prepare output in this format {err:?}")]
OutputFormatError { err: String },
#[error("Failed a requirement {err:?}")]
FailedRequirementError { err: String },
}
#[derive(ValueEnum, Clone, Debug)]
pub(crate) enum OutputFormat {
Text,
Yaml,
Json,
}
#[allow(dead_code)] pub(crate) trait SubcommandOutput: fmt::Display + Serialize + Termination {}
impl<T: fmt::Display + Serialize + Termination> SubcommandOutput for T {}
pub(crate) enum ExitOutcome {
Normal(SubcommandResult),
AlwaysSuccessful(SubcommandResult),
}
impl ExitOutcome {
pub(crate) const fn new(output: SubcommandResult, hard_success: bool) -> Self {
if hard_success {
Self::AlwaysSuccessful(output)
} else {
Self::Normal(output)
}
}
}
impl Termination for ExitOutcome {
fn report(self) -> ExitCode {
match self {
Self::Normal(result) => result.report(),
Self::AlwaysSuccessful(_result) => ExitCode::SUCCESS,
}
}
}
#[derive(Serialize)]
#[serde(untagged)]
pub(crate) enum SubcommandResult {
ComparisonStatement(results::ComparisonStatement),
OrderedVersionMap(results::OrderedVersionMap),
VersionExplanation(results::VersionExplanation),
FlatVersionsList(results::FlatVersionsList),
FlatStringList(results::FlatStringList),
FilterTestResult(results::FilterTestResult),
ValidateResult(results::ValidateResult),
JustAVersion(results::VersionMutationResult),
SelectResult(results::SelectResult),
}
impl From<results::ComparisonStatement> for SubcommandResult {
fn from(value: results::ComparisonStatement) -> Self {
Self::ComparisonStatement(value)
}
}
impl From<results::OrderedVersionMap> for SubcommandResult {
fn from(value: results::OrderedVersionMap) -> Self {
Self::OrderedVersionMap(value)
}
}
impl From<results::VersionExplanation> for SubcommandResult {
fn from(value: results::VersionExplanation) -> Self {
Self::VersionExplanation(value)
}
}
impl From<results::FlatVersionsList> for SubcommandResult {
fn from(value: results::FlatVersionsList) -> Self {
Self::FlatVersionsList(value)
}
}
impl From<results::FilterTestResult> for SubcommandResult {
fn from(value: results::FilterTestResult) -> Self {
Self::FilterTestResult(value)
}
}
impl From<results::ValidateResult> for SubcommandResult {
fn from(value: results::ValidateResult) -> Self {
Self::ValidateResult(value)
}
}
impl From<results::GenerateResult> for SubcommandResult {
fn from(value: results::GenerateResult) -> Self {
Self::FlatStringList(value.into())
}
}
impl From<results::VersionMutationResult> for SubcommandResult {
fn from(value: results::VersionMutationResult) -> Self {
Self::JustAVersion(value)
}
}
impl From<results::SelectResult> for SubcommandResult {
fn from(value: results::SelectResult) -> Self {
Self::SelectResult(value)
}
}
impl Termination for SubcommandResult {
fn report(self) -> ExitCode {
match self {
Self::ComparisonStatement(comparison_statement) => comparison_statement.report(),
Self::FilterTestResult(filter_test_result) => filter_test_result.report(),
Self::ValidateResult(validate_result) => validate_result.report(),
Self::SelectResult(select_result) => select_result.report(),
_ => ExitCode::SUCCESS,
}
}
}
impl fmt::Display for SubcommandResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::ComparisonStatement(v) => {
write!(f, "{}", v)
}
Self::OrderedVersionMap(v) => {
write!(f, "{}", v)
}
Self::VersionExplanation(v) => {
write!(f, "{}", v)
}
Self::FlatVersionsList(v) => {
write!(f, "{}", v)
}
Self::FlatStringList(v) => {
write!(f, "{}", v)
}
Self::FilterTestResult(v) => {
write!(f, "{}", v)
}
Self::ValidateResult(v) => {
write!(f, "{}", v)
}
Self::JustAVersion(v) => {
write!(f, "{}", v)
}
Self::SelectResult(v) => {
write!(f, "{}", v)
}
}
}
}