use std::{
convert::TryFrom,
fmt::{Debug, Display, Formatter},
ops::{Add, Sub},
};
#[cfg(feature = "serde")]
use serde_crate::{
de::{Error, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use crate::{RowBuf, SameStageVec};
#[allow(unused_imports)]
use crate::{Bell, Method, Row};
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(transparent)]
pub struct Stage(u8);
impl Stage {
#[track_caller]
pub fn new(num_bells: u8) -> Stage {
Self::try_from(num_bells).expect("Can't create a `Stage` of zero bells")
}
#[inline(always)]
pub fn num_bells(self) -> usize {
self.0 as usize
}
#[inline(always)]
pub fn num_bells_u8(self) -> u8 {
self.0
}
pub fn tenor(self) -> Bell {
Bell::tenor(self)
}
pub fn bells(self) -> impl DoubleEndedIterator<Item = Bell> {
(0..self.num_bells_u8()).map(Bell::from_index)
}
pub fn contains(self, bell: Bell) -> bool {
bell.number() <= self.num_bells_u8()
}
#[inline(always)]
pub fn is_even(self) -> bool {
self.num_bells() % 2 == 0
}
pub fn from_lower_case_name(name: &str) -> Option<Stage> {
Some(match name {
"one" => Stage::ONE,
"two" => Stage::TWO,
"singles" => Stage::SINGLES,
"minimus" => Stage::MINIMUS,
"doubles" => Stage::DOUBLES,
"minor" => Stage::MINOR,
"triples" => Stage::TRIPLES,
"major" => Stage::MAJOR,
"caters" => Stage::CATERS,
"royal" => Stage::ROYAL,
"cinques" => Stage::CINQUES,
"maximus" => Stage::MAXIMUS,
"sextuples" => Stage::SEXTUPLES,
"fourteen" => Stage::FOURTEEN,
"septuples" => Stage::SEPTUPLES,
"sixteen" => Stage::SIXTEEN,
"octuples" => Stage(17),
"eighteen" => Stage(18),
"nonuples" => Stage(19),
"twenty" => Stage(20),
"decuples" => Stage(21),
"twenty-two" => Stage(22),
_ => return None,
})
}
pub fn name(self) -> Option<&'static str> {
Some(match self.0 {
1 => "One",
2 => "Two",
3 => "Singles",
4 => "Minimus",
5 => "Doubles",
6 => "Minor",
7 => "Triples",
8 => "Major",
9 => "Caters",
10 => "Royal",
11 => "Cinques",
12 => "Maximus",
13 => "Sextuples",
14 => "Fourteen",
15 => "Septuples",
16 => "Sixteen",
17 => "Octuples",
18 => "Eighteen",
19 => "Nonuples",
20 => "Twenty",
21 => "Decuples",
22 => "Twenty-two",
_ => return None,
})
}
pub fn checked_add(self, rhs: u8) -> Option<Self> {
self.0.checked_add(rhs).map(Self)
}
pub fn checked_sub(self, rhs: u8) -> Option<Self> {
let new_num_bells = self.0.checked_sub(rhs)?;
(new_num_bells > 0).then_some(Self(new_num_bells))
}
pub fn extent(self) -> SameStageVec {
let self_minus_one = match self.checked_sub(1) {
Some(self_minus_one) => self_minus_one,
None => return SameStageVec::from_row_buf(RowBuf::rounds(self)),
};
let mut new_extent_bell_vec = Vec::new();
for prev_row in &self_minus_one.extent() {
for split_idx in 0..self.num_bells() {
let (bells_before, bells_after) = prev_row.slice().split_at(split_idx);
new_extent_bell_vec.extend_from_slice(bells_before);
new_extent_bell_vec.push(self.tenor());
new_extent_bell_vec.extend_from_slice(bells_after)
}
}
unsafe { SameStageVec::from_bell_vec_unchecked(new_extent_bell_vec, self) }
}
}
impl Stage {
pub const ONE: Stage = Stage(1);
pub const TWO: Stage = Stage(2);
pub const SINGLES: Stage = Stage(3);
pub const MINIMUS: Stage = Stage(4);
pub const DOUBLES: Stage = Stage(5);
pub const MINOR: Stage = Stage(6);
pub const TRIPLES: Stage = Stage(7);
pub const MAJOR: Stage = Stage(8);
pub const CATERS: Stage = Stage(9);
pub const ROYAL: Stage = Stage(10);
pub const CINQUES: Stage = Stage(11);
pub const MAXIMUS: Stage = Stage(12);
pub const SEXTUPLES: Stage = Stage(13);
pub const FOURTEEN: Stage = Stage(14);
pub const SEPTUPLES: Stage = Stage(15);
pub const SIXTEEN: Stage = Stage(16);
}
impl Debug for Stage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let const_name = match self.0 {
0 => unreachable!(),
1 => "ONE",
2 => "TWO",
3 => "SINGLES",
4 => "MINIMUS",
5 => "DOUBLES",
6 => "MINOR",
7 => "TRIPLES",
8 => "MAJOR",
9 => "CATERS",
10 => "ROYAL",
11 => "CINQUES",
12 => "MAXIMUS",
13 => "SEXTUPLES",
14 => "FOURTEEN",
15 => "SEPTUPLES",
16 => "SIXTEEN",
num_bells => return write!(f, "Stage({})", num_bells),
};
write!(f, "Stage::{}", const_name)
}
}
impl Display for Stage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self.name() {
Some(n) => write!(f, "{}", n),
None => write!(f, "{} bells", self.0),
}
}
}
impl TryFrom<u8> for Stage {
type Error = ZeroStageError;
fn try_from(num_bells: u8) -> Result<Self, Self::Error> {
match num_bells {
0 => Err(ZeroStageError),
_ => Ok(Stage(num_bells)),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct ZeroStageError;
impl Display for ZeroStageError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Can't create a `Stage` of zero bells")
}
}
impl Add<u8> for Stage {
type Output = Stage;
fn add(self, rhs: u8) -> Self::Output {
self.checked_add(rhs)
.expect("`u8` overflowed whilst adding to a `Stage`")
}
}
impl Sub<u8> for Stage {
type Output = Stage;
fn sub(self, rhs: u8) -> Self::Output {
self.checked_sub(rhs)
.expect("`u8` underflowed whilst adding to a `Stage`")
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct IncompatibleStages {
pub(crate) lhs_stage: Stage,
pub(crate) rhs_stage: Stage,
}
impl IncompatibleStages {
pub fn test_err(lhs_stage: Stage, rhs_stage: Stage) -> Result<(), Self> {
if lhs_stage == rhs_stage {
Ok(())
} else {
Err(IncompatibleStages {
lhs_stage,
rhs_stage,
})
}
}
pub fn test_err_opt(opt: &mut Option<Stage>, stage: Stage) -> Result<(), Self> {
match opt {
None => {
*opt = Some(stage);
Ok(())
}
Some(s) => Self::test_err(*s, stage),
}
}
}
impl Display for IncompatibleStages {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Incompatible stages: {} (lhs), {} (rhs)",
self.lhs_stage, self.rhs_stage
)
}
}
impl std::error::Error for IncompatibleStages {}
#[cfg(feature = "serde")]
impl Serialize for Stage {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u64(self.0 as u64)
}
}
#[cfg(feature = "serde")]
struct StageVisitor;
#[cfg(feature = "serde")]
impl<'de> Visitor<'de> for StageVisitor {
type Value = Stage;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a non-negative integer, or a stage name")
}
fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage_u(v as u64)
}
fn visit_i16<E>(self, v: i16) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage(v as i64)
}
fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage_u(v as u64)
}
fn visit_i32<E>(self, v: i32) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage(v as i64)
}
fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage_u(v as u64)
}
fn visit_i64<E>(self, v: i64) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage(v)
}
fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
where
E: Error,
{
try_parse_stage_u(v)
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: Error,
{
let lower_str = v.to_lowercase();
Stage::from_lower_case_name(&lower_str)
.ok_or_else(|| E::custom(format!("'{}' is not a stage name", v)))
}
}
#[cfg(feature = "serde")]
#[inline(always)]
fn try_parse_stage_u<E: Error>(val: u64) -> Result<Stage, E> {
let val_u8: u8 = val
.try_into()
.map_err(|_| E::custom(format!("stage is too large: {}", val)))?;
Stage::try_from(val_u8).map_err(|_| E::custom("Can't have a Stage of zero bells"))
}
#[cfg(feature = "serde")]
#[inline(always)]
fn try_parse_stage<E: Error>(val: i64) -> Result<Stage, E> {
try_parse_stage_u(
val.try_into()
.map_err(|_| E::custom(format!("negative stage: {}", val)))?,
)
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for Stage {
fn deserialize<D>(deserializer: D) -> Result<Stage, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_u64(StageVisitor)
}
}
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
#[cfg(test)]
impl Arbitrary for Stage {
fn arbitrary(gen: &mut Gen) -> Self {
let num_bells = u8::arbitrary(gen);
let num_bells = num_bells.max(1);
Self::new(num_bells)
}
}
#[cfg(test)]
mod tests {
use itertools::Itertools;
use crate::{Row, RowBuf};
use super::Stage;
#[test]
#[rustfmt::skip]
fn extent() {
#[track_caller]
fn check(stage: Stage, exp_extent: &[&str]) {
let mut extent = stage.extent().iter().map(Row::to_owned).collect_vec();
let mut expected_extent = exp_extent.iter().map(|s| RowBuf::parse(s).unwrap()).collect_vec();
extent.sort();
expected_extent.sort();
assert_eq!(extent, expected_extent);
}
check(Stage::ONE, &["1"]);
check(Stage::TWO, &["12", "21"]);
check(Stage::SINGLES, &["123", "132", "213", "231", "312", "321"]);
check(
Stage::MINIMUS,
&[
"1234", "1243", "1324", "1342", "1423", "1432",
"2134", "2143", "2314", "2341", "2413", "2431",
"3124", "3142", "3214", "3241", "3412", "3421",
"4123", "4132", "4213", "4231", "4312", "4321",
]
);
}
}