1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
use std::fs::File; use std::io::{Read, Seek, SeekFrom}; use crate::error::{Error, ErrorKind, Result}; /// Returns the last byte of a file, an in-memory cursor, or anything that /// implements `Read` and `Seek`. /// /// Note that this function does not alter the internal cursor of the given /// input. /// /// # Errors /// /// If the given reader is empty, an error variant of `ErrorKind::SeekNegative` will /// be returned. If this function encounters other errors, an error variant /// of `ErrorKind::Io` will be returned. /// /// # Examples /// /// ``` /// use fcc::get_last_byte; /// use std::io::Cursor; /// /// let mut cursor = Cursor::new(vec![1, 2, 3, b'\n']); /// let last_byte = get_last_byte(&mut cursor).unwrap(); /// /// assert_eq!(last_byte, b'\n'); /// ``` pub fn get_last_byte<R: Read + Seek>(f: &mut R) -> Result<u8> { let mut buf = [0; 1]; if let Err(_) = f.seek(SeekFrom::End(-1)) { return Err(Error::new(ErrorKind::SeekNegative)); } f.read_exact(&mut buf)?; f.seek(SeekFrom::Start(0))?; // reset the internal cursor Ok(buf[0]) } /// Checks if a given file ends with newline. /// /// This function returns `Ok(true)` if the given file ends with /// a newline `\n`, or returns `Ok(false)` if the given file does /// not end with a newline `\n'. /// /// # Errors /// /// This function has the same error semantics as [`get_last_byte`], /// except that if the given file is empty, it will return `Ok(false)` /// rather than return an error variant of `ErrorKind::SeekNegative`. /// /// # Examples /// /// ```no_run /// use fcc::ends_with_newline; /// use std::fs::File; /// use std::io::prelude::*; /// /// fn main() -> std::io::Result<()> { /// let mut f = File::create("foo.txt")?; /// /// f.write_all(b"Hello world!")?; /// assert_eq!(ends_with_newline(&mut f).unwrap(), false); /// /// f.write_all(b"Hello world!\n")?; /// assert_eq!(ends_with_newline(&mut f).unwrap(), true); /// Ok(()) /// } /// ``` /// /// [`get_last_byte`]: ./fn.get_last_byte.html pub fn ends_with_newline(f: &mut File) -> Result<bool> { let byte = get_last_byte(f); match byte { Ok(v) => match v { b'\n' => Ok(true), _ => Ok(false), }, Err(e) => match e.kind() { ErrorKind::SeekNegative => Ok(false), _ => Err(e), }, } }