1- use std:: {
2- fs:: File ,
3- io:: { self , BufReader , Read } ,
4- path:: PathBuf ,
5- time:: SystemTime ,
6- } ;
1+ use std:: { fs:: File , io, mem:: take, path:: PathBuf , str:: from_utf8, time:: SystemTime } ;
72
8- use super :: { change :: Change , constants:: COULD_NOT_UNWRAP_FILENAME } ;
3+ use super :: constants:: COULD_NOT_UNWRAP_FILENAME ;
94
10- pub struct FileData {
5+ #[ derive( Debug ) ]
6+ pub struct FileData < ' a > {
117 path : PathBuf ,
12- lines : Vec < String > ,
13- changes : Vec < Change > ,
8+ lines : Vec < & ' a str > ,
149 modified : SystemTime ,
1510 ends_with_newline : bool ,
1611}
1712
18- impl FileData {
13+ impl < ' a > FileData < ' a > {
1914 pub fn ends_with_newline ( & self ) -> bool {
2015 self . ends_with_newline
2116 }
2217
23- pub fn get_file ( path : PathBuf ) -> io:: Result < Self > {
24- let file = File :: open ( path. clone ( ) ) ?;
18+ pub fn get_file (
19+ path : PathBuf ,
20+ lines : Vec < & ' a str > ,
21+ ends_with_newline : bool ,
22+ ) -> io:: Result < Self > {
23+ let file = File :: open ( & path) ?;
2524 let modified = file. metadata ( ) ?. modified ( ) ?;
26- let mut buf_reader = BufReader :: new ( file) ;
27- let mut content = String :: new ( ) ;
28- buf_reader. read_to_string ( & mut content) ?;
2925
30- let mut lines = content
31- . lines ( )
32- . map ( |line| line. to_string ( ) )
33- . collect :: < Vec < String > > ( ) ;
34-
35- let ends_with_newline = content. ends_with ( "\n " ) ;
36-
37- if ends_with_newline {
38- lines. push ( String :: from ( "" ) ) ;
39- }
40-
41- let changes = vec ! [ Change :: None ; lines. len( ) ] ;
42-
43- let result = Self {
26+ Ok ( Self {
4427 path,
4528 lines,
46- changes,
4729 modified,
4830 ends_with_newline,
49- } ;
50-
51- Ok ( result)
31+ } )
5232 }
5333
54- pub fn get_context_identifier ( & self , change_index : usize ) -> & str {
55- match self . changes [ change_index] {
56- Change :: None => " " ,
57- Change :: Unchanged ( _) => " " ,
58- Change :: Insert ( _) => "+" ,
59- Change :: Delete ( _) => "-" ,
60- Change :: Substitute ( _) => "!" ,
61- }
62- }
63-
64- pub fn lines ( & self ) -> & Vec < String > {
34+ pub fn lines ( & self ) -> & Vec < & str > {
6535 & self . lines
6636 }
6737
68- pub fn line ( & self , index : usize ) -> & String {
69- & self . lines [ index]
38+ pub fn line ( & self , index : usize ) -> & str {
39+ self . lines [ index]
7040 }
7141
7242 pub fn modified ( & self ) -> SystemTime {
@@ -80,35 +50,54 @@ impl FileData {
8050 }
8151 }
8252
83- return COULD_NOT_UNWRAP_FILENAME ;
53+ COULD_NOT_UNWRAP_FILENAME
8454 }
8555
86- pub fn set_change ( & mut self , change : Change , index : usize ) {
87- self . changes [ index ] = change ;
56+ pub fn path ( & self ) -> & str {
57+ self . path . to_str ( ) . unwrap_or ( COULD_NOT_UNWRAP_FILENAME )
8858 }
59+ }
8960
90- pub fn expected_changed_in_range (
91- & self ,
92- start : usize ,
93- end : usize ,
94- expected_changes : & Vec < fn ( & Change ) -> bool > ,
95- ) -> bool {
96- for i in start..=end {
97- for expected_change in expected_changes {
98- if expected_change ( & self . changes [ i] ) {
99- return true ;
100- }
101- }
102- }
61+ pub struct LineReader < ' a > {
62+ content : & ' a [ u8 ] ,
63+ ends_with_newline : bool ,
64+ }
10365
104- return false ;
66+ impl < ' a > LineReader < ' a > {
67+ pub fn new ( content : & ' a [ u8 ] ) -> Self {
68+ let ends_with_newline = content. last ( ) == Some ( & b'\n' ) ;
69+ Self {
70+ content,
71+ ends_with_newline,
72+ }
10573 }
106-
107- pub fn change ( & self , index : usize ) -> & Change {
108- & self . changes [ index]
74+ pub fn ends_with_newline ( & self ) -> bool {
75+ self . ends_with_newline
10976 }
77+ }
11078
111- pub fn path ( & self ) -> & str {
112- self . path . to_str ( ) . unwrap_or ( COULD_NOT_UNWRAP_FILENAME )
79+ impl < ' a > Iterator for LineReader < ' a > {
80+ type Item = & ' a str ;
81+
82+ fn next ( & mut self ) -> Option < Self :: Item > {
83+ let mut carriage = false ;
84+ let mut iter = self . content . iter ( ) . enumerate ( ) ;
85+ let mut line_len = loop {
86+ match iter. next ( ) {
87+ Some ( ( i, b'\n' ) ) => break i + 1 ,
88+ None => {
89+ return ( !self . content . is_empty ( ) ) . then ( || {
90+ from_utf8 ( take ( & mut self . content ) ) . expect ( "Failed to convert to str" )
91+ } ) ;
92+ }
93+ Some ( ( _, & it) ) => carriage = it == b'\r' ,
94+ }
95+ } ;
96+ let ( line, rest) = self . content . split_at ( line_len) ;
97+ if carriage {
98+ line_len -= 1 ;
99+ }
100+ self . content = rest;
101+ Some ( from_utf8 ( & line[ ..line_len - 1 ] ) . expect ( "Failed to convert to str" ) )
113102 }
114103}
0 commit comments