tap_reader/
lib.rs

1//! Tapped reader
2//!
3//! Wraps an existing reader and copies the read bytes into it's own buffer
4//!
5//! This can be useful for when you are deserializing a stream of bytes, and want to be able to
6//! provide the original input for log messages, error messages, etc
7//!
8//! # Example
9//!
10//! ```
11//! extern crate tap_reader;
12//! extern crate serde_json;
13//! extern crate serde;
14//! #[macro_use] extern crate serde_derive;
15//!
16//! # use std::error::Error;
17//! use std::io::Cursor;
18//! use tap_reader::Tap;
19//!
20//! # fn main() -> Result<(), ()> {
21//! #[derive(Debug, Deserialize, PartialEq)]
22//! struct Foo {
23//!     foo: String,
24//!     bar: usize,
25//! }
26//!
27//! let input = r#"{"foo":"hello, world!","bar":42}"#;
28//! let bytes = input.as_bytes();
29//! let reader = Cursor::new(bytes);
30//! let mut reader = Tap::new(reader);
31
32//! let foo: Foo = match serde_json::from_reader(&mut reader) {
33//!     Ok(foo) => foo,
34//!     Err(e) => {
35//!         eprintln!("Error serializing Foo from input: '{}'\n error was: {}",
36//!                   String::from_utf8_lossy(&reader.bytes),
37//!                   e.description());
38//!         return Err(());
39//!     }
40//! };
41//! assert_eq!(foo, Foo { foo: "hello, world!".to_string(), bar: 42 });
42//! assert_eq!(reader.bytes, bytes);
43//! #   Ok(())
44//! # }
45//!
46//! ```
47//!
48//! ```
49//! extern crate tap_reader;
50//!
51//! use std::io::{Cursor, Read};
52//!
53//! use tap_reader::Tap;
54//!
55//! # fn main() -> ::std::io::Result<()> {
56//! let input = "hello, world!".to_string();
57//! let bytes = input.as_bytes();
58//! let cursor = Cursor::new(bytes);
59//! let mut reader = Tap::new(cursor);
60//!
61//! let mut output = String::new();
62//!
63//! reader.read_to_string(&mut output)?;
64//!
65//! assert_eq!(output, input);
66//! assert_eq!(bytes, &reader.bytes[..]);
67//!
68//! #     Ok(())
69//! # }
70//! ```
71
72#[cfg(test)]
73extern crate serde;
74#[cfg(test)]
75extern crate serde_json;
76
77#[cfg(test)]
78#[cfg_attr(test, macro_use)]
79extern crate serde_derive;
80
81use std::io::{self, Read};
82
83/// `Read` adaptor
84///
85/// Takes a `Read` as input and copies all read bytes into it's own buffer
86///
87/// # Example
88///
89/// ```
90/// # extern crate tap_reader;
91/// use tap_reader::Tap;
92/// # use std::io;
93/// use std::io::{Cursor, Read};
94///
95/// # fn main() -> io::Result<()> {
96/// let input = "hello, world!";
97/// let bytes = input.as_bytes();
98/// let cursor = Cursor::new(bytes);
99/// let mut reader = Tap::new(cursor);
100///
101/// let mut output = String::new();
102/// reader.read_to_string(&mut output)?;
103///
104/// assert_eq!(output, String::from_utf8_lossy(&reader.bytes));
105/// #   Ok(())
106/// # }
107/// ```
108pub struct Tap<R> {
109    pub bytes: Vec<u8>,
110    reader: R,
111}
112
113impl<R: Read> Tap<R> {
114    /// Construct a `Tap` reader from an existing reader
115    ///
116    /// # Example
117    ///
118    /// ```
119    /// # extern crate tap_reader;
120    /// use std::io::Cursor;
121    /// use tap_reader::Tap;
122    /// let input = "hello, world!";
123    /// let bytes = input.as_bytes();
124    /// let cursor = Cursor::new(bytes);
125    /// let mut reader = Tap::new(cursor);
126    /// ```
127    pub fn new(r: R) -> Tap<R> {
128        Tap { bytes: vec![], reader: r }
129    }
130}
131
132impl<R: Read> Read for Tap<R> {
133    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
134        let num = self.reader.read(buf)?;
135        self.bytes.extend_from_slice(&buf[..num]);
136        Ok(num)
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use std::io::Cursor;
144
145    #[derive(Deserialize, Debug, PartialEq)]
146    struct Foo {
147        foo: String,
148        bar: u64,
149    }
150
151    #[test]
152    fn tap_serde_deser() {
153        let input = r#"{"foo":"hello, world!","bar":42}"#;
154        let bytes = input.as_bytes();
155        let reader = Cursor::new(bytes);
156        let mut reader = Tap::new(reader);
157
158        let foo: Foo = serde_json::from_reader(&mut reader).expect("Couldn't deserialize");
159        assert_eq!(
160            foo,
161            Foo {
162                foo: "hello, world!".to_string(),
163                bar: 42
164            }
165        );
166        assert_eq!(reader.bytes, bytes);
167    }
168
169    #[test]
170    fn tap_cursor() {
171        let s = String::from("foo bar");
172        let bytes = s.as_bytes();
173        let reader = Cursor::new(bytes);
174
175        let mut reader = Tap::new(reader);
176
177        let mut output = String::new();
178        reader.read_to_string(&mut output).expect("Could not read");
179
180        let tapped = reader.bytes;
181        assert_eq!(output, String::from_utf8(bytes.to_vec()).expect("Couldn't create string from bytes"));
182        assert_eq!(tapped, bytes);
183    }
184
185    #[test]
186    fn test_large_string() {
187        let text = r#"Demicyclic Disease: Because there is no repeating stage in the life cycle of demicyclic
188        fungi, removal of the primary or the alternate host will disrupt the disease cycle. This method, however,
189        is not highly effective in managing all demicyclic diseases. Cedar-apple rust disease, for example, can
190        persist despite removal of one of the hosts since spores can be disseminated from long distances. The 
191        severity of Cedar-apple rust disease can be managed by removal of basidiospore producing galls from 
192        junipers or the application of protective fungicides to junipers."#;
193
194        let bytes = text.as_bytes();
195        let cursor = Cursor::new(bytes);
196        let mut reader = Tap::new(cursor);
197
198        let mut output = String::new();
199        reader.read_to_string(&mut output).expect("Could not read");
200
201        let tapped = reader.bytes;
202        assert_eq!(output, String::from_utf8(bytes.to_vec()).expect("Couldn't create string from bytes"));
203        assert_eq!(tapped, bytes);
204    }
205}