channels_io/write/
mod.rs

1use core::pin::Pin;
2use core::task::{ready, Context, Poll};
3
4use crate::buf::Buf;
5use crate::error::{IoError, WriteError};
6
7#[cfg(feature = "alloc")]
8use crate::transaction::{
9	WriteTransactionKind, WriteTransactionVariant,
10};
11
12mod flush;
13mod write_buf;
14mod write_buf_all;
15
16use self::flush::Flush;
17use self::write_buf::WriteBuf;
18use self::write_buf_all::WriteBufAll;
19
20/// This trait allows writing bytes to a writer.
21///
22/// Types implementing this trait are called "writers".
23pub trait Write {
24	/// Error type for IO operations involving the writer.
25	type Error: WriteError;
26
27	/// Write some bytes from `buf` to the writer.
28	///
29	/// This function is the lower level building block of [`write_buf()`]. It writes
30	/// bytes from `buf` and reports back to the caller how many bytes it wrote.
31	/// [`write_buf()`] should, usually, be preferred.
32	///
33	/// [`write_buf()`]: WriteExt::write_buf
34	fn write_slice(
35		&mut self,
36		buf: &[u8],
37	) -> Result<usize, Self::Error>;
38
39	/// Flush this writer once ensuring all bytes reach their destination.
40	///
41	/// This function is the lower level building block of [`flush()`]. It flushes
42	/// the writer only once. [`flush()`] should, usually, be preferred.
43	///
44	/// [`flush()`]: WriteExt::flush
45	fn flush_once(&mut self) -> Result<(), Self::Error>;
46}
47
48/// This trait is the asynchronous version of [`Write`].
49///
50/// [`Write`]: crate::Write
51pub trait AsyncWrite {
52	/// Error type for IO operations involving the writer.
53	type Error: WriteError;
54
55	/// Poll the writer and try to write some bytes from `buf` to it.
56	///
57	/// This method writes bytes from `buf` and reports back how many bytes it
58	/// wrote.
59	fn poll_write_slice(
60		self: Pin<&mut Self>,
61		cx: &mut Context,
62		buf: &[u8],
63	) -> Poll<Result<usize, Self::Error>>;
64
65	/// Poll the writer and try to flush it only once.
66	fn poll_flush_once(
67		self: Pin<&mut Self>,
68		cx: &mut Context,
69	) -> Poll<Result<(), Self::Error>>;
70}
71
72/// Write bytes to a writer.
73///
74/// Extension trait for all [`Write`] types.
75pub trait WriteExt: Write {
76	/// Write `buf` to the writer advancing it appropriately.
77	fn write_buf<B>(&mut self, buf: B) -> Result<(), Self::Error>
78	where
79		B: Buf,
80	{
81		write_buf(self, buf)
82	}
83
84	/// Write `buf` to the writer advancing it until all of it has been written.
85	///
86	/// This method will try to write `buf` repeatedly until either a) `buf` has
87	/// no more data, b) an error occurs, c) the writer cannot accept any more bytes.
88	fn write_buf_all<B>(&mut self, buf: B) -> Result<(), Self::Error>
89	where
90		B: Buf,
91	{
92		write_buf_all(self, buf)
93	}
94
95	/// Flush this writer ensuring all bytes reach their destination.
96	fn flush(&mut self) -> Result<(), Self::Error> {
97		flush(self)
98	}
99
100	/// Create a "by reference" adapter that takes the current instance of [`Write`]
101	/// by mutable reference.
102	fn by_ref(&mut self) -> &mut Self
103	where
104		Self: Sized,
105	{
106		self
107	}
108
109	/// Create a transaction that uses this writer.
110	///
111	/// This is a convenience wrapper for: [`WriteTransactionVariant::new()`]
112	#[cfg(feature = "alloc")]
113	fn transaction(
114		self,
115		kind: WriteTransactionKind,
116	) -> WriteTransactionVariant<'_, Self>
117	where
118		Self: Sized,
119	{
120		WriteTransactionVariant::new(self, kind)
121	}
122}
123
124/// This trait is the asynchronous version of [`WriteExt`].
125///
126/// Extension trait for all [`AsyncWrite`] types.
127///
128/// [`WriteExt`]: crate::WriteExt
129pub trait AsyncWriteExt: AsyncWrite {
130	/// Poll the writer and try to write `buf` to it.
131	fn poll_write_buf<B>(
132		self: Pin<&mut Self>,
133		cx: &mut Context,
134		buf: &mut B,
135	) -> Poll<Result<(), Self::Error>>
136	where
137		B: Buf + ?Sized,
138	{
139		poll_write_buf(self, cx, buf)
140	}
141
142	/// Poll the writer and try to write `buf` to it.
143	fn poll_write_buf_all<B>(
144		self: Pin<&mut Self>,
145		cx: &mut Context,
146		buf: &mut B,
147	) -> Poll<Result<(), Self::Error>>
148	where
149		B: Buf + ?Sized,
150	{
151		poll_write_buf_all(self, cx, buf)
152	}
153
154	/// Poll the writer and try to flush it.
155	fn poll_flush(
156		self: Pin<&mut Self>,
157		cx: &mut Context,
158	) -> Poll<Result<(), Self::Error>> {
159		poll_flush(self, cx)
160	}
161
162	/// Asynchronously write `buf` to the writer advancing it appropriately
163	///
164	/// This function behaves in the same way as [`write_buf()`] except that
165	/// it returns a [`Future`] that must be `.await`ed.
166	///
167	/// [`write_buf()`]: crate::WriteExt::write_buf
168	/// [`Future`]: core::future::Future
169	fn write_buf<B>(&mut self, buf: B) -> WriteBuf<'_, Self, B>
170	where
171		B: Buf + Unpin,
172		Self: Unpin,
173	{
174		WriteBuf::new(self, buf)
175	}
176
177	/// Asynchronously write `buf` to the writer advancing it until all of it has been written.
178	///
179	/// This function behaves in the same way as [`write_buf_all()`] except that
180	/// it returns a [`Future`] that must be `.await`ed.
181	///
182	/// [`write_buf_all()`]: crate::WriteExt::write_buf_all
183	/// [`Future`]: core::future::Future
184	fn write_buf_all<B>(&mut self, buf: B) -> WriteBufAll<'_, Self, B>
185	where
186		B: Buf + Unpin,
187		Self: Unpin,
188	{
189		WriteBufAll::new(self, buf)
190	}
191
192	/// Asynchronously flush the writer.
193	///
194	/// This function behaves in the same way as [`flush()`] except that
195	/// it returns a [`Future`] that must be `.await`ed.
196	///
197	/// [`flush()`]: crate::WriteExt::flush
198	/// [`Future`]: core::future::Future
199	fn flush(&mut self) -> Flush<'_, Self>
200	where
201		Self: Unpin,
202	{
203		Flush::new(self)
204	}
205
206	/// Create a "by reference" adapter that takes the current instance of [`AsyncWrite`]
207	/// by mutable reference.
208	fn by_ref(&mut self) -> &mut Self
209	where
210		Self: Sized,
211	{
212		self
213	}
214
215	/// Create a transaction that uses this instance of [`AsyncWrite`].
216	///
217	/// This is a convenience wrapper for: [`WriteTransactionVariant::new()`]
218	#[cfg(feature = "alloc")]
219	fn transaction(
220		self,
221		kind: WriteTransactionKind,
222	) -> WriteTransactionVariant<'_, Self>
223	where
224		Self: Sized,
225	{
226		WriteTransactionVariant::new(self, kind)
227	}
228}
229
230impl<T: Write + ?Sized> WriteExt for T {}
231
232impl<T: AsyncWrite + ?Sized> AsyncWriteExt for T {}
233
234fn write_buf<T, B>(writer: &mut T, mut buf: B) -> Result<(), T::Error>
235where
236	T: WriteExt + ?Sized,
237	B: Buf,
238{
239	if !buf.has_remaining() {
240		return Ok(());
241	}
242
243	loop {
244		match writer.write_slice(buf.chunk()) {
245			Ok(0) => return Err(T::Error::write_zero()),
246			Ok(n) => {
247				buf.advance(n);
248				return Ok(());
249			},
250			Err(e) if e.should_retry() => continue,
251			Err(e) => return Err(e),
252		}
253	}
254}
255
256fn poll_write_buf<T, B>(
257	mut writer: Pin<&mut T>,
258	cx: &mut Context,
259	buf: &mut B,
260) -> Poll<Result<(), T::Error>>
261where
262	T: AsyncWriteExt + ?Sized,
263	B: Buf + ?Sized,
264{
265	use Poll::Ready;
266
267	if !buf.has_remaining() {
268		return Ready(Ok(()));
269	}
270
271	loop {
272		match ready!(writer
273			.as_mut()
274			.poll_write_slice(cx, buf.chunk()))
275		{
276			Ok(0) => return Ready(Err(T::Error::write_zero())),
277			Ok(n) => {
278				buf.advance(n);
279				return Ready(Ok(()));
280			},
281			Err(e) if e.should_retry() => continue,
282			Err(e) => return Ready(Err(e)),
283		}
284	}
285}
286
287fn write_buf_all<T, B>(
288	writer: &mut T,
289	mut buf: B,
290) -> Result<(), T::Error>
291where
292	T: WriteExt + ?Sized,
293	B: Buf,
294{
295	while buf.has_remaining() {
296		match writer.write_slice(buf.chunk()) {
297			Ok(0) => return Err(T::Error::write_zero()),
298			Ok(n) => buf.advance(n),
299			Err(e) if e.should_retry() => continue,
300			Err(e) => return Err(e),
301		}
302	}
303
304	Ok(())
305}
306
307fn poll_write_buf_all<T, B>(
308	mut writer: Pin<&mut T>,
309	cx: &mut Context,
310	buf: &mut B,
311) -> Poll<Result<(), T::Error>>
312where
313	T: AsyncWriteExt + ?Sized,
314	B: Buf + ?Sized,
315{
316	use Poll::Ready;
317
318	while buf.has_remaining() {
319		match ready!(writer
320			.as_mut()
321			.poll_write_slice(cx, buf.chunk()))
322		{
323			Ok(0) => return Ready(Err(T::Error::write_zero())),
324			Ok(n) => buf.advance(n),
325			Err(e) if e.should_retry() => continue,
326			Err(e) => return Ready(Err(e)),
327		}
328	}
329
330	Ready(Ok(()))
331}
332
333fn flush<T>(writer: &mut T) -> Result<(), T::Error>
334where
335	T: WriteExt + ?Sized,
336{
337	loop {
338		match writer.flush_once() {
339			Ok(()) => break Ok(()),
340			Err(e) if e.should_retry() => continue,
341			Err(e) => break Err(e),
342		}
343	}
344}
345
346fn poll_flush<T>(
347	mut writer: Pin<&mut T>,
348	cx: &mut Context,
349) -> Poll<Result<(), T::Error>>
350where
351	T: AsyncWrite + ?Sized,
352{
353	loop {
354		match ready!(writer.as_mut().poll_flush_once(cx)) {
355			Ok(()) => return Poll::Ready(Ok(())),
356			Err(e) if e.should_retry() => continue,
357			Err(e) => return Poll::Ready(Err(e)),
358		}
359	}
360}
361
362macro_rules! forward_impl_write {
363	($to:ty) => {
364		type Error = <$to>::Error;
365
366		fn write_slice(
367			&mut self,
368			buf: &[u8],
369		) -> Result<usize, Self::Error> {
370			<$to>::write_slice(self, buf)
371		}
372
373		fn flush_once(&mut self) -> Result<(), Self::Error> {
374			<$to>::flush_once(self)
375		}
376	};
377}
378
379macro_rules! forward_impl_async_write {
380	($to:ty) => {
381		type Error = <$to>::Error;
382
383		fn poll_write_slice(
384			mut self: Pin<&mut Self>,
385			cx: &mut Context,
386			buf: &[u8],
387		) -> Poll<Result<usize, Self::Error>> {
388			let this = Pin::new(&mut **self);
389			<$to>::poll_write_slice(this, cx, buf)
390		}
391
392		fn poll_flush_once(
393			mut self: Pin<&mut Self>,
394			cx: &mut Context,
395		) -> Poll<Result<(), Self::Error>> {
396			let this = Pin::new(&mut **self);
397			<$to>::poll_flush_once(this, cx)
398		}
399	};
400}
401
402impl<T: Write + ?Sized> Write for &mut T {
403	forward_impl_write!(T);
404}
405
406impl<T: AsyncWrite + Unpin + ?Sized> AsyncWrite for &mut T {
407	forward_impl_async_write!(T);
408}
409
410#[cfg(feature = "alloc")]
411impl<T: Write + ?Sized> Write for alloc::boxed::Box<T> {
412	forward_impl_write!(T);
413}
414
415#[cfg(feature = "alloc")]
416impl<T: AsyncWrite + Unpin + ?Sized> AsyncWrite
417	for alloc::boxed::Box<T>
418{
419	forward_impl_async_write!(T);
420}