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}