io_enum/
lib.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3/*!
4<!-- tidy:crate-doc:start -->
5\#\[derive(Read, Write, Seek, BufRead)\] for enums.
6
7## Usage
8
9Add this to your `Cargo.toml`:
10
11```toml
12[dependencies]
13io-enum = "1"
14```
15
16## Examples
17
18```rust
19use std::{
20    fs::File,
21    io::{self, Write},
22    path::Path,
23};
24
25use io_enum::*;
26
27#[derive(Read, Write, Seek, BufRead)]
28enum Either<A, B> {
29    A(A),
30    B(B),
31}
32
33fn func(path: Option<&Path>) -> impl Write {
34    if let Some(path) = path {
35        Either::A(File::open(path).unwrap())
36    } else {
37        Either::B(io::stdout())
38    }
39}
40```
41
42See [auto_enums] crate for how to automate patterns like this.
43
44## Supported traits
45
46- [`Read`](https://doc.rust-lang.org/std/io/trait.Read.html) - [example](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/read.rs) | [generated code](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/read.expanded.rs)
47- [`BufRead`](https://doc.rust-lang.org/std/io/trait.BufRead.html) - [example](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/buf_read.rs) | [generated code](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/buf_read.expanded.rs)
48- [`Write`](https://doc.rust-lang.org/std/io/trait.Write.html) - [example](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/write.rs) | [generated code](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/write.expanded.rs)
49- [`Seek`](https://doc.rust-lang.org/std/io/trait.Seek.html) - [example](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/seek.rs) | [generated code](https://github.com/taiki-e/io-enum/blob/HEAD/tests/expand/seek.expanded.rs)
50
51## Related Projects
52
53- [auto_enums]: A library for to allow multiple return types by automatically generated enum.
54- [derive_utils]: A procedural macro helper for easily writing [derives macros][proc-macro-derive] for enums.
55- [iter-enum]: \#\[derive(Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, Extend)\] for enums.
56
57[auto_enums]: https://github.com/taiki-e/auto_enums
58[derive_utils]: https://github.com/taiki-e/derive_utils
59[iter-enum]: https://github.com/taiki-e/iter-enum
60[proc-macro-derive]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros
61
62<!-- tidy:crate-doc:end -->
63*/
64
65#![doc(test(
66    no_crate_inject,
67    attr(
68        deny(warnings, rust_2018_idioms, single_use_lifetimes),
69        allow(dead_code, unused_variables)
70    )
71))]
72#![forbid(unsafe_code)]
73
74use derive_utils::quick_derive;
75use proc_macro::TokenStream;
76
77#[proc_macro_derive(Read)]
78pub fn derive_read(input: TokenStream) -> TokenStream {
79    // TODO: Add is_read_vectored once stabilized https://github.com/rust-lang/rust/issues/69941
80    // TODO: Add read_buf,read_buf_exact once stabilized https://github.com/rust-lang/rust/issues/78485
81    quick_derive! {
82        input,
83        ::std::io::Read,
84        trait Read {
85            #[inline]
86            fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize>;
87            #[inline]
88            fn read_vectored(
89                &mut self, bufs: &mut [::std::io::IoSliceMut<'_>],
90            ) -> ::std::io::Result<usize>;
91            #[inline]
92            fn read_to_end(&mut self, buf: &mut ::std::vec::Vec<u8>) -> ::std::io::Result<usize>;
93            #[inline]
94            fn read_to_string(
95                &mut self,
96                buf: &mut ::std::string::String,
97            ) -> ::std::io::Result<usize>;
98            #[inline]
99            fn read_exact(&mut self, buf: &mut [u8]) -> ::std::io::Result<()>;
100        }
101    }
102}
103
104#[proc_macro_derive(Write)]
105pub fn derive_write(input: TokenStream) -> TokenStream {
106    // TODO: Add is_write_vectored once stabilized https://github.com/rust-lang/rust/issues/69941
107    // TODO: Add write_all_vectored once stabilized https://github.com/rust-lang/rust/issues/70436
108    quick_derive! {
109        input,
110        ::std::io::Write,
111        trait Write {
112            #[inline]
113            fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize>;
114            #[inline]
115            fn write_vectored(
116                &mut self,
117                bufs: &[::std::io::IoSlice<'_>],
118            ) -> ::std::io::Result<usize>;
119            #[inline]
120            fn flush(&mut self) -> ::std::io::Result<()>;
121            #[inline]
122            fn write_all(&mut self, buf: &[u8]) -> ::std::io::Result<()>;
123            #[inline]
124            fn write_fmt(&mut self, fmt: ::std::fmt::Arguments<'_>) -> ::std::io::Result<()>;
125        }
126    }
127}
128
129#[proc_macro_derive(Seek)]
130pub fn derive_seek(input: TokenStream) -> TokenStream {
131    quick_derive! {
132        input,
133        ::std::io::Seek,
134        trait Seek {
135            #[inline]
136            fn seek(&mut self, pos: ::std::io::SeekFrom) -> ::std::io::Result<u64>;
137        }
138    }
139}
140
141#[proc_macro_derive(BufRead)]
142pub fn derive_buf_read(input: TokenStream) -> TokenStream {
143    quick_derive! {
144        input,
145        ::std::io::BufRead,
146        trait BufRead {
147            #[inline]
148            fn fill_buf(&mut self) -> ::std::io::Result<&[u8]>;
149            #[inline]
150            fn consume(&mut self, amt: usize);
151            #[inline]
152            fn read_until(
153                &mut self, byte: u8, buf: &mut ::std::vec::Vec<u8>,
154            ) -> ::std::io::Result<usize>;
155            #[inline]
156            fn read_line(&mut self, buf: &mut ::std::string::String) -> ::std::io::Result<usize>;
157        }
158    }
159}