Skip to content

Commit

Permalink
Add const_fn!{} macro to make functions const without duplication.
Browse files Browse the repository at this point in the history
Many functions that can be const live in a generic context with bounds,
where `const fn` is not allowed without the "const_fn" feature.
In many places, functions duplicated becaue of this: A version with and
version without `const`.

This macro cleans that up by making it easy to define a function as
const only if possible, removing all duplication.

Also makes some more functions const using this macro.
  • Loading branch information
m-ou-se committed Apr 11, 2020
1 parent dea25ee commit d46d7c2
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 166 deletions.
66 changes: 21 additions & 45 deletions src/instructions/port.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,21 +114,13 @@ pub struct Port<T: PortReadWrite> {
}

impl<T: PortRead> PortReadOnly<T> {
/// Creates a read only I/O port with the given port number.
#[cfg(feature = "const_fn")]
pub const fn new(port: u16) -> PortReadOnly<T> {
PortReadOnly {
port,
phantom: PhantomData,
}
}

/// Creates a read only I/O port with the given port number.
#[cfg(not(feature = "const_fn"))]
pub fn new(port: u16) -> PortReadOnly<T> {
PortReadOnly {
port,
phantom: PhantomData,
const_fn! {
/// Creates a read only I/O port with the given port number.
pub fn new(port: u16) -> PortReadOnly<T> {
PortReadOnly {
port,
phantom: PhantomData,
}
}
}

Expand All @@ -145,21 +137,13 @@ impl<T: PortRead> PortReadOnly<T> {
}

impl<T: PortWrite> PortWriteOnly<T> {
/// Creates a write only I/O port with the given port number.
#[cfg(feature = "const_fn")]
pub const fn new(port: u16) -> PortWriteOnly<T> {
PortWriteOnly {
port,
phantom: PhantomData,
}
}

/// Creates a write only I/O port with the given port number.
#[cfg(not(feature = "const_fn"))]
pub fn new(port: u16) -> PortWriteOnly<T> {
PortWriteOnly {
port,
phantom: PhantomData,
const_fn! {
/// Creates a write only I/O port with the given port number.
pub fn new(port: u16) -> PortWriteOnly<T> {
PortWriteOnly {
port,
phantom: PhantomData,
}
}
}

Expand All @@ -176,21 +160,13 @@ impl<T: PortWrite> PortWriteOnly<T> {
}

impl<T: PortReadWrite> Port<T> {
/// Creates an I/O port with the given port number.
#[cfg(feature = "const_fn")]
pub const fn new(port: u16) -> Port<T> {
Port {
port,
phantom: PhantomData,
}
}

/// Creates an I/O port with the given port number.
#[cfg(not(feature = "const_fn"))]
pub fn new(port: u16) -> Port<T> {
Port {
port,
phantom: PhantomData,
const_fn! {
/// Creates an I/O port with the given port number.
pub fn new(port: u16) -> Port<T> {
Port {
port,
phantom: PhantomData,
}
}
}

Expand Down
19 changes: 19 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@

pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};

/// Makes a function const only when `feature = "const_fn"` is enabled.
///
/// This is needed for const functions with bounds on their generic parameters,
/// such as those in `Page` and `PhysFrame` and many more.
macro_rules! const_fn {
(
$(#[$attr:meta])*
pub $($fn:tt)*
) => {
$(#[$attr])*
#[cfg(feature = "const_fn")]
pub const $($fn)*

$(#[$attr])*
#[cfg(not(feature = "const_fn"))]
pub $($fn)*
}
}

#[cfg(not(feature = "inline_asm"))]
pub(crate) mod asm;

Expand Down
91 changes: 30 additions & 61 deletions src/structures/idt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -370,67 +370,36 @@ pub struct InterruptDescriptorTable {
}

impl InterruptDescriptorTable {
/// Creates a new IDT filled with non-present entries.
#[cfg(feature = "const_fn")]
pub const fn new() -> InterruptDescriptorTable {
InterruptDescriptorTable {
divide_error: Entry::missing(),
debug: Entry::missing(),
non_maskable_interrupt: Entry::missing(),
breakpoint: Entry::missing(),
overflow: Entry::missing(),
bound_range_exceeded: Entry::missing(),
invalid_opcode: Entry::missing(),
device_not_available: Entry::missing(),
double_fault: Entry::missing(),
coprocessor_segment_overrun: Entry::missing(),
invalid_tss: Entry::missing(),
segment_not_present: Entry::missing(),
stack_segment_fault: Entry::missing(),
general_protection_fault: Entry::missing(),
page_fault: Entry::missing(),
reserved_1: Entry::missing(),
x87_floating_point: Entry::missing(),
alignment_check: Entry::missing(),
machine_check: Entry::missing(),
simd_floating_point: Entry::missing(),
virtualization: Entry::missing(),
reserved_2: [Entry::missing(); 9],
security_exception: Entry::missing(),
reserved_3: Entry::missing(),
interrupts: [Entry::missing(); 256 - 32],
}
}

/// Creates a new IDT filled with non-present entries.
#[cfg(not(feature = "const_fn"))]
pub fn new() -> InterruptDescriptorTable {
InterruptDescriptorTable {
divide_error: Entry::missing(),
debug: Entry::missing(),
non_maskable_interrupt: Entry::missing(),
breakpoint: Entry::missing(),
overflow: Entry::missing(),
bound_range_exceeded: Entry::missing(),
invalid_opcode: Entry::missing(),
device_not_available: Entry::missing(),
double_fault: Entry::missing(),
coprocessor_segment_overrun: Entry::missing(),
invalid_tss: Entry::missing(),
segment_not_present: Entry::missing(),
stack_segment_fault: Entry::missing(),
general_protection_fault: Entry::missing(),
page_fault: Entry::missing(),
reserved_1: Entry::missing(),
x87_floating_point: Entry::missing(),
alignment_check: Entry::missing(),
machine_check: Entry::missing(),
simd_floating_point: Entry::missing(),
virtualization: Entry::missing(),
reserved_2: [Entry::missing(); 9],
security_exception: Entry::missing(),
reserved_3: Entry::missing(),
interrupts: [Entry::missing(); 256 - 32],
const_fn! {
/// Creates a new IDT filled with non-present entries.
pub fn new() -> InterruptDescriptorTable {
InterruptDescriptorTable {
divide_error: Entry::missing(),
debug: Entry::missing(),
non_maskable_interrupt: Entry::missing(),
breakpoint: Entry::missing(),
overflow: Entry::missing(),
bound_range_exceeded: Entry::missing(),
invalid_opcode: Entry::missing(),
device_not_available: Entry::missing(),
double_fault: Entry::missing(),
coprocessor_segment_overrun: Entry::missing(),
invalid_tss: Entry::missing(),
segment_not_present: Entry::missing(),
stack_segment_fault: Entry::missing(),
general_protection_fault: Entry::missing(),
page_fault: Entry::missing(),
reserved_1: Entry::missing(),
x87_floating_point: Entry::missing(),
alignment_check: Entry::missing(),
machine_check: Entry::missing(),
simd_floating_point: Entry::missing(),
virtualization: Entry::missing(),
reserved_2: [Entry::missing(); 9],
security_exception: Entry::missing(),
reserved_3: Entry::missing(),
interrupts: [Entry::missing(); 256 - 32],
}
}
}

Expand Down
44 changes: 26 additions & 18 deletions src/structures/paging/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,30 +35,38 @@ impl<S: PageSize> PhysFrame<S> {
}
}

/// Returns the start address of the frame.
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn start_address(&self) -> PhysAddr {
self.start_address
const_fn! {
/// Returns the start address of the frame.
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn start_address(&self) -> PhysAddr {
self.start_address
}
}

/// Returns the size the frame (4KB, 2MB or 1GB).
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn size(&self) -> u64 {
S::SIZE
const_fn! {
/// Returns the size the frame (4KB, 2MB or 1GB).
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn size(&self) -> u64 {
S::SIZE
}
}

/// Returns a range of frames, exclusive `end`.
#[inline]
pub fn range(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRange<S> {
PhysFrameRange { start, end }
const_fn! {
/// Returns a range of frames, exclusive `end`.
#[inline]
pub fn range(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRange<S> {
PhysFrameRange { start, end }
}
}

/// Returns a range of frames, inclusive `end`.
#[inline]
pub fn range_inclusive(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRangeInclusive<S> {
PhysFrameRangeInclusive { start, end }
const_fn! {
/// Returns a range of frames, inclusive `end`.
#[inline]
pub fn range_inclusive(start: PhysFrame<S>, end: PhysFrame<S>) -> PhysFrameRangeInclusive<S> {
PhysFrameRangeInclusive { start, end }
}
}
}

Expand Down
92 changes: 50 additions & 42 deletions src/structures/paging/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,57 +84,63 @@ impl<S: PageSize> Page<S> {
}
}

/// Returns the start address of the page.
#[inline]
pub fn start_address(&self) -> VirtAddr {
self.start_address
}

/// Returns the size the page (4KB, 2MB or 1GB).
#[cfg(feature = "const_fn")]
#[inline]
pub const fn size(&self) -> u64 {
S::SIZE
const_fn! {
/// Returns the start address of the page.
#[inline]
pub fn start_address(&self) -> VirtAddr {
self.start_address
}
}

/// Returns the size the page (4KB, 2MB or 1GB).
#[cfg(not(feature = "const_fn"))]
#[inline]
pub fn size(&self) -> u64 {
S::SIZE
const_fn! {
/// Returns the size the page (4KB, 2MB or 1GB).
#[inline]
pub fn size(&self) -> u64 {
S::SIZE
}
}

/// Returns the level 4 page table index of this page.
#[inline]
pub fn p4_index(&self) -> PageTableIndex {
self.start_address().p4_index()
const_fn! {
/// Returns the level 4 page table index of this page.
#[inline]
pub fn p4_index(&self) -> PageTableIndex {
self.start_address().p4_index()
}
}

/// Returns the level 3 page table index of this page.
#[inline]
pub fn p3_index(&self) -> PageTableIndex {
self.start_address().p3_index()
const_fn! {
/// Returns the level 3 page table index of this page.
#[inline]
pub fn p3_index(&self) -> PageTableIndex {
self.start_address().p3_index()
}
}

/// Returns a range of pages, exclusive `end`.
#[inline]
pub fn range(start: Self, end: Self) -> PageRange<S> {
PageRange { start, end }
const_fn! {
/// Returns a range of pages, exclusive `end`.
#[inline]
pub fn range(start: Self, end: Self) -> PageRange<S> {
PageRange { start, end }
}
}

/// Returns a range of pages, inclusive `end`.
#[inline]
pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
PageRangeInclusive { start, end }
const_fn! {
/// Returns a range of pages, inclusive `end`.
#[inline]
pub fn range_inclusive(start: Self, end: Self) -> PageRangeInclusive<S> {
PageRangeInclusive { start, end }
}
}
}

impl<S: NotGiantPageSize> Page<S> {
/// Returns the level 2 page table index of this page.
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn p2_index(&self) -> PageTableIndex {
self.start_address().p2_index()
const_fn! {
/// Returns the level 2 page table index of this page.
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn p2_index(&self) -> PageTableIndex {
self.start_address().p2_index()
}
}
}

Expand Down Expand Up @@ -188,11 +194,13 @@ impl Page<Size4KiB> {
Page::containing_address(VirtAddr::new(addr))
}

/// Returns the level 1 page table index of this page.
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn p1_index(&self) -> PageTableIndex {
self.start_address().p1_index()
const_fn! {
/// Returns the level 1 page table index of this page.
#[allow(clippy::trivially_copy_pass_by_ref)]
#[inline]
pub fn p1_index(&self) -> PageTableIndex {
self.start_address().p1_index()
}
}
}

Expand Down

0 comments on commit d46d7c2

Please sign in to comment.