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_ref
orderef
attribute 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
&mut
to escape, thus upholding anyPin
guarantees.
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 ;