concat_reader/lib.rs
1//! concat-reader is a library for Rust that contains utility functions and traits to create
2//! concatenated [`Read`] objects from any thing that implements [`IntoIterator`].
3//!
4//! ```no_run
5//! use concat_reader::{FileConcatRead, concat_path};
6//! use std::io::{self, Read, BufRead, BufReader, Write};
7//! fn main() -> io::Result<()>{
8//! let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"];
9//! let mut f = concat_path(files);
10//! let mut buffered = BufReader::new(f);
11//! let stdout = io::stdout();
12//! let mut handle = stdout.lock();
13//! loop {
14//! let mut line = String::new();
15//! let r = buffered.read_line(&mut line)?;
16//! if r == 0 {
17//! return Ok(())
18//! }
19//! let f = buffered.get_ref().file_path();
20//! eprintln!("read from {:?}", f);
21//! handle.write(line.as_bytes())?;
22//! }
23//! }
24//! ```
25//! [`READ`]: https://doc.rust-lang.org/std/io/trait.Read.html
26//! [`IntoIterator`]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html
27
28use std::io::Read;
29use std::path::Path;
30
31pub mod file;
32pub mod read;
33
34pub use self::file::FileConcatReader;
35pub use self::read::ConcatReader;
36
37/// Concats multiple readers into a single reader.
38///
39/// ```
40/// use concat_reader::concat;
41/// use std::io::Read;
42///
43/// let value1 = "some string".as_bytes();
44/// let value2 = "another string".as_bytes();
45///
46/// let mut buffer = String::new();
47/// let mut f = concat(vec![value1, value2]);
48/// f.read_to_string(&mut buffer).unwrap();
49/// ```
50pub fn concat<I: IntoIterator>(items: I) -> impl ConcatRead
51where
52 I::Item: Read,
53{
54 read::ConcatReader::from(items)
55}
56
57/// Concats multiple file paths into a single reader over all files.
58///
59/// ```no_run
60/// use concat_reader::{FileConcatRead, concat_path};
61/// use std::io::{self, Read, BufRead, BufReader, Write};
62/// fn main() -> io::Result<()>{
63/// let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"];
64/// let mut f = concat_path(files);
65/// let mut buffered = BufReader::new(f);
66/// let stdout = io::stdout();
67/// let mut handle = stdout.lock();
68/// loop {
69/// let mut line = String::new();
70/// let r = buffered.read_line(&mut line)?;
71/// if r == 0 {
72/// return Ok(())
73/// }
74/// let f = buffered.get_ref().file_path();
75/// eprintln!("read from {:?}", f);
76/// handle.write(line.as_bytes())?;
77/// }
78/// }
79/// ```
80pub fn concat_path<I: IntoIterator>(items: I) -> impl FileConcatRead
81where
82 I::Item: AsRef<Path>,
83{
84 file::FileConcatReader::from(items)
85}
86
87/// A special [`Read`] trait for concatenated readers.
88///
89/// This traids adds special function to fetch the current `Read` item and to skip to the next item.
90pub trait ConcatRead: Read {
91 type Item;
92
93 /// Skips to the next [`Read`] item in the internal [`Iterator`].
94 ///
95 /// ```rust
96 /// use concat_reader::concat;
97 /// use std::io::{self, Read};
98 /// use crate::concat_reader::ConcatRead;
99 ///
100 /// fn main() -> io::Result<()> {
101 /// let value1 = "some string".as_bytes();
102 /// let value2 = "another string".as_bytes();
103 ///
104 /// let mut buffer = [0; 4];
105 /// let mut f = concat(vec![value1, value2]);
106 /// f.read_exact(&mut buffer)?;
107 /// assert_eq!(buffer, "some".as_bytes());
108 ///
109 /// //skip to the next Read object
110 /// f.skip();
111 /// f.read_exact(&mut buffer)?;
112 /// assert_eq!(buffer, "anot".as_bytes());
113 /// Ok(())
114 /// }
115 /// ```
116 /// [`READ`]: https://doc.rust-lang.org/std/io/trait.Read.html
117 /// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html
118 ///
119 fn skip(&mut self) -> bool;
120
121 /// Returns the current `Read` item in the internal iterator being read from.
122 fn current(&self) -> Option<&Self::Item>;
123}
124
125/// `FileConcatRead` is a kind of `ConcatRead` which can provide information about the file currently read.
126///
127/// # Example
128///
129/// ```no_run
130/// use std::io;
131/// use std::io::prelude::*;
132/// use std::path::Path;
133/// use crate::concat_reader::*;
134///
135/// fn main() -> io::Result<()> {
136/// let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"];
137/// let mut f = concat_path(files);
138/// assert!(f.file_path().is_none());
139/// let mut buffer = [0; 10];
140/// f.read(&mut buffer)?;
141/// assert_eq!(f.file_path(), Some(Path::new("/path/to/file_1")));
142/// Ok(())
143/// }
144pub trait FileConcatRead: ConcatRead {
145 /// Returns the path to the current [`File`] being read from.
146 ///
147 /// ```no_run
148 /// use std::io;
149 /// use std::io::prelude::*;
150 /// use crate::concat_reader::*;
151 ///
152 /// fn main() -> io::Result<()> {
153 /// let files = vec!["/path/to/file_1", "/path/to/file_2", "/path/to/file_3"];
154 /// let mut f = concat_path(files);
155 ///
156 /// let mut buffer = [0; 1];
157 /// //read 1 bytes from the reader
158 /// f.read_exact(&mut buffer);
159 /// println!("read from {}", f.file_path().unwrap().display());
160 ///
161 /// //skip to next file in reader
162 /// f.skip();
163 /// /// //read 1 bytes from the reader
164 /// f.read_exact(&mut buffer);
165 /// println!("read from {}", f.file_path().unwrap().display());
166 /// Ok(())
167 /// }
168 /// ```
169 ///
170 /// [`File`]: https://doc.rust-lang.org/std/fs/struct.File.html
171 fn file_path(&self) -> Option<&Path>;
172}