// Copyright (C) Parity Technologies (UK) Ltd.
// This file is part of Pezkuwi.
// Pezkuwi is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Pezkuwi is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Pezkuwi. If not, see .
//! A helper macro for generating `SlotRange` enum.
#![cfg_attr(not(feature = "std"), no_std)]
pub use codec::{Decode, Encode};
pub use core::{ops::Add, result};
pub use enumn::N;
pub use paste;
pub use sp_runtime::traits::CheckedSub;
/// This macro generates a `SlotRange` enum of arbitrary length for use in the Slot Auction
/// mechanism on Pezkuwi.
///
/// Usage:
/// ```
/// slot_range_helper::generate_slot_range!(Zero(0), One(1), Two(2), Three(3));
/// ```
///
/// To extend the usage, continue to add `Identifier(value)` items to the macro.
///
/// This will generate an enum `SlotRange` with the following properties:
///
/// * Enum variants will range from all consecutive combinations of inputs, i.e. `ZeroZero`,
/// `ZeroOne`, `ZeroTwo`, `ZeroThree`, `OneOne`, `OneTwo`, `OneThree`...
/// * A constant `LEASE_PERIODS_PER_SLOT` will count the number of lease periods.
/// * A constant `SLOT_RANGE_COUNT` will count the total number of enum variants.
/// * A function `as_pair` will return a tuple representation of the `SlotRange`.
/// * A function `intersects` will tell you if two slot ranges intersect with one another.
/// * A function `len` will tell you the length of occupying a `SlotRange`.
/// * A function `new_bounded` will generate a `SlotRange` from an input of the current lease
/// period, the starting lease period, and the final lease period.
#[macro_export]
macro_rules! generate_slot_range{
// Entry point
($( $x:ident ( $e:expr ) ),*) => {
$crate::generate_lease_period_per_slot!( $( $x )* );
$crate::generate_slot_range!(@inner
{ }
$( $x ( $e ) )*
);
};
// Does the magic...
(@inner
{ $( $parsed:ident ( $t1:expr, $t2:expr ) )* }
$current:ident ( $ce:expr )
$( $remaining:ident ( $re:expr ) )*
) => {
$crate::paste::paste! {
$crate::generate_slot_range!(@inner
{
$( $parsed ( $t1, $t2 ) )*
[< $current $current >] ( $ce, $ce )
$( [< $current $remaining >] ($ce, $re) )*
}
$( $remaining ( $re ) )*
);
}
};
(@inner
{ $( $parsed:ident ( $t1:expr, $t2:expr ) )* }
) => {
$crate::generate_slot_range_enum!(@inner $( $parsed )* );
$crate::generate_slot_range_count!( $( $parsed )* );
#[cfg(feature = "std")]
impl std::fmt::Debug for SlotRange {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
let p = self.as_pair();
write!(fmt, "[{}..{}]", p.0, p.1)
}
}
impl SlotRange {
pub const LEASE_PERIODS_PER_SLOT: usize = LEASE_PERIODS_PER_SLOT;
pub const SLOT_RANGE_COUNT: usize = SLOT_RANGE_COUNT;
$crate::generate_slot_range_as_pair!(@inner $( $parsed ( $t1, $t2 ) )* );
$crate::generate_slot_range_len!(@inner $( $parsed ( $t1, $t2 ) )* );
$crate::generate_slot_range_new_bounded!(@inner $( $parsed ( $t1, $t2 ) )* );
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! generate_slot_range_enum {
(@inner
$( $parsed:ident )*
) => {
/// A compactly represented sub-range from the series.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, $crate::Encode, $crate::Decode, $crate::N)]
#[repr(u8)]
pub enum SlotRange { $( $parsed ),* }
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! generate_slot_range_as_pair {
(@inner
$( $parsed:ident ( $t1:expr, $t2:expr ) )*
) => {
/// Return true if two `SlotRange` intersect in their lease periods.
pub fn intersects(&self, other: SlotRange) -> bool {
let a = self.as_pair();
let b = other.as_pair();
b.0 <= a.1 && a.0 <= b.1
// == !(b.0 > a.1 || a.0 > b.1)
}
/// Return a tuple representation of the `SlotRange`.
///
/// Example:`SlotRange::OneTwo.as_pair() == (1, 2)`
pub fn as_pair(&self) -> (u8, u8) {
match self {
$( SlotRange::$parsed => { ($t1, $t2) } )*
}
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! generate_slot_range_len {
// Use evaluated length in function.
(@inner
$( $parsed:ident ( $t1:expr, $t2:expr ) )*
) => {
/// Return the length of occupying a `SlotRange`.
///
/// Example:`SlotRange::OneTwo.len() == 2`
pub fn len(&self) -> usize {
match self {
// len (0, 2) = 2 - 0 + 1 = 3
$( SlotRange::$parsed => { ( $t2 - $t1 + 1) } )*
}
}
};
}
#[macro_export]
#[doc(hidden)]
macro_rules! generate_slot_range_new_bounded {
(@inner
$( $parsed:ident ( $t1:expr, $t2:expr ) )*
) => {
/// Construct a `SlotRange` from the current lease period, the first lease period of the range,
/// and the last lease period of the range.
///
/// For example: `SlotRange::new_bounded(1, 2, 3) == SlotRange::OneTwo`.
pub fn new_bounded<
Index: $crate::Add