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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! Provides `Read` and `Write` alternatives on `no_std` while being compatible with the full
//! traits from `std` when allowed.
//!
//! ## Motivation
//!
//! The file parser ecosystem of Rust is more or less split across crates that use `no_std` and
//! crates that do not, as well as between crates using `alloc` and no-alloc (and the largely
//! overlapping zero-copy) crates. This has several reasons:
//!
//! * The `std::io::Read` and `std::io::Write` traits require an allocator due to their internal
//!   implementation and were not written to be OS independent.
//! * Before `1.36` it was not possible to depend on `alloc` without `std`.
//! * The lack of specialization makes it hard to be both generic over implementors of the standard
//!   traits while still allowing use when those traits are not available. This is in particular
//!   also since several types (e.g. `&[u8]`) implement those traits but would obviously be useful
//!   as byte sources and sinks even when they are unavailable.
//!
//! ## Usage guide
//!
//! This crate assumes you have a structure declared roughly as follows:
//!
//! ```rust
//! # struct SomeItem;
//! # use std::io::Read;
//!
//! struct Decoder<T> {
//!     reader: T,
//! }
//!
//! impl<T: std::io::Read> Decoder<T> {
//!     fn next(&mut self) -> Result<SomeItem, std::io::Error> {
//!         let mut buffer = vec![];
//!         self.reader.read_to_end(&mut buffer)?;
//! # unimplemented!()
//!     }
//! }
//! ```
//!
//! There is only one necessary change, be sure to keep the `std` feature enabled for now. This
//! should not break any code except if you relied on the precise type `T` in which case you will
//! need to use a few derefs and/or `into_inner`.
//!
//! ```
//! use not_io::AllowStd;
//! # use std::io::Read;
//!
//! struct Decoder<T> {
//!     reader: AllowStd<T>,
//! }
//!
//! # struct SomeItem;
//! # impl<T: std::io::Read> Decoder<T> {
//! #    fn next(&mut self) -> Result<SomeItem, std::io::Error> {
//! #        let mut buffer = vec![];
//! #        self.reader.0.read_to_end(&mut buffer)?;
//! # unimplemented!()
//! #    }
//! # }
//! ```
//!
//! And finally you can add to your crate a new default feature which enables the `std`/`alloc`
//! feature of this crate, and conditionally active your existing interfaces only when that feature
//! is active. Then add a few new impls that can be used even when the feature is inactive.
//!
//! ```
//! use not_io::AllowStd;
//! # struct SomeItem;
//!
//! struct Decoder<T> {
//!     reader: AllowStd<T>,
//! }
//!
//! /// The interface which lets the caller select which feature to turn on.
//! impl<T> Decoder<T>
//! where
//!     AllowStd<T>: not_io::Read
//! {
//!     fn no_std_next(&mut self) -> Result<SomeItem, not_io::Error> {
//! # unimplemented!()
//!     }
//! }
//!
//! /// An interface for pure no_std use with caller provide no_std reader.
//! impl<T> Decoder<T>
//! where
//!     T: not_io::Read
//! {
//!     fn not_io_next(&mut self) -> Result<SomeItem, not_io::Error> {
//!         let reader = &mut self.reader.0;
//! # unimplemented!()
//!     }
//! }
//! ```
//!
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(all(feature = "alloc", not(feature = "std")))]
extern crate alloc;

pub struct Error {
    _private: (),
}

pub type Result<T> = core::result::Result<T, Error>;

pub trait Read {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
}

pub trait Write {
    fn write(&mut self, buf: &[u8]) -> Result<usize>;
}

/// A simple new type wrapper holding a potential reader or writer.
///
/// This type allows the library to satisfy the compatibility across different features without
/// having to resort to specialization. Simply put, this struct implements `Read` and `Write`:
///
/// * for all types that implement the respective trait from `std` if the `std` feature is active.
/// * on a concrete subset of those types if the `alloc` feature but not the `std` feature has been
///   turned on.
/// * only for types from `core` when neither feature is turned on.
///
/// Note that without this type we couldn't safely introduce a conditionally active, generic impl
/// of our own traits. The reason is that features must only activate SemVer compatible changes.
/// These two sets of impls are not SemVer compatible due to the uncovered generic `T`. In
/// particular in the first case you'd be allowed to implement the trait for your own type that
/// also implements `std::io::Read` while in the second this is an impl conflict.
///
/// * `impl Read for &'_ [u8]`
/// * `impl<T> Read for T where std::io::Read`
///
/// By adding our own private struct as a layer of indirection, you are no longer allowed to make
/// such changes:
///
/// * `impl Read for AllowStd<&'_ [u8]>`
/// * `impl<T> Read for AllowStd<T> where T: std::io::Read`
///
/// This still means there is one impl which will never be added. Instead, the impls for
/// core/standard types are provided separately and individually.
///
/// * `impl<T> Read for AllowStd<T> where T: crate::Read`
pub struct AllowStd<T>(pub T);

#[cfg(not(feature = "alloc"))]
mod impls_on_neither {}

#[cfg(feature = "alloc")]
mod impls_on_alloc {}

#[cfg(feature = "std")]
mod impls_on_std {
    use super::{AllowStd, Error, Result};
    use std::io::{self, IoSlice, IoSliceMut};

    impl<R: io::Read> super::Read for AllowStd<R> {
        fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
            io::Read::read(&mut self.0, buf).map_err(Error::from)
        }
    }

    impl<R: io::Read> io::Read for AllowStd<R> {
        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
            self.0.read(buf)
        }
        fn read_vectored(&mut self, bufs: &mut [IoSliceMut]) -> io::Result<usize> {
            self.0.read_vectored(bufs)
        }
        fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
            self.0.read_to_end(buf)
        }
        fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
            self.0.read_to_string(buf)
        }
        fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
            self.0.read_exact(buf)
        }
    }

    impl<W: io::Write> super::Write for AllowStd<W> {
        fn write(&mut self, buf: &[u8]) -> Result<usize> {
            io::Write::write(&mut self.0, buf).map_err(Error::from)
        }
    }

    impl<W: io::Write> io::Write for AllowStd<W> {
        fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
            self.0.write(buf)
        }
        fn flush(&mut self) -> io::Result<()> {
            self.0.flush()
        }
        fn write_vectored(&mut self, bufs: &[IoSlice]) -> io::Result<usize> {
            self.0.write_vectored(bufs)
        }
        fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
            self.0.write_all(buf)
        }
    }

    impl From<io::Error> for Error {
        fn from(_: io::Error) -> Error {
            Error { _private: () }
        }
    }
}