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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
const SEPARATOR: char = '=';
#[derive(Debug, Copy, Clone)]
pub struct Property<'a> {
key: &'a str,
value: &'a str,
}
impl<'a> Property<'a> {
pub fn new() -> Self {
Property { key: "", value: "" }
}
pub fn init(key: &'a str, value: &'a str) -> Self {
Property { key, value }
}
pub fn key(self) -> String {
self.key.to_string()
}
pub fn value(self) -> String {
self.value.to_string()
}
}
impl<'a> PartialEq for Property<'a> {
fn eq(&self, other: &Property) -> bool {
self.key == other.key && self.value == other.value
}
fn ne(&self, other: &Property) -> bool {
self.key != other.key || self.value != other.value
}
}
pub fn split(line: &str, separator: Option<char>) -> Property {
let mut property: Property = Property::new();
let sep: char = match separator {
None => SEPARATOR,
Some(c) => c,
};
let split: Vec<&str> = line.split(sep).collect();
assert_eq!(split.len(), 2, "Invalid property line. Expected format: \"key{}value\"", sep);
property.key = split.first().unwrap().trim();
property.value = split.last().unwrap().trim();
return property;
}
fn check_line(line: &str, separator: char) -> bool {
let mut i = 0;
line.chars().for_each(|c| {
if c == separator {
i += 1;
}
});
if i != 1 {
return false;
}
return true;
}
pub fn try_split<'a>(
line: &'a str,
separator: Option<char>,
comment: Option<&'a str>,
) -> Option<Property<'a>> {
if line.is_empty() {
return None;
}
match comment {
None => {}
Some(c) => {
if line.starts_with(c) {
return None;
}
}
}
if separator == None && !check_line(line, SEPARATOR) {
return None;
} else {
if !check_line(line, separator.unwrap()) {
return None;
}
}
return Some(split(line, separator));
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let property: Property = Property::new();
assert_eq!(property.key(), String::new());
assert_eq!(property.value(), String::new());
}
#[test]
fn test_init() {
let property: Property = Property::init("foo", "bar");
assert_eq!(property.key(), String::from("foo"));
assert_eq!(property.value(), String::from("bar"));
}
#[test]
fn test_split() {
let expected: Property = Property::init("foo", "bar");
assert_eq!(split("foo: bar", Some(':')), expected);
}
#[test]
fn test_try_split() {
assert_eq!(try_split("", None, None), None);
assert_eq!(try_split("foo:bar:baz", Some(':'), None), None);
assert_eq!(try_split("//foo:bar", Some(':'), Some("//")), None);
let expected: Property = Property::init("foo", "bar");
assert_eq!(try_split("foo:bar", Some(':'), Some("//")), Some(expected));
}
}