1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright 2017-2018 LEXUGE
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

// inside uses
use parser_mod::xch_parser;
use balancer_mod::xch_balancer;
use public::CheckedType;

/// the API balances the Chemical Equation by equation.
/// It provides one balanced solution, but it may isn't the *most* correct solution (because it set all free variables = 1).
/// If the equation can balance, function would return a `T` vector which contains the answer.
/// If not, it would return `handler::ErrorHandler` which contains Delta-3 the parser's result and error message.
///
/// # Panics
///
/// The equation you provided should be a common unbalanced chemical equation which only contains **one** `=`.
///
/// -  Stack Overflow may cause **panic**. Because it is using regex-based parser.
/// -  The implement for `PartialOrd` and `PartialEq` trait may cause **panic**. Because it should return `Ordering`.
///
/// And in the other failed situation, it'll return a `error_message` and contain `parser_result`(maybe it is empty).
pub fn handler_api<T: CheckedType>(
    equation: &str,
) -> Result<ResultHandler<Vec<T>>, ErrorHandler<T>> {
    // T is successful traversal vector, E is list vector which parser returned.
    let (chemical_equation_struct, list) = match xch_parser(equation) {
        Ok(s) => s,
        Err(e) => {
            return Err(ErrorHandler {
                error_message: e,
                parser_result: {
                    let list: Vec<Vec<T>> = Vec::new();
                    list
                },
            })
        }
    };
    match xch_balancer(&list, &chemical_equation_struct) {
        Ok(s) => Ok(s),
        Err(e) => Err(ErrorHandler {
            error_message: e,
            parser_result: list,
        }),
    }
}

/// `ErrorHandler` returns when `handler::handler_api` failed somehow.
/// **CAUTION: `parser_result` might empty if parser is failed.**
pub struct ErrorHandler<T: CheckedType> {
    pub error_message: ErrorCases,
    pub parser_result: Vec<Vec<T>>,
}

/// `ResultHandler` returns the balancer's result.
/// And it may contain warning message.
pub struct ResultHandler<U> {
    pub warn_message: WarnCases,
    pub result: U,
}

/// All the Error Types.
///
/// -  more or less than 1 `=` or not allowed chars.
/// -  overflow.
/// -  brackets are not matched.
/// -  no formulas to split.
/// -  no tokens to get.
/// -  not found in `elements_table`.
/// -  no answer.
/// -  Can't parse into `T`.
/// -  Equation set unsolvable.
/// -  `checked_abs()` error.
/// -  `checked_neg()` error.
/// -  The denominator of a fraction is 0.
#[derive(PartialEq, Debug)]
pub enum ErrorCases {
    IllegalEquation,
    Overflow,
    MatchError,
    SplitError,
    NoTokens,
    NotFound,
    NoAnswer,
    ParseError,
    Unsolvable,
    AbsError,
    NegError,
    UndefinedFrac,
}

/// All the Warning Types.
///
/// -  Free variables detected, result may be wrong.
/// -  No warning.
#[derive(PartialEq, Debug)]
pub enum WarnCases {
    FreeVariablesDetected,
    NoWarn,
}