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