1#![allow(unknown_lints)]
20#![deny(renamed_and_removed_lints)]
21#![deny(
22 clippy::all,
23 clippy::missing_safety_doc,
24 clippy::multiple_unsafe_ops_per_block,
25 clippy::undocumented_unsafe_blocks
26)]
27#![allow(clippy::type_complexity)]
29#![allow(clippy::uninlined_format_args)]
31#![cfg_attr(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS, feature(proc_macro_def_site))]
35#![deny(
36 rustdoc::bare_urls,
37 rustdoc::broken_intra_doc_links,
38 rustdoc::invalid_codeblock_attributes,
39 rustdoc::invalid_html_tags,
40 rustdoc::invalid_rust_codeblocks,
41 rustdoc::missing_crate_level_docs,
42 rustdoc::private_intra_doc_links
43)]
44#![recursion_limit = "128"]
45
46macro_rules! ident {
47 (($fmt:literal $(, $arg:expr)*), $span:expr) => {
48 syn::Ident::new(&format!($fmt $(, crate::util::to_ident_str($arg))*), $span)
49 };
50}
51
52mod derive;
53#[cfg(test)]
54mod output_tests;
55mod repr;
56mod util;
57
58use syn::{DeriveInput, Error};
59
60use crate::util::*;
61
62macro_rules! derive {
86 ($trait:ident => $outer:ident => $inner:path) => {
87 #[proc_macro_derive($trait, attributes(zerocopy))]
88 pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
89 let ast = syn::parse_macro_input!(ts as DeriveInput);
90 let ctx = match Ctx::try_from_derive_input(ast) {
91 Ok(ctx) => ctx,
92 Err(e) => return e.into_compile_error().into(),
93 };
94 let ts = $inner(&ctx, Trait::$trait).into_ts();
95 let ts = const_block([Some(ts)]);
99 #[cfg(test)]
100 crate::util::testutil::check_hygiene(ts.clone());
101 ts.into()
102 }
103 };
104}
105
106trait IntoTokenStream {
107 fn into_ts(self) -> proc_macro2::TokenStream;
108}
109
110impl IntoTokenStream for proc_macro2::TokenStream {
111 fn into_ts(self) -> proc_macro2::TokenStream {
112 self
113 }
114}
115
116impl IntoTokenStream for Result<proc_macro2::TokenStream, Error> {
117 fn into_ts(self) -> proc_macro2::TokenStream {
118 match self {
119 Ok(ts) => ts,
120 Err(err) => err.to_compile_error(),
121 }
122 }
123}
124
125derive!(KnownLayout => derive_known_layout => crate::derive::known_layout::derive);
126derive!(Immutable => derive_immutable => crate::derive::derive_immutable);
127derive!(TryFromBytes => derive_try_from_bytes => crate::derive::try_from_bytes::derive_try_from_bytes);
128derive!(FromZeros => derive_from_zeros => crate::derive::from_bytes::derive_from_zeros);
129derive!(FromBytes => derive_from_bytes => crate::derive::from_bytes::derive_from_bytes);
130derive!(IntoBytes => derive_into_bytes => crate::derive::into_bytes::derive_into_bytes);
131derive!(Unaligned => derive_unaligned => crate::derive::unaligned::derive_unaligned);
132derive!(ByteHash => derive_hash => crate::derive::derive_hash);
133derive!(ByteEq => derive_eq => crate::derive::derive_eq);
134derive!(SplitAt => derive_split_at => crate::derive::derive_split_at);
135
136#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
140#[doc(hidden)]
141#[proc_macro]
142pub fn __test_hygienically_mixed_into_bytes(
143 _input: proc_macro::TokenStream,
144) -> proc_macro::TokenStream {
145 use proc_macro::{Group, Ident, Span, TokenStream, TokenTree};
146
147 fn rewrite(input: TokenStream) -> TokenStream {
148 input
149 .into_iter()
150 .map(|token| match token {
151 TokenTree::Ident(ident) if ident.to_string() == "CallT" => {
152 TokenTree::Ident(Ident::new("T", Span::call_site()))
153 }
154 TokenTree::Ident(ident) if ident.to_string() == "DefT" => {
155 TokenTree::Ident(Ident::new("T", Span::def_site()))
156 }
157 TokenTree::Group(group) => {
158 let mut rewritten = Group::new(group.delimiter(), rewrite(group.stream()));
159 rewritten.set_span(group.span());
160 TokenTree::Group(rewritten)
161 }
162 token => token,
163 })
164 .collect()
165 }
166
167 rewrite(
168 "#[derive(zerocopy_renamed::IntoBytes)] \
169 #[zerocopy(crate = \"zerocopy_renamed\")] \
170 #[repr(C)] \
171 struct IntoBytes15<DefT>(CallT, DefT);"
172 .parse()
173 .expect("test input must parse"),
174 )
175}
176
177#[cfg_attr(not(zerocopy_unstable_linux), doc(hidden))]
178#[proc_macro_derive(most_traits, attributes(zerocopy))]
179pub fn most_traits(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
180 let ast = syn::parse_macro_input!(ts as DeriveInput);
181 let ctx = match Ctx::try_from_derive_input(ast) {
182 Ok(ctx) => ctx,
183 Err(e) => return e.into_compile_error().into(),
184 }
185 .skip_on_error();
186
187 let derives: [(fn(&Ctx, Trait) -> _, _); 6] = [
189 (crate::derive::known_layout::derive, Trait::KnownLayout),
190 (crate::derive::derive_immutable, Trait::Immutable),
191 (crate::derive::from_bytes::derive_from_bytes, Trait::FromBytes),
192 (crate::derive::into_bytes::derive_into_bytes, Trait::IntoBytes),
193 (crate::derive::derive_split_at, Trait::SplitAt),
194 (crate::derive::unaligned::derive_unaligned, Trait::Unaligned),
195 ];
196
197 let mut tokens = proc_macro2::TokenStream::new();
198 for (derive, t) in derives {
199 tokens.extend(derive(&ctx, t))
200 }
201
202 let ts = const_block([Some(tokens)]);
206 #[cfg(test)]
207 crate::util::testutil::check_hygiene(ts.clone());
208 ts.into()
209}
210
211#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
213#[doc(hidden)]
214#[proc_macro_derive(FromZeroes)]
215pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
216 derive_from_zeros(ts)
217}
218
219#[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")]
221#[doc(hidden)]
222#[proc_macro_derive(AsBytes)]
223pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
224 derive_into_bytes(ts)
225}