From e02f4768ce2ee30473200fe98e2687e42acb9c33 Mon Sep 17 00:00:00 2001 From: EdJoPaTo Date: Mon, 4 Mar 2024 06:17:28 +0100 Subject: [PATCH] perf(borders): allow border!() in const (#977) This allows more compiler optimizations when the macro is used. --- src/widgets/borders.rs | 94 ++++++++++++++++++++++++++++++++---------- tests/border_macro.rs | 19 --------- 2 files changed, 72 insertions(+), 41 deletions(-) delete mode 100644 tests/border_macro.rs diff --git a/src/widgets/borders.rs b/src/widgets/borders.rs index eb44a70e..3d1cef25 100644 --- a/src/widgets/borders.rs +++ b/src/widgets/borders.rs @@ -51,39 +51,52 @@ impl Debug for Borders { } } -/// Macro that constructs and returns a [`Borders`] object from TOP, BOTTOM, LEFT, RIGHT, NONE, and -/// ALL. Internally it creates an empty `Borders` object and then inserts each bit flag specified -/// into it using `Borders::insert()`. +/// Macro that constructs and returns a combination of the [`Borders`] object from TOP, BOTTOM, LEFT +/// and RIGHT. +/// +/// When used with NONE you should consider omitting this completely. For ALL you should consider +/// [`Block::bordered()`](crate::widgets::Block::bordered) instead. /// /// ## Examples /// -///``` -/// use ratatui::{border, prelude::*, widgets::*}; -/// -/// Block::default() -/// //Construct a `Borders` object and use it in place +/// ``` +/// # use ratatui::{border, prelude::*, widgets::*}; +/// Block::new() +/// .title("Construct Borders and use them in place") /// .borders(border!(TOP, BOTTOM)); +/// ``` /// -/// //`border!` can be called with any order of individual sides -/// let bottom_first = border!(BOTTOM, LEFT, TOP); -/// //with the ALL keyword which works as expected -/// let all = border!(ALL); -/// //or with nothing to return a `Borders::NONE' bitflag. -/// let none = border!(NONE); +/// `border!` can be called with any number of individual sides: +/// +/// ``` +/// # use ratatui::{border, prelude::*, widgets::*}; +/// let right_open = border!(TOP, LEFT, BOTTOM); +/// assert_eq!(right_open, Borders::TOP | Borders::LEFT | Borders::BOTTOM); +/// ``` +/// +/// Single borders work but using `Borders::` directly would be simpler. +/// +/// ``` +/// # use ratatui::{border, prelude::*, widgets::*}; +/// assert_eq!(border!(TOP), Borders::TOP); +/// assert_eq!(border!(ALL), Borders::ALL); +/// assert_eq!(border!(), Borders::NONE); /// ``` #[cfg(feature = "macros")] #[macro_export] macro_rules! border { -( $($b:tt), +) => {{ - let mut border = Borders::empty(); + () => { + Borders::NONE + }; + ($b:ident) => { + Borders::$b + }; + ($first:ident,$($other:ident),*) => { + Borders::$first $( - border.insert(Borders::$b); + .union(Borders::$other) )* - border -}}; -() =>{ - Borders::NONE -} + }; } #[cfg(test)] @@ -107,3 +120,40 @@ mod tests { ); } } + +#[cfg(all(test, feature = "macros"))] +mod macro_tests { + use super::*; + + #[test] + fn can_be_const() { + const NOTHING: Borders = border!(); + const JUST_TOP: Borders = border!(TOP); + const TOP_BOTTOM: Borders = border!(TOP, BOTTOM); + const RIGHT_OPEN: Borders = border!(TOP, LEFT, BOTTOM); + + assert_eq!(NOTHING, Borders::NONE); + assert_eq!(JUST_TOP, Borders::TOP); + assert_eq!(TOP_BOTTOM, Borders::TOP | Borders::BOTTOM); + assert_eq!(RIGHT_OPEN, Borders::TOP | Borders::LEFT | Borders::BOTTOM); + } + + #[test] + fn border_empty() { + let empty = Borders::NONE; + assert_eq!(empty, border!()); + } + + #[test] + fn border_all() { + let all = Borders::ALL; + assert_eq!(all, border!(ALL)); + assert_eq!(all, border!(TOP, BOTTOM, LEFT, RIGHT)); + } + + #[test] + fn border_left_right() { + let left_right = Borders::from_bits(Borders::LEFT.bits() | Borders::RIGHT.bits()); + assert_eq!(left_right, Some(border!(RIGHT, LEFT))); + } +} diff --git a/tests/border_macro.rs b/tests/border_macro.rs deleted file mode 100644 index fc8cc8cd..00000000 --- a/tests/border_macro.rs +++ /dev/null @@ -1,19 +0,0 @@ -#![cfg(feature = "macros")] -use ratatui::{border, widgets::Borders}; - -#[test] -fn border_empty_test() { - let empty = Borders::NONE; - assert_eq!(empty, border!()); -} -#[test] -fn border_all_test() { - let all = Borders::ALL; - assert_eq!(all, border!(ALL)); - assert_eq!(all, border!(TOP, BOTTOM, LEFT, RIGHT)); -} -#[test] -fn border_left_right_test() { - let left_right = Borders::from_bits(Borders::LEFT.bits() | Borders::RIGHT.bits()); - assert_eq!(left_right, Some(border!(RIGHT, LEFT))); -}