1#![doc(html_root_url = "https://docs.rs/io_wrapper_statistics/0.1.1")]
2
3use std::io::{Read, Write, Seek, SeekFrom};
4use std::io::Result as IOResult;
5use std::io::ErrorKind;
6use std::io::{IoSlice, IoSliceMut};
7#[rustversion::nightly]
8#[cfg(feature = "read_initializer")]
9use std::io::Initializer;
10
11use std::convert::TryFrom;
12
13use std::iter::Extend;
14
15use num_traits::{PrimInt, Unsigned, Signed};
16
17pub use success_failure_ctr::SuccessFailureCounter;
18
19pub mod success_failure_ctr {
20 use num_traits::{PrimInt, Unsigned};
21
22 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
23 pub struct SuccessFailureCounter<T: PrimInt + Unsigned> {
25 success_ctr: T,
26 failure_ctr: T
27 }
28 impl<T: PrimInt + Unsigned> SuccessFailureCounter<T> {
29 pub fn increment_success(&mut self) {
30 self.success_ctr = self.success_ctr + T::one();
31 }
32 pub fn add_successes(&mut self, amount: T) {
33 self.success_ctr = self.success_ctr + amount;
34 }
35 pub fn success_ctr(&self) -> T {
36 self.success_ctr
37 }
38 pub fn increment_failure(&mut self) {
39 self.failure_ctr = self.failure_ctr + T::one();
40 }
41 pub fn add_failures(&mut self, amount: T) {
42 self.failure_ctr = self.failure_ctr + amount;
43 }
44 pub fn failure_ctr(&self) -> T {
45 self.failure_ctr
46 }
47 pub fn attempt_ctr(&self) -> T {
48 self.success_ctr + self.failure_ctr
49 }
50 }
51}
52
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54enum SignedAbsResult<T: PrimInt + Unsigned> {
55 Negative(T),
56 Zero,
57 Positive(T)
58}
59fn abs_sign_tuple<S, U>(signed_number: S) -> SignedAbsResult<U>
63where
64 S: PrimInt + Signed,
65 U: PrimInt + Unsigned
66{
67 if signed_number.signum() == S::one() {
69 SignedAbsResult::Positive(U::from(signed_number.abs()).unwrap())
70 } else if signed_number.signum() == S::zero() {
71 SignedAbsResult::Zero
72 } else if signed_number.signum() == -S::one() {
73 if signed_number == S::min_value() {
74 SignedAbsResult::Negative(U::from(S::max_value()).unwrap()+U::one())
77 } else {
78 SignedAbsResult::Negative(U::from(signed_number.abs()).unwrap())
79 }
80 } else {
81 unreachable!()
82 }
83}
84
85#[derive(Debug, Clone, Copy)]
86pub enum IopActions {
88 Read(usize),
90 Seek(SeekFrom),
92 Write(usize),
94 Flush
96}
97#[derive(Debug, Clone, Copy)]
98pub enum IopResults {
102 Read(Result<usize, ErrorKind>),
104 Seek(Result<u64, ErrorKind>),
106 Write(Result<usize, ErrorKind>),
108 Flush(Result<(), ErrorKind>)
110}
111pub type IopInfoPair = (IopActions, IopResults);
112
113#[derive(Debug)]
114pub struct IOStatWrapper<T, C> {
116 inner_io: T,
117 iop_log: C,
118 read_call_counter: SuccessFailureCounter<u64>,
119 read_byte_counter: usize,
120 seek_call_counter: SuccessFailureCounter<u64>,
121 seek_pos: u64, write_call_counter: SuccessFailureCounter<u64>,
123 write_flush_counter: SuccessFailureCounter<u64>,
124 write_byte_counter: usize
125}
126
127impl<T, C> IOStatWrapper<T, C>
128where
129 C: Default + Extend<IopInfoPair>
130{
131 pub fn new(obj: T, start_seek_pos: u64) -> IOStatWrapper<T, C> {
134 IOStatWrapper {
135 inner_io: obj,
136 iop_log: C::default(),
137 read_call_counter: SuccessFailureCounter::default(),
138 read_byte_counter: 0,
139 seek_call_counter: SuccessFailureCounter::default(),
140 seek_pos: start_seek_pos,
141 write_call_counter: SuccessFailureCounter::default(),
142 write_flush_counter: SuccessFailureCounter::default(),
143 write_byte_counter: 0
144 }
145 }
146 pub fn into_inner(self) -> T {
148 self.inner_io
149 }
150 pub fn iop_log(&self) -> &C {
152 &self.iop_log
153 }
154}
155
156impl<T: Read, C: Extend<IopInfoPair>> Read for IOStatWrapper<T, C> {
157 fn read(&mut self, buf: &mut [u8]) -> IOResult<usize> {
161 let read_result = self.inner_io.read(buf);
163 let extend_item: [IopInfoPair; 1] = match read_result {
164 Ok(n) => {
165 self.read_call_counter.increment_success();
166 self.read_byte_counter += n;
167 self.seek_pos += u64::try_from(n).unwrap();
168 [(IopActions::Read(buf.len()),
169 IopResults::Read(Ok(n)))]
170 },
171 Err(ref e) => {
172 self.read_call_counter.increment_failure();
173 [(IopActions::Read(buf.len()),
174 IopResults::Read(Err(e.kind())))]
175 }
176 };
177 self.iop_log.extend(extend_item);
178 read_result
179 }
180
181 #[rustversion::since(1.36)]
182 fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> IOResult<usize> {
183 self.inner_io.read_vectored(bufs)
184 }
185 #[rustversion::nightly]
186 #[cfg(feature = "can_vector")]
187 fn is_read_vectored(&self) -> bool {
188 self.inner_io.is_read_vectored()
189 }
190 #[rustversion::nightly]
191 #[inline]
192 #[cfg(feature = "read_initializer")]
193 unsafe fn initializer(&self) -> Initializer {
194 self.inner_io.initializer()
195 }
196 fn read_to_end(&mut self, buf: &mut Vec<u8>) -> IOResult<usize> {
197 self.inner_io.read_to_end(buf)
198 }
199 fn read_to_string(&mut self, buf: &mut String) -> IOResult<usize> {
200 self.inner_io.read_to_string(buf)
201 }
202 #[rustversion::since(1.6)]
203 fn read_exact(&mut self, buf: &mut [u8]) -> IOResult<()> {
204 self.inner_io.read_exact(buf)
205 }
206 fn by_ref(&mut self) -> &mut Self
207 where
208 Self: Sized,
209 {
210 self
212 }
213 }
235impl<T: Read, C> IOStatWrapper<T, C> {
236 pub fn read_call_counter(&self) -> &SuccessFailureCounter<u64> {
238 &self.read_call_counter
239 }
240 pub fn read_byte_counter(&self) -> usize {
242 self.read_byte_counter
243 }
244}
245
246impl<T: Seek, C: Extend<IopInfoPair>> Seek for IOStatWrapper<T, C> {
247 fn seek(&mut self, pos: SeekFrom) -> IOResult<u64> {
250 let old_pos = self.seek_pos;
252 let seek_result = self.inner_io.seek(pos);
253 let extend_item: [IopInfoPair; 1] = match seek_result {
254 Ok(n) => {
255 self.seek_call_counter.increment_success();
256 self.seek_pos = n;
257 if let SeekFrom::Current(offset) = pos {
258 match abs_sign_tuple::<i64, u64>(offset) {
259 SignedAbsResult::Zero => {
260 debug_assert_eq!(old_pos, n);
261 },
262 SignedAbsResult::Positive(a) => {
263 debug_assert_eq!(old_pos+a, n)
264 },
265 SignedAbsResult::Negative(a) => {
266 debug_assert_eq!(old_pos-a, n)
267 }
268 }
269 };
270 [(IopActions::Seek(pos),
271 IopResults::Seek(Ok(n)))]
272 },
273 Err(ref e) => {
274 self.seek_call_counter.increment_failure();
275 [(IopActions::Seek(pos),
276 IopResults::Seek(Err(e.kind())))]
277 }
278 };
279 self.iop_log.extend(extend_item);
280 seek_result
281 }
282 #[rustversion::since(1.55)]
283 fn rewind(&mut self) -> IOResult<()> {
284 self.inner_io.rewind()
285 }
286 #[rustversion::nightly]
287 #[cfg(feature = "seek_stream_len")]
288 fn stream_len(&mut self) -> IOResult<u64> {
289 self.inner_io.stream_len()
290 }
291 #[rustversion::since(1.51)]
292 fn stream_position(&mut self) -> IOResult<u64> {
293 self.inner_io.stream_position()
294 }
295}
296impl<T: Seek, C> IOStatWrapper<T, C> {
297 pub fn seek_call_counter(&self) -> &SuccessFailureCounter<u64> {
299 &self.seek_call_counter
300 }
301 pub fn seek_pos(&self) -> u64 {
306 self.seek_pos
307 }
308}
309
310impl<T: Write, C: Extend<IopInfoPair>> Write for IOStatWrapper<T, C> {
311 fn write(&mut self, buf: &[u8]) -> IOResult<usize> {
314 let write_result = self.inner_io.write(buf);
316 let extend_item: [IopInfoPair; 1] = match write_result {
317 Ok(n) => {
318 self.write_call_counter.increment_success();
319 self.write_byte_counter += n;
320 self.seek_pos += u64::try_from(n).unwrap();
321 [(IopActions::Write(buf.len()),
322 IopResults::Write(Ok(n)))]
323 },
324 Err(ref e) => {
325 self.write_call_counter.increment_failure();
326 [(IopActions::Write(buf.len()),
327 IopResults::Write(Err(e.kind())))]
328 }
329 };
330 self.iop_log.extend(extend_item);
331 write_result
332 }
333 fn flush(&mut self) -> IOResult<()> {
334 let flush_result = self.inner_io.flush();
336 let extend_item: [IopInfoPair; 1] = match flush_result {
337 Ok(()) => {
338 self.write_flush_counter.increment_success();
339 [(IopActions::Flush, IopResults::Flush(Ok(())))]
340 },
341 Err(ref e) => {
342 self.write_flush_counter.increment_failure();
343 [(IopActions::Flush,
344 IopResults::Flush(Err(e.kind())))]
345 }
346 };
347 self.iop_log.extend(extend_item);
348 flush_result
349 }
350
351 #[rustversion::since(1.36.0)]
352 fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> IOResult<usize> {
353 self.inner_io.write_vectored(bufs)
354 }
355 #[rustversion::nightly]
356 #[cfg(feature = "can_vector")]
357 fn is_write_vectored(&self) -> bool {
358 self.inner_io.is_write_vectored()
359 }
360 #[allow(unused_mut)]
362 fn write_all(&mut self, mut buf: &[u8]) -> IOResult<()> {
363 self.inner_io.write_all(buf)
364 }
365 #[rustversion::nightly]
366 #[cfg(feature = "write_all_vectored")]
367 fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> IOResult<()> {
368 self.inner_io.write_all_vectored(bufs)
369 }
370 fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> IOResult<()> {
371 self.inner_io.write_fmt(fmt)
372 }
373 fn by_ref(&mut self) -> &mut Self
374 where
375 Self: Sized,
376 {
377 self
379 }
380}
381impl<T: Write, C> IOStatWrapper<T, C> {
382 pub fn write_call_counter(&self) -> &SuccessFailureCounter<u64> {
384 &self.write_call_counter
385 }
386 pub fn write_flush_counter(&self) -> &SuccessFailureCounter<u64> {
388 &self.write_flush_counter
389 }
390 pub fn write_byte_counter(&self) -> usize {
391 self.write_byte_counter
392 }
393}