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;
53mod invariant;
54#[cfg(test)]
55mod output_tests;
56mod repr;
57mod util;
58
59use syn::{DeriveInput, Error};
60
61use crate::util::*;
62
63macro_rules! derive {
87 ($(#[$attr:meta])* $trait:ident => $outer:ident => $inner:path) => {
88 $(#[$attr])*
89 #[proc_macro_derive($trait, attributes(zerocopy))]
90 pub fn $outer(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
91 let ast = syn::parse_macro_input!(ts as DeriveInput);
92 let ctx = match Ctx::try_from_derive_input(ast) {
93 Ok(ctx) => ctx,
94 Err(e) => return e.into_compile_error().into(),
95 };
96 let ts = $inner(&ctx, Trait::$trait).into_ts();
97 let ts = if matches!(Trait::$trait, Trait::TryFromBytes) {
100 ctx.const_block([Some(ts)])
101 } else {
102 const_block([Some(ts)])
103 };
104 #[cfg(test)]
105 crate::util::testutil::check_hygiene(ts.clone());
106 ts.into()
107 }
108 };
109}
110
111trait IntoTokenStream {
112 fn into_ts(self) -> proc_macro2::TokenStream;
113}
114
115impl IntoTokenStream for proc_macro2::TokenStream {
116 fn into_ts(self) -> proc_macro2::TokenStream {
117 self
118 }
119}
120
121impl IntoTokenStream for Result<proc_macro2::TokenStream, Error> {
122 fn into_ts(self) -> proc_macro2::TokenStream {
123 match self {
124 Ok(ts) => ts,
125 Err(err) => err.to_compile_error(),
126 }
127 }
128}
129
130derive!(KnownLayout => derive_known_layout => crate::derive::known_layout::derive);
131derive!(Immutable => derive_immutable => crate::derive::derive_immutable);
132derive!(#[doc(hidden)] Project => derive_project => crate::derive::project::derive);
133derive!(TryFromBytes => derive_try_from_bytes => crate::derive::try_from_bytes::derive_try_from_bytes);
134derive!(FromZeros => derive_from_zeros => crate::derive::from_bytes::derive_from_zeros);
135derive!(FromBytes => derive_from_bytes => crate::derive::from_bytes::derive_from_bytes);
136derive!(IntoBytes => derive_into_bytes => crate::derive::into_bytes::derive_into_bytes);
137derive!(Unaligned => derive_unaligned => crate::derive::unaligned::derive_unaligned);
138derive!(ByteHash => derive_hash => crate::derive::derive_hash);
139derive!(ByteEq => derive_eq => crate::derive::derive_eq);
140derive!(SplitAt => derive_split_at => crate::derive::derive_split_at);
141
142#[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
146#[doc(hidden)]
147#[proc_macro]
148pub fn __test_hygienically_mixed_into_bytes(
149 _input: proc_macro::TokenStream,
150) -> proc_macro::TokenStream {
151 use proc_macro::{Group, Ident, Span, TokenStream, TokenTree};
152
153 fn rewrite(input: TokenStream) -> TokenStream {
154 input
155 .into_iter()
156 .map(|token| match token {
157 TokenTree::Ident(ident) if ident.to_string() == "CallT" => {
158 TokenTree::Ident(Ident::new("T", Span::call_site()))
159 }
160 TokenTree::Ident(ident) if ident.to_string() == "DefT" => {
161 TokenTree::Ident(Ident::new("T", Span::def_site()))
162 }
163 TokenTree::Group(group) => {
164 let mut rewritten = Group::new(group.delimiter(), rewrite(group.stream()));
165 rewritten.set_span(group.span());
166 TokenTree::Group(rewritten)
167 }
168 token => token,
169 })
170 .collect()
171 }
172
173 rewrite(
174 "#[derive(zerocopy_renamed::IntoBytes)] \
175 #[zerocopy(crate = \"zerocopy_renamed\")] \
176 #[repr(C)] \
177 struct IntoBytes15<DefT>(CallT, DefT);"
178 .parse()
179 .expect("test input must parse"),
180 )
181}
182
183#[doc(hidden)]
186#[proc_macro]
187pub fn __test_hygienically_mixed_invariant(
188 input: proc_macro::TokenStream,
189) -> proc_macro::TokenStream {
190 #[cfg(not(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS))]
193 {
194 let _ = input;
195 proc_macro::TokenStream::new()
196 }
197 #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)]
198 {
199 use proc_macro::{Group, Ident, Span, TokenStream, TokenTree};
200
201 fn rewrite(input: TokenStream) -> TokenStream {
202 input
203 .into_iter()
204 .map(|token| match token {
205 TokenTree::Ident(ident) if ident.to_string() == "DefField" => {
206 TokenTree::Ident(Ident::new("field", Span::def_site()))
207 }
208 TokenTree::Ident(ident) if ident.to_string() == "CallField" => {
209 TokenTree::Ident(Ident::new("field", Span::call_site()))
210 }
211 TokenTree::Group(group) => {
212 let mut rewritten = Group::new(group.delimiter(), rewrite(group.stream()));
213 rewritten.set_span(group.span());
214 TokenTree::Group(rewritten)
215 }
216 token => token,
217 })
218 .collect()
219 }
220
221 rewrite(input)
222 }
223}
224
225#[cfg_attr(not(zerocopy_unstable_linux), doc(hidden))]
226#[proc_macro_derive(most_traits, attributes(zerocopy))]
227pub fn most_traits(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
228 let ast = syn::parse_macro_input!(ts as DeriveInput);
229 let ctx = match Ctx::try_from_derive_input(ast) {
230 Ok(ctx) => ctx,
231 Err(e) => return e.into_compile_error().into(),
232 }
233 .skip_on_error();
234
235 let derives: [(fn(&Ctx, Trait) -> _, _); 6] = [
237 (crate::derive::known_layout::derive, Trait::KnownLayout),
238 (crate::derive::derive_immutable, Trait::Immutable),
239 (crate::derive::from_bytes::derive_from_bytes, Trait::FromBytes),
240 (crate::derive::into_bytes::derive_into_bytes, Trait::IntoBytes),
241 (crate::derive::derive_split_at, Trait::SplitAt),
242 (crate::derive::unaligned::derive_unaligned, Trait::Unaligned),
243 ];
244
245 let mut tokens = proc_macro2::TokenStream::new();
246 for (derive, t) in derives {
247 tokens.extend(derive(&ctx, t))
248 }
249 if ctx.invariant_span.is_some() {
252 tokens.extend(crate::derive::try_from_bytes::derive_try_from_bytes(
253 &ctx,
254 Trait::TryFromBytes,
255 ));
256 }
257
258 let ts = ctx.const_block([Some(tokens)]);
261 #[cfg(test)]
262 crate::util::testutil::check_hygiene(ts.clone());
263 ts.into()
264}
265
266#[deprecated(since = "0.8.0", note = "`FromZeroes` was renamed to `FromZeros`")]
268#[doc(hidden)]
269#[proc_macro_derive(FromZeroes)]
270pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
271 derive_from_zeros(ts)
272}
273
274#[deprecated(since = "0.8.0", note = "`AsBytes` was renamed to `IntoBytes`")]
276#[doc(hidden)]
277#[proc_macro_derive(AsBytes)]
278pub fn derive_as_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
279 derive_into_bytes(ts)
280}