1010#[ macro_use]
1111extern crate amplify;
1212
13- use std:: fs:: File ;
13+ use std:: fs:: { File , OpenOptions } ;
1414use std:: io:: { self , Read , Write } ;
1515use std:: ops:: { Deref , DerefMut } ;
1616use std:: path:: Path ;
@@ -97,26 +97,43 @@ impl<const MAGIC: u64, const VERSION: u16> BinFile<MAGIC, VERSION> {
9797 /// bytes) and version number (2 bytes). The produced file stream will start at byte offset 10.
9898 pub fn open ( path : impl AsRef < Path > ) -> io:: Result < Self > {
9999 let path = path. as_ref ( ) ;
100- let mut file = File :: open ( & path) ?;
100+ let mut file = Self ( File :: open ( & path) ?) ;
101+ file. check ( & path) ?;
102+ Ok ( file)
103+ }
104+
105+ /// Attempts to open a file in read-write mode the same way as [`OpenOptions::new`], followed by
106+ /// `read(true)` and `write(true)` calls does.
107+ ///
108+ /// Then it reads first 10 bytes of the file and verifies them to match the magic number (8
109+ /// bytes) and version number (2 bytes). The produced file stream will start at byte offset 10.
110+ pub fn open_rw ( path : impl AsRef < Path > ) -> io:: Result < Self > {
111+ let path = path. as_ref ( ) ;
112+ let mut file = Self ( OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( & path) ?) ;
113+ file. check ( & path) ?;
114+ Ok ( file)
115+ }
116+
117+ fn check ( & mut self , filename : & Path ) -> io:: Result < ( ) > {
101118 let mut magic = [ 0u8 ; 8 ] ;
102- file . read_exact ( & mut magic) ?;
119+ self . read_exact ( & mut magic) ?;
103120 if magic != MAGIC . to_be_bytes ( ) {
104121 return Err ( io:: Error :: other ( BinFileError :: InvalidMagic {
105- filename : path . to_string_lossy ( ) . to_string ( ) ,
122+ filename : filename . to_string_lossy ( ) . to_string ( ) ,
106123 expected : MAGIC ,
107124 actual : u64:: from_be_bytes ( magic) ,
108125 } ) ) ;
109126 }
110127 let mut version = [ 0u8 ; 2 ] ;
111- file . read_exact ( & mut version) ?;
128+ self . read_exact ( & mut version) ?;
112129 if version != VERSION . to_be_bytes ( ) {
113130 return Err ( io:: Error :: other ( BinFileError :: InvalidVersion {
114- filename : path . to_string_lossy ( ) . to_string ( ) ,
131+ filename : filename . to_string_lossy ( ) . to_string ( ) ,
115132 expected : VERSION ,
116133 actual : u16:: from_be_bytes ( version) ,
117134 } ) ) ;
118135 }
119- Ok ( Self ( file ) )
136+ Ok ( ( ) )
120137 }
121138}
122139
@@ -177,7 +194,7 @@ mod tests {
177194 }
178195
179196 #[ test]
180- fn open ( ) {
197+ fn open_ro ( ) {
181198 const MY_MAGIC : u64 = u64:: from_be_bytes ( * b"MYMAGIC!" ) ;
182199 let mut file = BinFile :: < MY_MAGIC , 1 > :: create ( "target/test3" ) . unwrap ( ) ;
183200 file. write_all ( b"hello world" ) . unwrap ( ) ;
@@ -190,6 +207,21 @@ mod tests {
190207 assert_eq ! ( buf, b"hello world" ) ;
191208 }
192209
210+ #[ test]
211+ fn open_rw ( ) {
212+ const MY_MAGIC : u64 = u64:: from_be_bytes ( * b"MYMAGIC!" ) ;
213+ let mut file = BinFile :: < MY_MAGIC , 1 > :: create ( "target/test5" ) . unwrap ( ) ;
214+ file. write_all ( b"hello world" ) . unwrap ( ) ;
215+ file. flush ( ) . unwrap ( ) ;
216+
217+ let mut file = BinFile :: < MY_MAGIC , 1 > :: open_rw ( "target/test5" ) . unwrap ( ) ;
218+ let mut buf = Vec :: new ( ) ;
219+ let check = file. read_to_end ( & mut buf) . unwrap ( ) ;
220+ assert_eq ! ( check, 11 ) ;
221+ assert_eq ! ( buf, b"hello world" ) ;
222+ file. write_all ( b"\n and hello again" ) . unwrap ( ) ;
223+ }
224+
193225 #[ test]
194226 fn open_wrong_magic ( ) {
195227 const MY_MAGIC : u64 = u64:: from_be_bytes ( * b"MYMAGIC!" ) ;
0 commit comments