Skip to content

Commit c562c41

Browse files
committed
🚀 Finishing the algorithm.
(but it still needs optimizations, by the way)
1 parent e5fa3db commit c562c41

4 files changed

Lines changed: 244 additions & 103 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "multipath"
3-
version = "0.1.0"
3+
version = "1.0.0"
44
authors = ["Jimskapt <rami.programmer@gmail.com>"]
55
description = "A library to split file path, like `/home/{user,admin}/file.txt`."
66
edition = "2018"

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,21 @@
22

33
A library to split file path, like `/home/{user,admin}/file.txt`.
44

5-
⚠ Warning : this version is not finished yet and should not be used in production. Take a look of [test accomplishments][GHA].
5+
⚠ Warning : this version now satisfies [all the tests][GHA]. However, I think the code need to be optimized !
66

77
Example :
88

99
```rust
1010
fn main() {
1111
assert_eq!(
12-
multipath::from("/home/{user,admin}/{Desktop,Download}/file.txt"),
12+
multipath::parse("/home/{user,admin}/{Desktop,Download}/file.txt"),
1313
vec![
1414
"/home/user/Desktop/file.txt",
1515
"/home/user/Download/file.txt",
1616
"/home/admin/Desktop/file.txt",
1717
"/home/admin/Download/file.txt",
1818
]
19+
);
1920
}
2021
```
2122

src/lib.rs

Lines changed: 102 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,123 @@
11
#[cfg(test)]
22
mod tests;
33

4-
pub fn from(input: &str) -> Vec<String> {
5-
let mut results: Vec<String> = Vec::new();
6-
7-
let mut value_buffer = input.clone();
8-
9-
while !value_buffer.is_empty() {
10-
// dbg!("new_loop", &value_buffer, &results);
11-
12-
if let Some(first_open) = value_buffer.find("{") {
13-
// dbg!(&first_open);
14-
let value_close_buffer = &value_buffer[first_open..];
15-
// dbg!(&value_close_buffer);
16-
let mut found = false;
17-
if let Some(first_close) = value_close_buffer.find("}") {
18-
// dbg!(&first_close);
19-
let split_potential = &value_buffer[first_open + 1..first_open + first_close];
20-
let split_potential: Vec<&str> =
21-
split_potential.split(',').map(|e| e.trim()).collect();
22-
// dbg!(&split_potential);
23-
24-
if split_potential.len() > 1 {
25-
if results.is_empty() {
26-
for split_content in &split_potential {
27-
let mut temp = String::from(&value_buffer[..first_open]);
28-
temp += split_content;
29-
results.push(temp);
30-
}
31-
} else {
32-
let mut new_results = vec![];
33-
34-
for split_value in split_potential {
35-
for result in &results {
36-
let mut new_result = result.clone();
37-
new_result += &value_buffer[..first_open];
38-
new_result += split_value;
39-
40-
new_results.push(new_result);
41-
}
42-
}
4+
const FLAG: &str = "[grgnrt64sg@rth144615r0jk]";
5+
6+
/**
7+
Split `input` as vector of string according to `{a,b,c}` schema.
8+
9+
**Warning :** in some specific case, result can return characters which are not
10+
supported by O.S. paths, like `'{'` or `','`.
11+
Read some [tests](https://github.com/Jimskapt/multipath/blob/master/src/tests.rs)
12+
in order to know more about this cases.
13+
14+
# Example
15+
16+
```rust
17+
assert_eq!(
18+
multipath::parse("/home/{user,admin}/{Desktop,Download}/file.txt"),
19+
vec![
20+
"/home/user/Desktop/file.txt",
21+
"/home/user/Download/file.txt",
22+
"/home/admin/Desktop/file.txt",
23+
"/home/admin/Download/file.txt",
24+
]
25+
);
26+
```
27+
*/
28+
pub fn parse(input: &str) -> Vec<String> {
29+
30+
// "start" begins after an `{`.
31+
let mut start_pos = 0;
32+
// "level" is current level of `{`.
33+
// example : in `` level is 0, in `{` level is 1, in `{{` level is 2, in `{{{` level is 3, ...
34+
let mut level = 0;
35+
36+
// a new element begins after an `{` or an `,`.
37+
// example : in `{a,b,c}`, elements are `a`, `b` and `c`.
38+
let mut previous_element_pos = 0;
39+
let mut elements = vec![];
40+
41+
for (i, character) in input.chars().enumerate() {
42+
if character == '{' {
43+
44+
level += 1;
45+
46+
if level == 1 {
47+
start_pos = i;
48+
previous_element_pos = start_pos;
49+
}
4350

44-
results = new_results;
45-
}
51+
} else if character == ',' && level == 1 {
4652

47-
value_buffer = &value_buffer[first_open + first_close + 1..];
48-
found = true;
49-
}
53+
let recursive_elements = parse(&input[previous_element_pos + 1..i].trim());
54+
for element in recursive_elements {
55+
elements.push(element);
5056
}
5157

52-
// dbg!(&found);
53-
if !found {
54-
if results.is_empty() {
55-
results.push(value_buffer[..first_open + 1].to_owned());
56-
} else {
57-
let mut new_results = vec![];
58-
59-
for result in &results {
60-
let mut new_result = result.clone();
61-
new_result += &value_buffer[..first_open + 1];
58+
previous_element_pos = i;
6259

63-
new_results.push(new_result);
64-
}
60+
} else if character == '}' {
6561

66-
results = new_results;
62+
if level == 1 {
63+
let last_recursive_elements = parse(&input[previous_element_pos + 1..i].trim());
64+
for element in last_recursive_elements {
65+
elements.push(element.clone());
6766
}
6867

69-
value_buffer = &value_buffer[first_open + 1..];
70-
}
71-
} else {
72-
if results.is_empty() {
73-
results.push(value_buffer.to_owned());
74-
} else {
75-
let mut new_results = vec![];
68+
if !elements.is_empty() {
69+
return elements
70+
.iter()
71+
.flat_map(|element| {
72+
let mut res = vec![];
73+
74+
let recursive_elements = parse(&input[i + 1..]);
75+
for recursive_element in recursive_elements {
76+
let mut temp = String::from(&input[..start_pos]);
77+
temp += &element;
78+
temp += &recursive_element;
7679

77-
for result in &results {
78-
let mut new_result = result.clone();
79-
new_result += &value_buffer;
80+
res.push(temp);
81+
}
8082

81-
new_results.push(new_result);
83+
res
84+
})
85+
.collect();
86+
} else {
87+
return vec![String::from(input)];
8288
}
89+
}
8390

84-
results = new_results;
91+
if level > 0 {
92+
level -= 1;
8593
}
8694

87-
value_buffer = "";
8895
}
8996
}
9097

91-
return results;
98+
if level > 0 {
99+
let mut last_open = 0;
100+
for (i, character) in input.chars().enumerate() {
101+
if character == '{' {
102+
last_open = i;
103+
}
104+
}
105+
106+
if last_open > 0 {
107+
let mut temp = String::from(&input[..last_open]);
108+
temp += FLAG;
109+
temp += &input[(last_open + 1)..];
110+
111+
dbg!(&temp);
112+
113+
let res = parse(&temp);
114+
115+
return res
116+
.iter()
117+
.map(|element| element.replace(FLAG, "{"))
118+
.collect();
119+
}
120+
}
121+
122+
return vec![String::from(input)];
92123
}

0 commit comments

Comments
 (0)