Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[byteorder] Make some methods const #851

Merged
merged 1 commit into from
Feb 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:
matrix:
# See `INTERNAL.md` for an explanation of these pinned toolchain
# versions.
toolchain: [ "msrv", "stable", "nightly", "zerocopy-aarch64-simd" ]
toolchain: [ "msrv", "stable", "nightly", "zerocopy-aarch64-simd", "zerocopy-generic-bounds-in-const-fn" ]
target: [
"i686-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
Expand All @@ -61,6 +61,8 @@ jobs:
features: "--all-features"
- toolchain: "zerocopy-aarch64-simd"
features: "--all-features"
- toolchain: "zerocopy-generic-bounds-in-const-fn"
features: "--all-features"
# Exclude any combination for the zerocopy-derive crate which
# uses zerocopy features.
- crate: "zerocopy-derive"
Expand All @@ -75,6 +77,8 @@ jobs:
# zerocopy-derive doesn't behave different on these toolchains.
- crate: "zerocopy-derive"
toolchain: "zerocopy-aarch64-simd"
- crate: "zerocopy-derive"
toolchain: "zerocopy-generic-bounds-in-const-fn"

name: Build & Test (crate:${{ matrix.crate }}, toolchain:${{ matrix.toolchain }}, target:${{ matrix.target }}, features:${{ matrix.features }})

Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ exclude = [".*"]
# versions, these types require the "simd-nightly" feature.
zerocopy-aarch64-simd = "1.59.0"

# From 1.61.0, Rust supports generic types with trait bounds in `const fn`.
zerocopy-generic-bounds-in-const-fn = "1.61.0"

[package.metadata.ci]
# The versions of the stable and nightly compiler toolchains to use in CI.
pinned-stable = "1.75.0"
Expand Down
3 changes: 2 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,14 @@ fn main() {
}
}

#[derive(Ord, PartialEq, PartialOrd, Eq)]
#[derive(Debug, Ord, PartialEq, PartialOrd, Eq)]
struct Version {
major: usize,
minor: usize,
patch: usize,
}

#[derive(Debug)]
struct VersionCfg {
version: Version,
cfg_name: String,
Expand Down
55 changes: 36 additions & 19 deletions src/byteorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,40 +401,45 @@ example of how it can be used for parsing UDP packets.
/// Constructs a new value from bytes which are already in `O` byte
/// order.
#[inline(always)]
pub fn from_bytes(bytes: [u8; $bytes]) -> $name<O> {
pub const fn from_bytes(bytes: [u8; $bytes]) -> $name<O> {
$name(bytes, PhantomData)
}

/// Extracts the bytes of `self` without swapping the byte order.
///
/// The returned bytes will be in `O` byte order.
#[inline(always)]
pub fn to_bytes(self) -> [u8; $bytes] {
pub const fn to_bytes(self) -> [u8; $bytes] {
self.0
}
}

impl<O: ByteOrder> $name<O> {
/// Constructs a new value, possibly performing an endianness swap
/// to guarantee that the returned value has endianness `O`.
#[inline(always)]
pub fn new(n: $native) -> $name<O> {
let bytes = match O::ORDER {
Order::BigEndian => $to_be_fn(n),
Order::LittleEndian => $to_le_fn(n),
};
maybe_const_trait_bounded_fn! {
/// Constructs a new value, possibly performing an endianness
/// swap to guarantee that the returned value has endianness
/// `O`.
#[inline(always)]
pub const fn new(n: $native) -> $name<O> {
let bytes = match O::ORDER {
Order::BigEndian => $to_be_fn(n),
Order::LittleEndian => $to_le_fn(n),
};

$name(bytes, PhantomData)
$name(bytes, PhantomData)
}
}

/// Returns the value as a primitive type, possibly performing an
/// endianness swap to guarantee that the return value has the
/// endianness of the native platform.
#[inline(always)]
pub fn get(self) -> $native {
match O::ORDER {
Order::BigEndian => $from_be_fn(self.0),
Order::LittleEndian => $from_le_fn(self.0),
maybe_const_trait_bounded_fn! {
/// Returns the value as a primitive type, possibly performing
/// an endianness swap to guarantee that the return value has
/// the endianness of the native platform.
#[inline(always)]
pub const fn get(self) -> $native {
match O::ORDER {
Order::BigEndian => $from_be_fn(self.0),
Order::LittleEndian => $from_le_fn(self.0),
}
}
}

Expand Down Expand Up @@ -1123,6 +1128,18 @@ mod tests {
1024
};

#[test]
fn test_const_methods() {
use big_endian::*;

#[rustversion::since(1.61.0)]
const _U: U16 = U16::new(0);
#[rustversion::since(1.61.0)]
const _NATIVE: u16 = _U.get();
const _FROM_BYTES: U16 = U16::from_bytes([0, 1]);
const _BYTES: [u8; 2] = _FROM_BYTES.to_bytes();
}

#[cfg_attr(test, test)]
#[cfg_attr(kani, kani::proof)]
fn test_zero() {
Expand Down
16 changes: 16 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -416,3 +416,19 @@ macro_rules! assert_unaligned {
$(assert_unaligned!($ty);)*
};
}

/// Emits a function definition as either `const fn` or `fn` depending on
/// whether the current toolchain version supports `const fn` with generic trait
/// bounds.
macro_rules! maybe_const_trait_bounded_fn {
// This case handles both `self` methods (where `self` is by value) and
// non-method functions. Each `$args` may optionally be followed by `:
// $arg_tys:ty`, which can be omitted for `self`.
($(#[$attr:meta])* $vis:vis const fn $name:ident($($args:ident $(: $arg_tys:ty)?),* $(,)?) $(-> $ret_ty:ty)? $body:block) => {
#[cfg(zerocopy_generic_bounds_in_const_fn)]
$(#[$attr])* $vis const fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body

#[cfg(not(zerocopy_generic_bounds_in_const_fn))]
$(#[$attr])* $vis fn $name($($args $(: $arg_tys)?),*) $(-> $ret_ty)? $body
};
}