1+ //! https://docs.rs/not-io/0.1.0-alpha/not_io/
2+ //! Provides `Read` and `Write` alternatives on `no_std` while being compatible with the full
3+ //! traits from `std` when allowed.
4+ //!
5+ //! ## Motivation
6+ //!
7+ //! The file parser ecosystem of Rust is more or less split across crates that use `no_std` and
8+ //! crates that do not, as well as between crates using `alloc` and no-alloc (and the largely
9+ //! overlapping zero-copy) crates. This has several reasons:
10+ //!
11+ //! * The `std::io::Read` and `std::io::Write` traits require an allocator due to their internal
12+ //! implementation and were not written to be OS independent.
13+ //! * Before `1.36` it was not possible to depend on `alloc` without `std`.
14+ //! * The lack of specialization makes it hard to be both generic over implementors of the standard
15+ //! traits while still allowing use when those traits are not available. This is in particular
16+ //! also since several types (e.g. `&[u8]`) implement those traits but would obviously be useful
17+ //! as byte sources and sinks even when they are unavailable.
18+ //!
19+ //! ## Usage guide
20+ //!
21+ //! This crate assumes you have a structure declared roughly as follows:
22+ //!
23+ //! ```rust
24+ //! # struct SomeItem;
25+ //! # use std::io::Read;
26+ //!
27+ //! struct Decoder<T> {
28+ //! reader: T,
29+ //! }
30+ //!
31+ //! impl<T: std::io::Read> Decoder<T> {
32+ //! fn next(&mut self) -> Result<SomeItem, std::io::Error> {
33+ //! let mut buffer = vec![];
34+ //! self.reader.read_to_end(&mut buffer)?;
35+ //! # unimplemented!()
36+ //! }
37+ //! }
38+ //! ```
39+ //!
40+ //! There is only one necessary change, be sure to keep the `std` feature enabled for now. This
41+ //! should not break any code except if you relied on the precise type `T` in which case you will
42+ //! need to use a few derefs and/or `into_inner`.
43+ //!
44+ //! ```
45+ //! use not_io::AllowStd;
46+ //! # use std::io::Read;
47+ //!
48+ //! struct Decoder<T> {
49+ //! reader: AllowStd<T>,
50+ //! }
51+ //!
52+ //! # struct SomeItem;
53+ //! # impl<T: std::io::Read> Decoder<T> {
54+ //! # fn next(&mut self) -> Result<SomeItem, std::io::Error> {
55+ //! # let mut buffer = vec![];
56+ //! # self.reader.0.read_to_end(&mut buffer)?;
57+ //! # unimplemented!()
58+ //! # }
59+ //! # }
60+ //! ```
61+ //!
62+ //! And finally you can add to your crate a new default feature which enables the `std`/`alloc`
63+ //! feature of this crate, and conditionally active your existing interfaces only when that feature
64+ //! is active. Then add a few new impls that can be used even when the feature is inactive.
65+ //!
66+ //! ```
67+ //! use not_io::AllowStd;
68+ //! # struct SomeItem;
69+ //!
70+ //! struct Decoder<T> {
71+ //! reader: AllowStd<T>,
72+ //! }
73+ //!
74+ //! /// The interface which lets the caller select which feature to turn on.
75+ //! impl<T> Decoder<T>
76+ //! where
77+ //! AllowStd<T>: not_io::Read
78+ //! {
79+ //! fn no_std_next(&mut self) -> Result<SomeItem, not_io::Error> {
80+ //! # unimplemented!()
81+ //! }
82+ //! }
83+ //!
84+ //! /// An interface for pure no_std use with caller provide no_std reader.
85+ //! impl<T> Decoder<T>
86+ //! where
87+ //! T: not_io::Read
88+ //! {
89+ //! fn not_io_next(&mut self) -> Result<SomeItem, not_io::Error> {
90+ //! let reader = &mut self.reader.0;
91+ //! # unimplemented!()
92+ //! }
93+ //! }
94+ //! ```
95+ //!
96+ #![ cfg_attr( not( feature = "std" ) , no_std) ]
97+
98+ #[ cfg( all( feature = "alloc" , not( feature = "std" ) ) ) ]
99+ extern crate alloc;
100+
101+ #[ derive( Debug ) ]
102+ pub struct Error {
103+ _private : ( ) ,
104+ }
105+
106+ pub type Result < T > = core:: result:: Result < T , Error > ;
107+
108+ pub trait Read {
109+ fn read ( & mut self , buf : & mut [ u8 ] ) -> Result < usize > ;
110+ }
111+
112+ pub trait Write {
113+ fn write ( & mut self , buf : & [ u8 ] ) -> Result < usize > ;
114+ }
115+
116+ /// A simple new type wrapper holding a potential reader or writer.
117+ ///
118+ /// This type allows the library to satisfy the compatibility across different features without
119+ /// having to resort to specialization. Simply put, this struct implements `Read` and `Write`:
120+ ///
121+ /// * for all types that implement the respective trait from `std` if the `std` feature is active.
122+ /// * on a concrete subset of those types if the `alloc` feature but not the `std` feature has been
123+ /// turned on.
124+ /// * only for types from `core` when neither feature is turned on.
125+ ///
126+ /// Note that without this type we couldn't safely introduce a conditionally active, generic impl
127+ /// of our own traits. The reason is that features must only activate SemVer compatible changes.
128+ /// These two sets of impls are not SemVer compatible due to the uncovered generic `T`. In
129+ /// particular in the first case you'd be allowed to implement the trait for your own type that
130+ /// also implements `std::io::Read` while in the second this is an impl conflict.
131+ ///
132+ /// * `impl Read for &'_ [u8]`
133+ /// * `impl<T> Read for T where std::io::Read`
134+ ///
135+ /// By adding our own private struct as a layer of indirection, you are no longer allowed to make
136+ /// such changes:
137+ ///
138+ /// * `impl Read for AllowStd<&'_ [u8]>`
139+ /// * `impl<T> Read for AllowStd<T> where T: std::io::Read`
140+ ///
141+ /// This still means there is one impl which will never be added. Instead, the impls for
142+ /// core/standard types are provided separately and individually.
143+ ///
144+ /// * `impl<T> Read for AllowStd<T> where T: crate::Read`
145+ pub struct AllowStd < T > ( pub T ) ;
146+
147+ #[ cfg( not( feature = "alloc" ) ) ]
148+ mod impls_on_neither { }
149+
150+ #[ cfg( feature = "alloc" ) ]
151+ mod impls_on_alloc { }
152+
153+ #[ cfg( feature = "std" ) ]
154+ mod impls_on_std {
155+ use super :: { AllowStd , Error , Result } ;
156+ use std:: io:: { self , IoSlice , IoSliceMut } ;
157+
158+ impl < R : io:: Read > super :: Read for AllowStd < R > {
159+ fn read ( & mut self , buf : & mut [ u8 ] ) -> Result < usize > {
160+ io:: Read :: read ( & mut self . 0 , buf) . map_err ( Error :: from)
161+ }
162+ }
163+
164+ impl < R : io:: Read > io:: Read for AllowStd < R > {
165+ fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
166+ self . 0 . read ( buf)
167+ }
168+ fn read_vectored ( & mut self , bufs : & mut [ IoSliceMut ] ) -> io:: Result < usize > {
169+ self . 0 . read_vectored ( bufs)
170+ }
171+ fn read_to_end ( & mut self , buf : & mut Vec < u8 > ) -> io:: Result < usize > {
172+ self . 0 . read_to_end ( buf)
173+ }
174+ fn read_to_string ( & mut self , buf : & mut String ) -> io:: Result < usize > {
175+ self . 0 . read_to_string ( buf)
176+ }
177+ fn read_exact ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < ( ) > {
178+ self . 0 . read_exact ( buf)
179+ }
180+ }
181+
182+ impl < W : io:: Write > super :: Write for AllowStd < W > {
183+ fn write ( & mut self , buf : & [ u8 ] ) -> Result < usize > {
184+ io:: Write :: write ( & mut self . 0 , buf) . map_err ( Error :: from)
185+ }
186+ }
187+
188+ impl < W : io:: Write > io:: Write for AllowStd < W > {
189+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
190+ self . 0 . write ( buf)
191+ }
192+ fn flush ( & mut self ) -> io:: Result < ( ) > {
193+ self . 0 . flush ( )
194+ }
195+ fn write_vectored ( & mut self , bufs : & [ IoSlice ] ) -> io:: Result < usize > {
196+ self . 0 . write_vectored ( bufs)
197+ }
198+ fn write_all ( & mut self , buf : & [ u8 ] ) -> io:: Result < ( ) > {
199+ self . 0 . write_all ( buf)
200+ }
201+ }
202+
203+ impl From < io:: Error > for Error {
204+ fn from ( _: io:: Error ) -> Error {
205+ Error { _private : ( ) }
206+ }
207+ }
208+ }
0 commit comments