@@ -1329,6 +1329,78 @@ pub trait Seek {
1329
1329
/// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
1330
1330
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1331
1331
fn seek ( & mut self , pos : SeekFrom ) -> Result < u64 > ;
1332
+
1333
+ /// Returns the length of this stream (in bytes).
1334
+ ///
1335
+ /// This method is implemented using three seek operations. If this method
1336
+ /// returns successfully, the seek position is unchanged (i.e. the position
1337
+ /// before calling this method is the same as afterwards). However, if this
1338
+ /// method returns an error, the seek position is undefined.
1339
+ ///
1340
+ /// If you need to obtain the length of *many* streams and you don't care
1341
+ /// about the seek position afterwards, you can reduce the number of seek
1342
+ /// operations by simply calling `seek(SeekFrom::End(0))` and use its
1343
+ /// return value (it is also the stream length).
1344
+ ///
1345
+ /// Note that length of a stream can change over time (for example, when
1346
+ /// data is appended to a file). So calling this method multiply times does
1347
+ /// not necessarily return the same length each time.
1348
+ ///
1349
+ ///
1350
+ /// # Example
1351
+ ///
1352
+ /// ```no_run
1353
+ /// #![feature(seek_convenience)]
1354
+ /// use std::{
1355
+ /// io::{self, Seek},
1356
+ /// fs::File,
1357
+ /// };
1358
+ ///
1359
+ /// fn main() -> io::Result<()> {
1360
+ /// let mut f = File::open("foo.txt")?;
1361
+ ///
1362
+ /// let len = f.stream_len()?;
1363
+ /// println!("The file is currently {} bytes long", len);
1364
+ /// Ok(())
1365
+ /// }
1366
+ /// ```
1367
+ #[ unstable( feature = "seek_convenience" , issue = "0" ) ]
1368
+ fn stream_len ( & mut self ) -> Result < u64 > {
1369
+ let old_pos = self . stream_position ( ) ?;
1370
+ let len = self . seek ( SeekFrom :: End ( 0 ) ) ?;
1371
+ self . seek ( SeekFrom :: Start ( old_pos) ) ?;
1372
+ Ok ( len)
1373
+ }
1374
+
1375
+ /// Returns the current seek position from the start of the stream.
1376
+ ///
1377
+ /// This is equivalent to `self.seek(SeekFrom::Current(0))`.
1378
+ ///
1379
+ ///
1380
+ /// # Example
1381
+ ///
1382
+ /// ```no_run
1383
+ /// #![feature(seek_convenience)]
1384
+ /// use std::{
1385
+ /// io::{self, BufRead, BufReader, Seek},
1386
+ /// fs::File,
1387
+ /// };
1388
+ ///
1389
+ /// fn main() -> io::Result<()> {
1390
+ /// let mut f = BufReader::new(File::open("foo.txt")?);
1391
+ ///
1392
+ /// let before = f.stream_position()?;
1393
+ /// f.read_line(&mut String::new())?;
1394
+ /// let after = f.stream_position()?;
1395
+ ///
1396
+ /// println!("The first line was {} bytes long", after - before);
1397
+ /// Ok(())
1398
+ /// }
1399
+ /// ```
1400
+ #[ unstable( feature = "seek_convenience" , issue = "0" ) ]
1401
+ fn stream_position ( & mut self ) -> Result < u64 > {
1402
+ self . seek ( SeekFrom :: Current ( 0 ) )
1403
+ }
1332
1404
}
1333
1405
1334
1406
/// Enumeration of possible methods to seek within an I/O object.
@@ -2157,8 +2229,7 @@ impl<B: BufRead> Iterator for Lines<B> {
2157
2229
mod tests {
2158
2230
use crate :: io:: prelude:: * ;
2159
2231
use crate :: io;
2160
- use super :: Cursor ;
2161
- use super :: repeat;
2232
+ use super :: { Cursor , SeekFrom , repeat} ;
2162
2233
2163
2234
#[ test]
2164
2235
#[ cfg_attr( target_os = "emscripten" , ignore) ]
@@ -2380,4 +2451,50 @@ mod tests {
2380
2451
super :: read_to_end ( & mut lr, & mut vec)
2381
2452
} ) ;
2382
2453
}
2454
+
2455
+ #[ test]
2456
+ fn seek_len ( ) -> io:: Result < ( ) > {
2457
+ let mut c = Cursor :: new ( vec ! [ 0 ; 15 ] ) ;
2458
+ assert_eq ! ( c. stream_len( ) ?, 15 ) ;
2459
+
2460
+ c. seek ( SeekFrom :: End ( 0 ) ) ?;
2461
+ let old_pos = c. stream_position ( ) ?;
2462
+ assert_eq ! ( c. stream_len( ) ?, 15 ) ;
2463
+ assert_eq ! ( c. stream_position( ) ?, old_pos) ;
2464
+
2465
+ c. seek ( SeekFrom :: Start ( 7 ) ) ?;
2466
+ c. seek ( SeekFrom :: Current ( 2 ) ) ?;
2467
+ let old_pos = c. stream_position ( ) ?;
2468
+ assert_eq ! ( c. stream_len( ) ?, 15 ) ;
2469
+ assert_eq ! ( c. stream_position( ) ?, old_pos) ;
2470
+
2471
+ Ok ( ( ) )
2472
+ }
2473
+
2474
+ #[ test]
2475
+ fn seek_position ( ) -> io:: Result < ( ) > {
2476
+ // All `asserts` are duplicated here to make sure the method does not
2477
+ // change anything about the seek state.
2478
+ let mut c = Cursor :: new ( vec ! [ 0 ; 15 ] ) ;
2479
+ assert_eq ! ( c. stream_position( ) ?, 0 ) ;
2480
+ assert_eq ! ( c. stream_position( ) ?, 0 ) ;
2481
+
2482
+ c. seek ( SeekFrom :: End ( 0 ) ) ?;
2483
+ assert_eq ! ( c. stream_position( ) ?, 15 ) ;
2484
+ assert_eq ! ( c. stream_position( ) ?, 15 ) ;
2485
+
2486
+
2487
+ c. seek ( SeekFrom :: Start ( 7 ) ) ?;
2488
+ c. seek ( SeekFrom :: Current ( 2 ) ) ?;
2489
+ assert_eq ! ( c. stream_position( ) ?, 9 ) ;
2490
+ assert_eq ! ( c. stream_position( ) ?, 9 ) ;
2491
+
2492
+ c. seek ( SeekFrom :: End ( -3 ) ) ?;
2493
+ c. seek ( SeekFrom :: Current ( 1 ) ) ?;
2494
+ c. seek ( SeekFrom :: Current ( -5 ) ) ?;
2495
+ assert_eq ! ( c. stream_position( ) ?, 8 ) ;
2496
+ assert_eq ! ( c. stream_position( ) ?, 8 ) ;
2497
+
2498
+ Ok ( ( ) )
2499
+ }
2383
2500
}
0 commit comments