Skip to content

Commit 45fb86f

Browse files
authored
Merge pull request #313 from fox0/split
split: impl struct Suffix and add tests
2 parents 199f206 + 9e7f3ec commit 45fb86f

File tree

1 file changed

+67
-36
lines changed

1 file changed

+67
-36
lines changed

file/split.rs

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -55,48 +55,37 @@ struct Args {
5555
prefix: String,
5656
}
5757

58-
fn inc_char(ch: char) -> char {
59-
((ch as u8) + 1) as char
60-
}
61-
62-
struct OutputState {
63-
prefix: String,
64-
boundary: u64,
65-
58+
pub struct Suffix {
6659
suffix: String,
67-
suffix_len: u32,
68-
count: u64,
69-
outf: Option<File>,
7060
}
7161

72-
impl OutputState {
73-
fn new(prefix: &str, boundary: u64, suffix_len: u32) -> OutputState {
74-
OutputState {
75-
prefix: String::from(prefix),
76-
boundary,
77-
suffix_len,
78-
suffix: String::new(),
79-
count: 0,
80-
outf: None,
62+
impl Suffix {
63+
pub fn new(len: usize) -> Self {
64+
debug_assert!(len > 0);
65+
Self {
66+
suffix: "a".repeat(len),
8167
}
8268
}
8369

84-
fn incr_suffix(&mut self) -> Result<(), &'static str> {
85-
assert!(self.suffix_len > 1);
70+
fn inc_char(ch: char) -> char {
71+
debug_assert!('a' <= ch && ch < 'z');
72+
((ch as u8) + 1) as char
73+
}
74+
}
75+
76+
impl Iterator for Suffix {
77+
type Item = String;
8678

87-
if self.suffix.is_empty() {
88-
self.suffix = "a".repeat(self.suffix_len as usize);
89-
return Ok(());
90-
}
79+
fn next(&mut self) -> Option<Self::Item> {
80+
let current = self.suffix.clone();
9181

92-
assert!(self.suffix.len() > 1);
9382
let mut i = self.suffix.len() - 1;
9483
loop {
9584
let ch = self.suffix.chars().nth(i).unwrap();
9685
if ch != 'z' {
9786
self.suffix
98-
.replace_range(i..i + 1, inc_char(ch).to_string().as_str());
99-
return Ok(());
87+
.replace_range(i..i + 1, Self::inc_char(ch).to_string().as_str());
88+
return Some(current);
10089
}
10190

10291
self.suffix
@@ -107,21 +96,43 @@ impl OutputState {
10796
}
10897
i -= 1;
10998
}
99+
None
100+
}
101+
}
110102

111-
Err("maximum suffix reached")
103+
struct OutputState {
104+
prefix: String,
105+
boundary: u64,
106+
107+
suffix: Suffix,
108+
count: u64,
109+
outf: Option<File>,
110+
}
111+
112+
impl OutputState {
113+
fn new(prefix: &str, boundary: u64, suffix_len: u32) -> OutputState {
114+
OutputState {
115+
prefix: String::from(prefix),
116+
boundary,
117+
suffix: Suffix::new(suffix_len as usize),
118+
count: 0,
119+
outf: None,
120+
}
112121
}
113122

114123
fn open_output(&mut self) -> io::Result<()> {
115124
if self.outf.is_some() {
116125
return Ok(());
117126
}
118127

119-
let inc_res = self.incr_suffix();
120-
if let Err(e) = inc_res {
121-
return Err(Error::new(ErrorKind::Other, e));
122-
}
128+
let suffix = match self.suffix.next() {
129+
Some(s) => s,
130+
None => {
131+
return Err(Error::new(ErrorKind::Other, "maximum suffix reached"));
132+
}
133+
};
123134

124-
let out_fn = format!("{}{}", self.prefix, self.suffix);
135+
let out_fn = format!("{}{}", self.prefix, suffix);
125136
let f = OpenOptions::new()
126137
.read(false)
127138
.write(true)
@@ -152,7 +163,8 @@ impl OutputState {
152163
fn write(&mut self, buf: &[u8]) -> io::Result<()> {
153164
match &mut self.outf {
154165
Some(ref mut f) => f.write_all(buf),
155-
None => Ok(()),
166+
// TODO:
167+
None => panic!("unreachable"),
156168
}
157169
}
158170

@@ -265,3 +277,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
265277

266278
Ok(())
267279
}
280+
281+
#[cfg(test)]
282+
mod tests {
283+
use super::*;
284+
285+
#[test]
286+
fn test_suffix_inc_char() {
287+
assert_eq!(Suffix::inc_char('a'), 'b');
288+
assert_eq!(Suffix::inc_char('b'), 'c');
289+
assert_eq!(Suffix::inc_char('y'), 'z');
290+
}
291+
292+
#[ignore]
293+
#[test]
294+
fn test_suffix_iterable() {
295+
let suffix = Suffix::new(1);
296+
assert_eq!(suffix.count(), 26);
297+
}
298+
}

0 commit comments

Comments
 (0)