proxmox/proxmox-lang/src/lib.rs
Wolfgang Bumiller 5b2e8b4c66 Revert "lang: get offsetof const fn ready"
This reverts commit 8f89f9ad60.

generates broken code in release builds on current rustc
1.55
2021-11-17 10:07:08 +01:00

140 lines
3.6 KiB
Rust

//! Rust language related helpers.
//!
//! This provides some macros for features which are not yet available in the language, or
//! sometimes also types from nightly `std` which are simple enough to do just haven't been
//! bikeshedded and stabilized in the standard library yet.
mod constnamedbitmap;
pub mod ops;
/// Macro to write error-handling blocks (like perl eval {})
///
/// #### Example:
/// ```
/// # use proxmox_lang::try_block;
/// # macro_rules! format_err {
/// # ($($msg:tt)+) => { format!($($msg)+) }
/// # }
/// # macro_rules! bail {
/// # ($($msg:tt)+) => { return Err(format_err!($($msg)+)); }
/// # }
/// # let some_condition = false;
/// let result = try_block!({
/// if (some_condition) {
/// bail!("some error");
/// }
/// Ok(())
/// })
/// .map_err(|e| format_err!("my try block returned an error - {}", e));
/// ```
#[macro_export]
macro_rules! try_block {
{ $($token:tt)* } => {{ (|| -> Result<_,_> { $($token)* })() }}
}
/// Statically assert the size of a type at compile time.
///
/// This should compile:
/// ```
/// # use proxmox_lang::static_assert_size;
/// #[repr(C)]
/// struct Stuff {
/// value: [u8; 32]
/// }
/// static_assert_size!(Stuff, 32);
/// ```
///
/// This should fail to compile:
/// ```compile_fail
/// # use proxmox_lang::static_assert_size;
/// #[repr(C)]
/// struct Stuff {
/// value: [u8; 32]
/// }
/// static_assert_size!(Stuff, 128);
/// ```
#[macro_export]
macro_rules! static_assert_size {
($ty:ty, $size:expr) => {
const _: fn() -> () = || {
let _ = ::std::mem::transmute::<[u8; $size], $ty>;
};
};
}
/// Evaluates to the offset (in bytes) of a given member within a struct
///
/// ```
/// # use proxmox_lang::offsetof;
///
/// #[repr(C)]
/// struct Stuff {
/// first: u32,
/// second: u32,
/// }
///
/// assert_eq!(offsetof!(Stuff, second), 4);
///
/// ```
// FIXME: With 1.56 we get `const transmute` which may help making this usable `const fn` as we can
// avoid dereferencing the raw pointer by transmuting `0usize` into a proper reference instead.
//
// So with 1.56, do this instead:
//
// unsafe { &(std::mem::transmute::<_, &$ty>(0usize).$field) as *const _ as usize }
#[macro_export]
macro_rules! offsetof {
($ty:ty, $field:ident) => {
unsafe { &(*(std::ptr::null::<$ty>())).$field as *const _ as usize }
};
}
/// Shortcut for generating an `&'static CStr`.
///
/// This takes a *string* (*not* a *byte-string*), appends a terminating zero, and calls
/// `CStr::from_bytes_with_nul_unchecked`.
///
/// Shortcut for:
/// ```no_run
/// let bytes = concat!("THE TEXT", "\0");
/// unsafe { ::std::ffi::CStr::from_bytes_with_nul_unchecked(bytes.as_bytes()) }
/// # ;
/// ```
#[macro_export]
macro_rules! c_str {
($data:expr) => {{
let bytes = concat!($data, "\0");
unsafe { ::std::ffi::CStr::from_bytes_with_nul_unchecked(bytes.as_bytes()) }
}};
}
/*
// With rust 1.56 we can enable the `c_str!()` macro for const fns:
#[doc(hidden)]
#[allow(unconditional_panic)]
pub const fn illegal_c_string() {
[][0]
}
/// Assert that a static byte slice is a valid C string (has no zeros except at the very end),
/// and return it as a `&'static CStr`.
pub const fn checked_c_str(bytes: &'static [u8]) -> &'static std::ffi::CStr {
let mut i = 0;
while i < bytes.len() - 1 {
if bytes[i] == 0 {
illegal_c_string();
}
i += 1;
}
unsafe { std::mem::transmute::<_, &'static std::ffi::CStr>(bytes) }
}
#[macro_export]
macro_rules! c_str {
($data:expr) => { $crate::checked_c_str(concat!($data, "\0")) };
}
*/