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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
//! concat-reader is a library for Rust that contains utility functions and traits to create //! concatenated [`Read`] objects from any thing that implements [`IntoIterator`]. //! //! ```no_run //! use concat_reader::{FileConcatRead, concat_path}; //! use std::io::{self, Read, BufRead, BufReader, Write}; //! fn main() -> io::Result<()>{ //! let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"]; //! let mut f = concat_path(files); //! let mut buffered = BufReader::new(f); //! let stdout = io::stdout(); //! let mut handle = stdout.lock(); //! loop { //! let mut line = String::new(); //! let r = buffered.read_line(&mut line)?; //! if r == 0 { //! return Ok(()) //! } //! let f = buffered.get_ref().file_path(); //! eprintln!("read from {:?}", f); //! handle.write(line.as_bytes())?; //! } //! } //! ``` //! [`READ`]: https://doc.rust-lang.org/std/io/trait.Read.html //! [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html use std::io::Read; use std::path::Path; pub mod file; pub mod read; pub use self::file::FileConcatReader; pub use self::read::ConcatReader; /// Concats multiple readers into a single reader. /// /// ``` /// use concat_reader::concat; /// use std::io::Read; /// /// let value1 = "some string".as_bytes(); /// let value2 = "another string".as_bytes(); /// /// let mut buffer = String::new(); /// let mut f = concat(vec![value1, value2]); /// f.read_to_string(&mut buffer).unwrap(); /// ``` pub fn concat<I: IntoIterator>(items: I) -> impl ConcatRead where I::Item: Read, { read::ConcatReader::from(items) } /// Concats multiple file paths into a single reader over all files. /// /// ```no_run /// use concat_reader::{FileConcatRead, concat_path}; /// use std::io::{self, Read, BufRead, BufReader, Write}; /// fn main() -> io::Result<()>{ /// let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"]; /// let mut f = concat_path(files); /// let mut buffered = BufReader::new(f); /// let stdout = io::stdout(); /// let mut handle = stdout.lock(); /// loop { /// let mut line = String::new(); /// let r = buffered.read_line(&mut line)?; /// if r == 0 { /// return Ok(()) /// } /// let f = buffered.get_ref().file_path(); /// eprintln!("read from {:?}", f); /// handle.write(line.as_bytes())?; /// } /// } /// ``` pub fn concat_path<I: IntoIterator>(items: I) -> impl FileConcatRead where I::Item: AsRef<Path>, { file::FileConcatReader::from(items) } /// A special [`Read`] trait for concatenated readers. /// /// This traids adds special function to fetch the current `Read` item and to skip to the next item. pub trait ConcatRead: Read { type Item; /// Skips to the next [`Read`] item in the internal [`Iterator`]. /// /// ```rust /// use concat_reader::concat; /// use std::io::{self, Read}; /// use crate::concat_reader::ConcatRead; /// /// fn main() -> io::Result<()> { /// let value1 = "some string".as_bytes(); /// let value2 = "another string".as_bytes(); /// /// let mut buffer = [0; 4]; /// let mut f = concat(vec![value1, value2]); /// f.read_exact(&mut buffer)?; /// assert_eq!(buffer, "some".as_bytes()); /// /// //skip to the next Read object /// f.skip(); /// f.read_exact(&mut buffer)?; /// assert_eq!(buffer, "anot".as_bytes()); /// Ok(()) /// } /// ``` /// [`READ`]: https://doc.rust-lang.org/std/io/trait.Read.html /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html /// fn skip(&mut self) -> bool; /// Returns the current `Read` item in the internal iterator being read from. fn current(&self) -> Option<&Self::Item>; } /// `FileConcatRead` is a kind of `ConcatRead` which can provide information about the file currently read. /// /// # Example /// /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use std::path::Path; /// use crate::concat_reader::*; /// /// fn main() -> io::Result<()> { /// let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"]; /// let mut f = concat_path(files); /// assert!(f.file_path().is_none()); /// let mut buffer = [0; 10]; /// f.read(&mut buffer)?; /// assert_eq!(f.file_path(), Some(Path::new("/path/to/file_1"))); /// Ok(()) /// } pub trait FileConcatRead: ConcatRead { /// Returns the path to the current [`File`] being read from. /// /// ```no_run /// use std::io; /// use std::io::prelude::*; /// use crate::concat_reader::*; /// /// fn main() -> io::Result<()> { /// let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"]; /// let mut f = concat_path(files); /// /// let mut buffer = [0; 1]; /// //read 1 bytes from the reader /// f.read_exact(&mut buffer); /// println!("read from {}", f.file_path().unwrap().display()); /// /// //skip to next file in reader /// f.skip(); /// /// //read 1 bytes from the reader /// f.read_exact(&mut buffer); /// println!("read from {}", f.file_path().unwrap().display()); /// Ok(()) /// } /// ``` /// /// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html fn file_path(&self) -> Option<&Path>; }