use std::fmt;
use super::{Duration, Fraction};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum FullMeasureRest {
False,
True,
#[default]
Auto,
Always,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Rest {
duration: Duration,
offset: Fraction,
hidden: bool,
full_measure: FullMeasureRest,
step_shift: i8,
}
impl Rest {
pub fn new(duration: Duration) -> Self {
Self {
duration,
offset: Fraction::new(0, 1),
hidden: false,
full_measure: FullMeasureRest::Auto,
step_shift: 0,
}
}
pub fn whole() -> Self {
Self::new(Duration::whole())
}
pub fn half() -> Self {
Self::new(Duration::half())
}
pub fn quarter() -> Self {
Self::new(Duration::quarter())
}
pub fn eighth() -> Self {
Self::new(Duration::eighth())
}
pub fn sixteenth() -> Self {
Self::new(Duration::sixteenth())
}
pub fn full_measure(duration: Duration) -> Self {
let mut rest = Self::new(duration);
rest.full_measure = FullMeasureRest::True;
rest
}
pub fn duration(&self) -> &Duration {
&self.duration
}
pub fn duration_mut(&mut self) -> &mut Duration {
&mut self.duration
}
pub fn set_duration(&mut self, duration: Duration) {
self.duration = duration;
}
pub fn offset(&self) -> Fraction {
self.offset
}
pub fn set_offset(&mut self, offset: Fraction) {
self.offset = offset;
}
pub fn quarter_length(&self) -> Fraction {
self.duration.quarter_length()
}
pub fn is_hidden(&self) -> bool {
self.hidden
}
pub fn set_hidden(&mut self, hidden: bool) {
self.hidden = hidden;
}
pub fn is_full_measure(&self) -> bool {
matches!(self.full_measure, FullMeasureRest::True | FullMeasureRest::Always)
}
pub fn set_full_measure(&mut self, full_measure: bool) {
self.full_measure = if full_measure {
FullMeasureRest::True
} else {
FullMeasureRest::False
};
}
pub fn full_measure_mode(&self) -> FullMeasureRest {
self.full_measure
}
pub fn set_full_measure_mode(&mut self, mode: FullMeasureRest) {
self.full_measure = mode;
}
pub fn is_full_measure_in_context(&self, measure_duration: Fraction) -> bool {
match self.full_measure {
FullMeasureRest::True | FullMeasureRest::Always => true,
FullMeasureRest::False => false,
FullMeasureRest::Auto => self.quarter_length() == measure_duration,
}
}
pub fn step_shift(&self) -> i8 {
self.step_shift
}
pub fn set_step_shift(&mut self, shift: i8) {
self.step_shift = shift;
}
pub fn augment_or_diminish(&self, scalar: Fraction) -> Rest {
let mut scaled = self.clone();
scaled.duration = self.duration.augment_or_diminish(scalar);
scaled
}
}
impl Default for Rest {
fn default() -> Self {
Self::quarter()
}
}
impl fmt::Display for Rest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Rest {}", self.duration)
}
}
impl From<Duration> for Rest {
fn from(duration: Duration) -> Self {
Self::new(duration)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rest_creation() {
let rest = Rest::quarter();
assert_eq!(rest.quarter_length(), Fraction::new(1, 1));
}
#[test]
fn test_rest_full_measure() {
let rest = Rest::full_measure(Duration::whole());
assert!(rest.is_full_measure());
assert_eq!(rest.quarter_length(), Fraction::new(4, 1));
}
#[test]
fn test_rest_step_shift() {
let mut rest = Rest::quarter();
assert_eq!(rest.step_shift(), 0);
rest.set_step_shift(2);
assert_eq!(rest.step_shift(), 2);
}
#[test]
fn test_rest_full_measure_default_is_auto() {
let rest = Rest::whole();
assert_eq!(rest.full_measure_mode(), FullMeasureRest::Auto);
assert!(!rest.is_full_measure());
assert!(rest.is_full_measure_in_context(Fraction::new(4, 1)));
assert!(!rest.is_full_measure_in_context(Fraction::new(3, 1)));
}
#[test]
fn test_rest_full_measure_explicit_states() {
let mut rest = Rest::quarter();
rest.set_full_measure_mode(FullMeasureRest::True);
assert!(rest.is_full_measure());
assert!(rest.is_full_measure_in_context(Fraction::new(3, 1)));
rest.set_full_measure_mode(FullMeasureRest::False);
assert!(!rest.is_full_measure());
assert!(!rest.is_full_measure_in_context(Fraction::new(1, 1)));
rest.set_full_measure_mode(FullMeasureRest::Always);
assert!(rest.is_full_measure());
assert!(rest.is_full_measure_in_context(Fraction::new(100, 1))); }
#[test]
fn test_rest_augment() {
let rest = Rest::quarter();
let augmented = rest.augment_or_diminish(Fraction::new(2, 1));
assert_eq!(augmented.quarter_length(), Fraction::new(2, 1));
}
}