#![allow(unknown_lints, non_local_definitions, unreachable_patterns)]
#![deny(renamed_and_removed_lints)]
#![deny(
anonymous_parameters,
deprecated_in_future,
late_bound_lifetime_arguments,
missing_docs,
path_statements,
patterns_in_fns_without_body,
rust_2018_idioms,
trivial_numeric_casts,
unreachable_pub,
unsafe_op_in_unsafe_fn,
unused_extern_crates,
// We intentionally choose not to deny `unused_qualifications`. When items
// are added to the prelude (e.g., `core::mem::size_of`), this has the
// consequence of making some uses trigger this lint on the latest toolchain
// (e.g., `mem::size_of`), but fixing it (e.g. by replacing with `size_of`)
// does not work on older toolchains.
//
// We tested a more complicated fix in #1413, but ultimately decided that,
// since this lint is just a minor style lint, the complexity isn't worth it
// - it's fine to occasionally have unused qualifications slip through,
// especially since these do not affect our user-facing API in any way.
variant_size_differences
)]
#![deny(
clippy::all,
clippy::alloc_instead_of_core,
clippy::arithmetic_side_effects,
clippy::as_underscore,
clippy::assertions_on_result_states,
clippy::as_conversions,
clippy::correctness,
clippy::dbg_macro,
clippy::decimal_literal_representation,
clippy::double_must_use,
clippy::get_unwrap,
clippy::indexing_slicing,
clippy::missing_const_for_fn,
clippy::missing_inline_in_public_items,
clippy::missing_safety_doc,
clippy::must_use_candidate,
clippy::must_use_unit,
clippy::obfuscated_if_else,
clippy::perf,
clippy::print_stdout,
clippy::return_self_not_must_use,
clippy::std_instead_of_core,
clippy::style,
clippy::suspicious,
clippy::todo,
clippy::undocumented_unsafe_blocks,
clippy::unimplemented,
clippy::unnested_or_patterns,
clippy::unwrap_used,
clippy::use_debug
)]
#![allow(clippy::type_complexity)]
#![deny(
rustdoc::bare_urls,
rustdoc::broken_intra_doc_links,
rustdoc::invalid_codeblock_attributes,
rustdoc::invalid_html_tags,
rustdoc::invalid_rust_codeblocks,
rustdoc::missing_crate_level_docs,
rustdoc::private_intra_doc_links
)]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
use core::marker::PhantomData;
#[repr(transparent)]
pub struct Unsafe<O: ?Sized, F: ?Sized, const NAME_HASH: u128> {
_marker: PhantomData<O>,
field: F,
}
impl<O: ?Sized, F: Copy, const NAME_HASH: u128> Copy for Unsafe<O, F, { NAME_HASH }> {}
impl<O: ?Sized, F: Copy, const NAME_HASH: u128> Clone for Unsafe<O, F, { NAME_HASH }> {
#[inline(always)]
#[allow(clippy::non_canonical_clone_impl)]
fn clone(&self) -> Self {
Unsafe { _marker: PhantomData, field: self.field }
}
}
impl<O: ?Sized, F: ?Sized, const NAME_HASH: u128> Unsafe<O, F, { NAME_HASH }> {
#[inline(always)]
pub const unsafe fn as_ref_unchecked(&self) -> &F {
&self.field
}
#[inline(always)]
#[cfg(feature = "zerocopy_0_8")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "zerocopy_0_8")))]
pub const fn as_ref(&self) -> &F
where
F: zerocopy_0_8::Immutable,
{
unsafe { self.as_ref_unchecked() }
}
#[inline(always)]
pub unsafe fn as_mut(&mut self) -> &mut F {
&mut self.field
}
}
impl<O: ?Sized, F, const NAME_HASH: u128> Unsafe<O, F, { NAME_HASH }> {
#[inline(always)]
pub const unsafe fn new(field: F) -> Unsafe<O, F, { NAME_HASH }> {
Unsafe { _marker: PhantomData, field }
}
#[inline(always)]
pub const fn into(self) -> F {
use core::mem::ManuallyDrop;
let slf = ManuallyDrop::new(self);
#[repr(C)]
union Transmute<Src, Dst> {
src: ManuallyDrop<Src>,
dst: ManuallyDrop<Dst>,
}
let dst = unsafe { Transmute { src: slf }.dst };
ManuallyDrop::into_inner(dst)
}
}
#[macro_export]
macro_rules! unsafe_fields {
($(#[$attr:meta])* $vis:vis struct $name:ident {
$($(#[$field_attr:tt])? $field:ident: $field_ty:ty),* $(,)?
}) => {
$(#[$attr])*
$vis struct $name {
$(
$field: unsafe_fields!(@field $(#[$field_attr])? $field: $field_ty),
)*
}
};
(@field #[unsafe] $field:ident: $field_ty:ty) => {
$crate::Unsafe<Self, $field_ty, {$crate::macro_util::hash_field_name(stringify!($field))}>
};
(@field $_field:ident: $field_ty:ty) => {
$field_ty
}
}
#[doc(hidden)]
pub mod macro_util {
#[inline(always)]
#[must_use]
#[allow(clippy::as_conversions, clippy::indexing_slicing, clippy::arithmetic_side_effects)]
pub const fn hash_field_name(field_name: &str) -> u128 {
let field_name = field_name.as_bytes();
let mut hash = 0u128;
let mut i = 0;
while i < field_name.len() {
const K: u128 = 0x517cc1b727220a95517cc1b727220a95;
hash = (hash.rotate_left(5) ^ (field_name[i] as u128)).wrapping_mul(K);
i += 1;
}
hash
}
}
#[cfg(test)]
#[allow(clippy::missing_const_for_fn)]
mod tests {
use super::*;
unsafe_fields! {
#[allow(unused)]
struct Foo {
#[unsafe]
a: usize,
b: usize,
}
}
unsafe_fields! {
#[allow(unused)]
struct Bar {
#[unsafe]
a: usize,
#[unsafe]
b: usize,
}
}
#[test]
#[allow(clippy::undocumented_unsafe_blocks)]
fn test_unsafe_fieds() {
let mut _foo = Foo { a: unsafe { Unsafe::new(0) }, b: 0 };
let mut _bar = Bar { a: unsafe { Unsafe::new(0) }, b: unsafe { Unsafe::new(0) } };
}
}
#[doc(hidden)]
pub mod compile_fail {}