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}