channels_io/
convert.rs

1/// Convert a type to a reader.
2///
3/// This trait is how functions can accept different readers under one unified
4/// interface. It is very flexible, allowing code to be agnostic over synchronous
5/// or asynchronous readers and/or different interfaces.
6///
7/// The trait consists of only one method [`IntoRead::into_read()`]. The
8/// purpose of this method is to wrap any type `T` with its appropriate wrapper
9/// type so that it can implement [`Read`] and/or [`AsyncRead`]. This is necessary
10/// because we can't implement a trait directly for every type `T` multiple times
11/// with different trait bounds. Which basically means we cannot do this:
12///
13/// ```rust,compile_fail
14/// trait AsyncRead {
15///     // -- snip --
16/// }
17///
18/// impl<T> AsyncRead for T
19/// where
20///     T: tokio::io::AsyncRead
21/// {
22///     // -- snip --
23/// }
24///
25/// impl<T> AsyncRead for T
26/// where
27///     T: futures::AsyncRead
28/// {
29///     // -- snip --
30/// }
31/// ```
32///
33/// We _can_ solve this problem though. The Rust book [recommends using the
34/// "newtype" pattern to solve this](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types).
35/// To do this we must wrap the type `T` in a new type for which then we implement
36/// the desired trait. This trait is what wraps a `T` with the new type.
37///
38/// # Examples
39///
40/// - Accepting any reader.
41///
42/// ```rust,no_run
43/// use channels_io::{IntoRead, AsyncRead, Read};
44///
45/// struct MyStruct<R> {
46///     reader: R
47/// }
48///
49/// impl<R> MyStruct<R> {
50///     pub fn new(reader: impl IntoRead<R>) -> Self {
51///         Self {
52///             reader: reader.into_read()
53///         }
54///     }
55/// }
56///
57/// impl<R: Read> MyStruct<R> {
58///     // implement things for when the reader is synchronous
59/// }
60///
61/// impl<R: AsyncRead> MyStruct<R> {
62///     // implement things for when the reader is asynchronous
63/// }
64///
65/// // With a synchronous reader.
66/// let _ = MyStruct::new(std::io::empty());
67///
68/// // With an asynchronous reader.
69/// let _ = MyStruct::new(tokio::io::empty());
70/// ```
71///
72/// - Accepting synchronous/asynchronous readers only.
73///
74/// ```rust,no_run
75/// use channels_io::{IntoRead, AsyncRead, Read};
76///
77/// fn sync_only<R: Read>(reader: impl IntoRead<R>) { /* ... */ }
78/// fn async_only<R: AsyncRead>(reader: impl IntoRead<R>) { /* ... */ }
79///
80/// let _ = sync_only(std::io::empty());
81/// let _ = async_only(tokio::io::empty());
82/// ```
83///
84/// So the following cannot work:
85///
86/// ```rust,compile_fail
87/// use channels_io::{IntoRead, Read};
88///
89/// fn sync_only<R: Read>(reader: impl IntoRead<R>) { /* ... */ }
90///
91/// let _ = sync_only(tokio::io::empty());
92/// ```
93///
94/// ```rust,compile_fail
95/// use channels_io::{IntoRead, AsyncRead};
96///
97/// fn async_only<R: AsyncRead>(reader: impl IntoRead<R>) { /* ... */ }
98///
99/// let _ = async_only(std::io::empty());
100/// ```
101///
102/// [`Read`]: crate::Read
103/// [`AsyncRead`]: crate::AsyncRead
104pub trait IntoRead<T> {
105	/// Convert `self` to a reader `T`.
106	fn into_read(self) -> T;
107}
108
109/// Convert a type to a writer.
110///
111/// This trait is how functions can accept different writers under one unified
112/// interface. It is very flexible, allowing code to be agnostic over synchronous
113/// or asynchronous writers and/or different interfaces.
114///
115/// The trait consists of only one method [`IntoWrite::into_write()`]. The
116/// purpose of this method is to wrap any type `T` with its appropriate wrapper
117/// type so that it can implement [`Write`] and/or [`AsyncWrite`]. This is necessary
118/// because we can't implement a trait directly for every type `T` multiple times
119/// with different trait bounds. Which basically means we cannot do this:
120///
121/// ```rust,compile_fail
122/// trait AsyncWrite {
123///     // -- snip --
124/// }
125///
126/// impl<T> AsyncWrite for T
127/// where
128///     T: tokio::io::AsyncWrite
129/// {
130///     // -- snip --
131/// }
132///
133/// impl<T> AsyncWrite for T
134/// where
135///     T: futures::AsyncWrite
136/// {
137///     // -- snip --
138/// }
139/// ```
140///
141/// We _can_ solve this problem though. The Rust book [recommends using the
142/// "newtype" pattern to solve this](https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types).
143/// To do this we must wrap the type `T` in a new type for which then we implement
144/// the desired trait. This trait is what wraps a `T` with the new type.
145///
146/// # Examples
147///
148/// - Accepting any writer.
149///
150/// ```rust,no_run
151/// use channels_io::{IntoWrite, AsyncWrite, Write};
152///
153/// struct MyStruct<R> {
154///     writer: R
155/// }
156///
157/// impl<R> MyStruct<R> {
158///     pub fn new(writer: impl IntoWrite<R>) -> Self {
159///         Self {
160///             writer: writer.into_write()
161///         }
162///     }
163/// }
164///
165/// impl<R: Write> MyStruct<R> {
166///     // implement things for when the writer is synchronous
167/// }
168///
169/// impl<R: AsyncWrite> MyStruct<R> {
170///     // implement things for when the writer is asynchronous
171/// }
172///
173/// // With a synchronous writer.
174/// let _ = MyStruct::new(std::io::empty());
175///
176/// // With an asynchronous writer.
177/// let _ = MyStruct::new(tokio::io::empty());
178/// ```
179///
180/// - Accepting synchronous/asynchronous readers only.
181///
182/// ```rust,no_run
183/// use channels_io::{IntoWrite, AsyncWrite, Write};
184///
185/// fn sync_only<W: Write>(writer: impl IntoWrite<W>) { /* ... */ }
186/// fn async_only<W: AsyncWrite>(writer: impl IntoWrite<W>) { /* ... */ }
187///
188/// let _ = sync_only(std::io::sink());
189/// let _ = async_only(tokio::io::sink());
190/// ```
191///
192/// So the following cannot work:
193///
194/// ```rust,compile_fail
195/// use channels_io::{IntoWrite, Write};
196///
197/// fn sync_only<W: Write>(writer: impl IntoWrite<W>) { /* ... */ }
198///
199/// let _ = sync_only(tokio::io::empty());
200/// ```
201///
202/// ```rust,compile_fail
203/// use channels_io::{IntoWrite, AsyncWrite};
204///
205/// fn async_only<W: AsyncWrite>(writer: impl IntoWrite<W>) { /* ... */ }
206///
207/// let _ = async_only(std::io::empty());
208/// ```
209///
210/// [`Write`]: crate::Write
211/// [`AsyncWrite`]: crate::AsyncWrite
212pub trait IntoWrite<T> {
213	/// Convert `self` to a writer `T`.
214	fn into_write(self) -> T;
215}
216
217/// This trait should be implemented for every "newtype".
218///
219/// It is a generic interface that allows access to a type `T` while still
220/// allowing foreign trait implementations on it. Usually this trait is
221/// implemented by single-field tuple structs that store a type `T` and
222/// implement some traits. This is used to implement [`Read`], [`Write`] and
223/// friends on foreign types.
224///
225/// Consider the following:
226///
227/// ```rust,no_run
228/// use std::io::{empty, Empty};
229/// use channels_io::{IntoRead, Std, Read, Container};
230///
231/// struct MyStruct<R> {
232///     reader: R
233/// }
234///
235/// impl<R> MyStruct<R> {
236///     pub fn new(reader: impl IntoRead<R>) -> Self {
237///         Self { reader: reader.into_read() }
238///     }
239/// }
240///
241/// impl<R: Container> MyStruct<R> {
242///     pub fn get(&self) -> &R::Inner {
243///         self.reader.get_ref()
244///     }
245///
246///     pub fn get_mut(&mut self) -> &mut R::Inner {
247///         self.reader.get_mut()
248///     }
249/// }
250///
251/// let mut foo = MyStruct::new(empty());
252/// // foo.reader is not an `Empty`
253///
254/// // Get references
255/// let reader: &Empty = foo.get();
256/// let reader: &mut Empty = foo.get_mut();
257///
258/// // Destruct into the original type.
259/// let reader: Empty = foo.reader.into_inner();
260/// ```
261///
262/// [`Read`]: crate::Read
263/// [`Write`]: crate::Write
264pub trait Container {
265	/// The inner type this container stores.
266	type Inner;
267
268	/// Construct a `Self` from the inner type.
269	fn from_inner(inner: Self::Inner) -> Self;
270
271	/// Get a reference to the inner type.
272	fn get_ref(&self) -> &Self::Inner;
273
274	/// Get a mutable reference to the inner type.
275	fn get_mut(&mut self) -> &mut Self::Inner;
276
277	/// Destruct the container into its inner type.
278	fn into_inner(self) -> Self::Inner;
279}