@@ -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