derive-io
A Rust crate that provides derive macros for implementing sync and async I/O traits on structs and enums (including Tokio, stdlib I/O, and more).
Supported traits
#[derive(Read)]: [std::io::Read]#[derive(BufRead)]: [std:io::BufRead]#[derive(Write)]: [std::io::Write]#[derive(AsyncRead)]: [tokio::io::AsyncRead]#[derive(AsyncWrite)]: [tokio::io::AsyncWrite]#[derive(AsFileDescriptor)]:std::os::fd::{AsFd, AsRawFd}std::os::windows::io::{AsHandle, AsRawHandle}
#[derive(AsSocketDescriptor)]:std::os::fd::{AsFd, AsRawFd}std::os::windows::io::{AsSocket, AsRawSocket}
Features
- Derive most common I/O traits for structs and enums
- Support for both named and tuple structs
- Support for enums with multiple variants
- Support for split read/write streams (ie: two fields provide the read/write halves)
- Support for generic types
- Support for duck typing (ie: implementing traits using a method with a "similar" interface)
- Individual methods can be overridden with custom implementations
- Support for
as_reforderefattribute on fields to delegate to the inner type- Note: for traits requiring a pinned-self (ie: async read/write), the holder
type and the outer type must both be
Unpin!
- Note: for traits requiring a pinned-self (ie: async read/write), the holder
type and the outer type must both be
- Pin safety: internal pin projection never allows a
&mutto escape, thus upholding anyPinguarantees.
as_ref/deref delegation
Most I/O traits are implemented correctly for Box<dyn (trait)> (that is: they
are implemented for Box<T> where T: ?Sized). However, some traits have
accidental or intentional additional Sized requirements which prevent
automatic delegation from working. Generally this is only required for
AsFileDescriptor and AsSocketDescriptor, as most other traits are
implemented for themselves on Box<T> where T: Trait + ?Sized.
To uphold Pin safety guarantees, both the inner and outer types must be
Unpin.
The as_ref attribute can be used to delegate to the inner type's unwrapped
type as_ref/as_mut implementation. The deref attribute can be used to
delegate to the inner type's pointee via Deref/DerefMut.
use ;
Overrides
#[read(<function>=<override>)] and #[write(<function>=<override>)] may be
specified to redirect a method to a custom implementation.
duck delegation
duck delegation uses non-trait impl methods defined on a type to implement
the trait (i.e. "duck typing"). This is useful for when you want to implement a
trait for a type that doesn't implement the trait directly, but has methods that
are similar to the trait
#[read(duck)] and #[write(duck)] may be specified on the outer type or an
inner field.
When using duck delegation, specify the methods to delegate to using the
#[duck(...)] attribute:
use ;
use ;
Examples
Tokio
use *;
use ;
Generic types are supported. The generated implementations will automatically
add a where clause to the impl block for each stream type.
use ;
Override one method in the write implementation:
use ;