Skip to content

Commit cd41602

Browse files
committed
v0.2.6 use ErrorCases; Add comments; Add tests; API changed.
1 parent bbdf97a commit cd41602

10 files changed

+118
-45
lines changed

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "lib_xch"
3-
version = "0.2.4"
3+
version = "0.2.6"
44
authors = ["LEXUGE <LEXUGEyky@outlook.com>"]
55
description = "Crate xch-ceb's official lib"
66
license = "GPL-3.0"

src/balancer_mod.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ use std::vec::Vec;
1919
use std::i32;
2020
// inside uses
2121
use structs::ChemicalEquation;
22+
use handler::ErrorCases;
23+
use handler::ErrorCases::I32Overflow;
2224

2325
pub fn xch_try(
2426
f: i32,
@@ -27,7 +29,7 @@ pub fn xch_try(
2729
list: &[Vec<i32>],
2830
chmcl_f_sut: &ChemicalEquation,
2931
len: usize,
30-
) -> Result<bool, String> {
32+
) -> Result<bool, ErrorCases> {
3133
if f == chmcl_f_sut.sum + 1 {
3234
match check(traversal, list, chmcl_f_sut, len) {
3335
Ok(true) => return Ok(true),
@@ -53,7 +55,7 @@ fn check(
5355
list: &[Vec<i32>],
5456
chmcl_f_sut: &ChemicalEquation,
5557
len: usize,
56-
) -> Result<bool, String> {
58+
) -> Result<bool, ErrorCases> {
5759
let mut tmp1: i32;
5860
let mut tmp2: i32;
5961
for item in list.iter().take(len + 1).skip(1) {
@@ -63,22 +65,22 @@ fn check(
6365
let tmp: i32;
6466
tmp = match item[j].checked_mul(traversal[j - 1]) {
6567
Some(s) => s,
66-
None => return Err("[ERROR] i32 overflow".to_string()),
68+
None => return Err(I32Overflow),
6769
};
6870
tmp1 = match tmp1.checked_add(tmp) {
6971
Some(s) => s,
70-
None => return Err("[ERROR] i32 overflow".to_string()),
72+
None => return Err(I32Overflow),
7173
};
7274
}
7375
for j in chmcl_f_sut.left_num as usize + 1..chmcl_f_sut.sum as usize + 1 {
7476
let tmp: i32;
7577
tmp = match item[j].checked_mul(traversal[j - 1]) {
7678
Some(s) => s,
77-
None => return Err("[ERROR] i32 overflow".to_string()),
79+
None => return Err(I32Overflow),
7880
};
7981
tmp2 = match tmp2.checked_add(tmp) {
8082
Some(s) => s,
81-
None => return Err("[ERROR] i32 overflow".to_string()),
83+
None => return Err(I32Overflow),
8284
};
8385
}
8486
if tmp1 != tmp2 {

src/handler.rs

+28-5
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ use balancer_mod::xch_try;
2323
///
2424
/// # Panics
2525
///
26-
/// The equation you provided should be a common unbalanced chemical equation which only contains **one** `+`.
27-
/// In following cases, API will **panic**:
28-
/// 1.Stack Overflow may cause panic too. Because it is using recusive balancer and regex-based parser.
26+
/// The equation you provided should be a common unbalanced chemical equation which only contains **one** `=`.
27+
///
28+
/// - Stack Overflow may cause **panic**. Because it is using recusive balancer and regex-based parser.
29+
///
2930
/// And in the other failed situation, it'll return a `error_message` and contain `parser_result`(maybe it is empty).
3031
pub fn handler_api(equation: &str, searching_range: i32) -> Result<Vec<i32>, ErrorHandler> {
3132
// T is successful traversal vector, E is list vector which parser returned.
@@ -52,7 +53,7 @@ pub fn handler_api(equation: &str, searching_range: i32) -> Result<Vec<i32>, Err
5253
) {
5354
Ok(true) => Ok(traversal),
5455
Ok(false) => Err(ErrorHandler {
55-
error_message: "No answer".to_string(),
56+
error_message: ErrorCases::NoAnswer,
5657
parser_result: list,
5758
}),
5859
Err(s) => Err(ErrorHandler {
@@ -65,6 +66,28 @@ pub fn handler_api(equation: &str, searching_range: i32) -> Result<Vec<i32>, Err
6566
/// `ErrorHandler` returns when `handler::handler_api` failed somehow.
6667
/// **CAUTION: `parser_result` might empty if parser is failed.**
6768
pub struct ErrorHandler {
68-
pub error_message: String,
69+
pub error_message: ErrorCases,
6970
pub parser_result: Vec<Vec<i32>>,
7071
}
72+
73+
/// All the Error Types.
74+
///
75+
/// - more or less than 1 `=`; not allowed chars; too many formulas.
76+
/// - i32 overflow.
77+
/// - brackets are not matched.
78+
/// - no formulas to split.
79+
/// - no tokens to get.
80+
/// - not found in `elements_table`.
81+
/// - no answer.
82+
/// - Can't parse into i32.
83+
#[derive(PartialEq, Debug)]
84+
pub enum ErrorCases {
85+
IllegalEquation,
86+
I32Overflow,
87+
MatchError,
88+
SplitError,
89+
NoTokens,
90+
NotFound,
91+
NoAnswer,
92+
I32ParseError,
93+
}

src/lib.rs

+11
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
// You should have received a copy of the GNU General Public License
1414
// along with this program. If not, see <http://www.gnu.org/licenses/>.
1515

16+
// Documentation
17+
//! This is the official library of xch-ceb.
18+
//! It can parse and balance *the Chemical Equation*.
19+
//!
20+
//! - Unlimited brackets
21+
//! - No Periodic table of the elements needed
22+
//!
23+
//! # Getting Started
24+
//!
25+
//! Just use the `handler_api`: ``lib_xch::handler::handler_api("H2O=H2+O2", 10);``
26+
1627
// extern crate(s)
1728
#[macro_use]
1829
extern crate lazy_static;

src/parser_mod/legal_check_util.rs

+10-6
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,28 @@
1515

1616
// Overall: This is the source code of the Delta-3 Parser.
1717

18-
pub fn legal_check(equation: &str) -> Result<bool, String> {
18+
// inside uses
19+
use handler::ErrorCases;
20+
use handler::ErrorCases::{IllegalEquation, MatchError};
21+
22+
pub fn legal_check(equation: &str) -> Result<bool, ErrorCases> {
1923
let equation = equation.chars().into_iter().collect::<Vec<_>>();
2024
let mut tmp = 0;
2125
for i in equation {
2226
if check_char(i) == 0 {
23-
return Err("[ERROR] Illegal Equation!".to_string());
27+
return Err(IllegalEquation);
2428
}
2529
if i == '=' {
2630
tmp += 1;
2731
}
2832
}
2933
if tmp != 1 {
30-
return Err("[ERROR] Illegal Equation!".to_string());
34+
return Err(IllegalEquation);
3135
}
3236
Ok(true)
3337
}
3438

35-
pub fn legal_check_brackets(formula: &str) -> Result<bool, String> {
39+
pub fn legal_check_brackets(formula: &str) -> Result<bool, ErrorCases> {
3640
let formula = formula.chars().into_iter().collect::<Vec<_>>();
3741
for i in 0..formula.len() {
3842
if formula[i] == '(' {
@@ -45,7 +49,7 @@ pub fn legal_check_brackets(formula: &str) -> Result<bool, String> {
4549
Ok(true)
4650
}
4751

48-
fn brackets_matcher(formula: &[char], pos: usize, mode: bool) -> Result<usize, String> {
52+
fn brackets_matcher(formula: &[char], pos: usize, mode: bool) -> Result<usize, ErrorCases> {
4953
let mut fake_stack = 0;
5054

5155
if mode {
@@ -75,7 +79,7 @@ fn brackets_matcher(formula: &[char], pos: usize, mode: bool) -> Result<usize, S
7579
}
7680
}
7781
}
78-
Err("[ERROR] Can't match!".to_string())
82+
Err(MatchError)
7983
}
8084

8185
fn check_char(test: char) -> i32 {

src/parser_mod/mod.rs

+16-13
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ use std::i32;
2727
use structs::ChemicalEquation;
2828
use self::parser_struct::{FormulaDesc, TableDesc, TokenDesc};
2929
use self::legal_check_util::{legal_check, legal_check_brackets};
30+
use handler::ErrorCases;
31+
use handler::ErrorCases::{I32Overflow, I32ParseError, IllegalEquation, NoTokens, SplitError};
3032

31-
pub fn xch_parser(equation: &str) -> Result<(ChemicalEquation, usize, Vec<Vec<i32>>), String> {
33+
pub fn xch_parser(equation: &str) -> Result<(ChemicalEquation, usize, Vec<Vec<i32>>), ErrorCases> {
3234
legal_check(equation)?;
3335
let mut chemical_equation_struct = ChemicalEquation {
3436
left_num: 0,
@@ -68,18 +70,18 @@ pub fn xch_parser(equation: &str) -> Result<(ChemicalEquation, usize, Vec<Vec<i3
6870
))
6971
}
7072

71-
fn parser_get_sum(equation: &str) -> Result<i32, String> {
73+
fn parser_get_sum(equation: &str) -> Result<i32, ErrorCases> {
7274
let mut sum: i32 = 0;
7375
for _ in equation.split('+') {
7476
sum = match sum.checked_add(1) {
7577
Some(s) => s,
76-
None => return Err("[ERROR] i32 overflow: Illegal Equation!".to_string()),
78+
None => return Err(IllegalEquation),
7779
}
7880
}
7981
Ok(sum)
8082
}
8183

82-
fn part_parser(equation: &str, table: &mut TableDesc, begin: i32) -> Result<i32, String> {
84+
fn part_parser(equation: &str, table: &mut TableDesc, begin: i32) -> Result<i32, ErrorCases> {
8385
let mut sum = begin;
8486
for formula in equation.split('+') {
8587
sum += 1;
@@ -89,14 +91,14 @@ fn part_parser(equation: &str, table: &mut TableDesc, begin: i32) -> Result<i32,
8991
Ok(sum - begin)
9092
}
9193

92-
fn formula_spliter(target: &str) -> Result<Vec<FormulaDesc>, String> {
94+
fn formula_spliter(target: &str) -> Result<Vec<FormulaDesc>, ErrorCases> {
9395
let mut v: Vec<FormulaDesc> = Vec::new();
9496
lazy_static! {
9597
static ref RE: Regex = Regex::new(r"\((([A-Z][a-z]*(\d+)*)+)\)(\d+)*").unwrap();
9698
}
9799

98100
if !RE.is_match(target) {
99-
return Err("[ERROR] No more to split!".to_string());
101+
return Err(SplitError);
100102
}
101103
for cap in RE.captures_iter(target) {
102104
let mut times: i32;
@@ -106,7 +108,7 @@ fn formula_spliter(target: &str) -> Result<Vec<FormulaDesc>, String> {
106108
} else {
107109
times = match cap4.trim().parse::<i32>() {
108110
Ok(s) => s,
109-
Err(_) => return Err("[ERROR] Not a number!".to_string()),
111+
Err(_) => return Err(I32ParseError),
110112
}
111113
}
112114
v.push(FormulaDesc {
@@ -118,13 +120,13 @@ fn formula_spliter(target: &str) -> Result<Vec<FormulaDesc>, String> {
118120
Ok(v)
119121
}
120122

121-
fn get_token(target: &str) -> Result<Vec<TokenDesc>, String> {
123+
fn get_token(target: &str) -> Result<Vec<TokenDesc>, ErrorCases> {
122124
let mut v: Vec<TokenDesc> = Vec::new();
123125
lazy_static! {
124126
static ref RE: Regex = Regex::new(r"([A-Z][a-z]*)(\d+)*").unwrap();
125127
}
126128
if !RE.is_match(target) {
127-
return Err("[ERROR] No tokens!".to_string());
129+
return Err(NoTokens);
128130
}
129131
for cap in RE.captures_iter(target) {
130132
let cap2 = cap.get(2).map_or("", |m| m.as_str());
@@ -134,7 +136,7 @@ fn get_token(target: &str) -> Result<Vec<TokenDesc>, String> {
134136
} else {
135137
times = match cap2.trim().parse::<i32>() {
136138
Ok(s) => s,
137-
Err(_) => return Err("[ERROR] Not a number!".to_string()),
139+
Err(_) => return Err(I32ParseError),
138140
}
139141
}
140142
v.push(TokenDesc {
@@ -145,12 +147,12 @@ fn get_token(target: &str) -> Result<Vec<TokenDesc>, String> {
145147
Ok(v)
146148
}
147149

148-
fn mul_phrase(phrase: &FormulaDesc) -> Result<String, String> {
150+
fn mul_phrase(phrase: &FormulaDesc) -> Result<String, ErrorCases> {
149151
let mut v = get_token(&phrase.formula_self)?;
150152
for token in &mut v {
151153
token.times = match token.times.checked_mul(phrase.times) {
152154
Some(s) => s,
153-
None => return Err("[ERROR] i32 overflow".to_string()),
155+
None => return Err(I32Overflow),
154156
}
155157
}
156158
let mut s: String = String::new();
@@ -170,10 +172,11 @@ fn parser_formula(
170172
formula: &str,
171173
table: &mut TableDesc,
172174
location: usize,
173-
) -> Result<bool, String> {
175+
) -> Result<bool, ErrorCases> {
174176
let formula_backup = formula;
175177
let mut formula = format!("({})", formula_backup);
176178

179+
formula_spliter(&formula)?;
177180
while formula_spliter(&formula).is_ok() {
178181
for p in formula_spliter(&formula)? {
179182
formula = replace_phrase(&formula, &p.all, &(mul_phrase(&p)?));

src/parser_mod/parser_struct.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
// inside uses
1919
use structs::ElementStruct;
20-
use parser_mod::get_token;
20+
use super::get_token;
21+
use handler::ErrorCases;
22+
use handler::ErrorCases::{I32Overflow, NotFound};
2123

2224
pub struct FormulaDesc {
2325
pub formula_self: String,
@@ -38,7 +40,7 @@ pub struct TableDesc {
3840
}
3941

4042
impl TableDesc {
41-
pub fn store_in_table(&mut self, formula: &str, location: usize) -> Result<bool, String> {
43+
pub fn store_in_table(&mut self, formula: &str, location: usize) -> Result<bool, ErrorCases> {
4244
for t in get_token(formula)? {
4345
if !self.find_element_in_table(&t.token_name).is_ok() {
4446
let len = self.elements_table.len();
@@ -54,7 +56,7 @@ impl TableDesc {
5456
let tmp = self.find_element_in_table(&t.token_name)?; // It have been checked.
5557
self.list[tmp][location] = match self.list[tmp][location].checked_add(t.times) {
5658
Some(s) => s,
57-
None => return Err("[ERROR] i32 overflow".to_string()),
59+
None => return Err(I32Overflow),
5860
}
5961
}
6062
}
@@ -91,12 +93,12 @@ impl TableDesc {
9193
v
9294
}
9395

94-
fn find_element_in_table(&self, target: &str) -> Result<usize, String> {
96+
fn find_element_in_table(&self, target: &str) -> Result<usize, ErrorCases> {
9597
for i in &(self.elements_table) {
9698
if i.name == *target {
9799
return Ok(i.num);
98100
}
99101
}
100-
Err("[ERROR] Not found!".to_string())
102+
Err(NotFound)
101103
}
102104
}

0 commit comments

Comments
 (0)