Read and Write

Using Read and BufRead, you can abstract over u8 sources:

1. ```
   use std::io::{BufRead, BufReader, Read, Result};
   ```

3. ```
   fn count_lines<R: Read>(reader: R) -> usize {
   ```
4. ```
       let buf_reader = BufReader::new(reader);
   ```
5. ```
       buf_reader.lines().count()
   ```
6. ```
   }
   ```

8. ```
   fn main() -> Result<()> {
   ```
9. ```
       let slice: &[u8] = b"foo\nbar\nbaz\n";
   ```
10. ```
        println!("lines in slice: {}", count_lines(slice));
    ```

12. ```
        let file = std::fs::File::open(std::env::current_exe()?)?;
    ```
13. ```
        println!("lines in file: {}", count_lines(file));
    ```
14. ```
        Ok(())
    ```
15. ```
    }
    ```

Similarly, Write lets you abstract over u8 sinks:

1. ```
   use std::io::{Result, Write};
   ```

3. ```
   fn log&lt;W: Write>(writer: &mut W, msg: &str) -> Result<()> {
   ```
4. ```
       writer.write_all(msg.as_bytes())?;
   ```
5. ```
       writer.write_all("\n".as_bytes())
   ```
6. ```
   }
   ```

8. ```
   fn main() -> Result<()> {
   ```
9. ```
       let mut buffer = Vec::new();
   ```
10. ```
        log(&mut buffer, "Hello")?;
    ```
11. ```
        log(&mut buffer, "World")?;
    ```
12. ```
        println!("Logged: {buffer:?}");
    ```
13. ```
        Ok(())
    ```
14. ```
    }
    ```