use crate::bms::prelude::Bms;
#[cfg(feature = "bmson")]
use crate::bmson::prelude::Bmson;
use strict_num_extended::PositiveF64;
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BaseBpm(pub PositiveF64);
impl BaseBpm {
#[must_use]
pub const fn new(value: PositiveF64) -> Self {
Self(value)
}
#[must_use]
pub const fn value(&self) -> &PositiveF64 {
&self.0
}
#[must_use]
pub const fn as_f64(&self) -> f64 {
self.0.as_f64()
}
}
impl From<PositiveF64> for BaseBpm {
fn from(value: PositiveF64) -> Self {
Self(value)
}
}
impl From<BaseBpm> for PositiveF64 {
fn from(value: BaseBpm) -> Self {
value.0
}
}
impl AsRef<PositiveF64> for BaseBpm {
fn as_ref(&self) -> &PositiveF64 {
&self.0
}
}
impl Default for BaseBpm {
fn default() -> Self {
Self(PositiveF64::new_const(120.0))
}
}
pub trait BaseBpmGenerator<S> {
fn generate(&self, source: &S) -> Option<BaseBpm>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct StartBpmGenerator;
#[derive(Debug, Clone, Copy, Default)]
pub struct MinBpmGenerator;
#[derive(Debug, Clone, Copy, Default)]
pub struct MaxBpmGenerator;
#[derive(Debug, Clone, Copy)]
pub struct ManualBpmGenerator(pub BaseBpm);
impl AsRef<BaseBpm> for ManualBpmGenerator {
fn as_ref(&self) -> &BaseBpm {
&self.0
}
}
impl AsRef<PositiveF64> for ManualBpmGenerator {
fn as_ref(&self) -> &PositiveF64 {
&self.0.0
}
}
impl From<BaseBpm> for ManualBpmGenerator {
fn from(value: BaseBpm) -> Self {
Self(value)
}
}
impl From<ManualBpmGenerator> for BaseBpm {
fn from(value: ManualBpmGenerator) -> Self {
value.0
}
}
impl From<PositiveF64> for ManualBpmGenerator {
fn from(value: PositiveF64) -> Self {
Self(BaseBpm::new(value))
}
}
impl From<ManualBpmGenerator> for PositiveF64 {
fn from(value: ManualBpmGenerator) -> Self {
value.0.0
}
}
impl ManualBpmGenerator {
#[must_use]
pub const fn value(&self) -> &BaseBpm {
&self.0
}
#[must_use]
pub const fn into_value(self) -> BaseBpm {
self.0
}
}
impl BaseBpmGenerator<Bms> for StartBpmGenerator {
fn generate(&self, bms: &Bms) -> Option<BaseBpm> {
bms.bpm
.bpm
.as_ref()
.and_then(|bpm| bpm.value().as_ref().ok().copied())
.map(BaseBpm::new)
}
}
impl BaseBpmGenerator<Bms> for MinBpmGenerator {
fn generate(&self, bms: &Bms) -> Option<BaseBpm> {
bms.bpm
.bpm
.iter()
.filter_map(|bpm| bpm.value().as_ref().ok().copied())
.chain(bms.bpm.bpm_changes.values().map(|change| change.bpm))
.min()
.map(BaseBpm::new)
}
}
impl BaseBpmGenerator<Bms> for MaxBpmGenerator {
fn generate(&self, bms: &Bms) -> Option<BaseBpm> {
bms.bpm
.bpm
.iter()
.filter_map(|bpm| bpm.value().as_ref().ok().copied())
.chain(bms.bpm.bpm_changes.values().map(|change| change.bpm))
.max()
.map(BaseBpm::new)
}
}
impl BaseBpmGenerator<Bms> for ManualBpmGenerator {
fn generate(&self, _bms: &Bms) -> Option<BaseBpm> {
Some(self.0)
}
}
#[cfg(feature = "bmson")]
impl<'a> BaseBpmGenerator<Bmson<'a>> for StartBpmGenerator {
fn generate(&self, bmson: &Bmson<'a>) -> Option<BaseBpm> {
Some(BaseBpm::new(bmson.info.init_bpm))
}
}
#[cfg(feature = "bmson")]
impl<'a> BaseBpmGenerator<Bmson<'a>> for MinBpmGenerator {
fn generate(&self, bmson: &Bmson<'a>) -> Option<BaseBpm> {
std::iter::once(bmson.info.init_bpm)
.chain(bmson.bpm_events.iter().map(|ev| ev.bpm))
.min()
.map(BaseBpm::new)
}
}
#[cfg(feature = "bmson")]
impl<'a> BaseBpmGenerator<Bmson<'a>> for MaxBpmGenerator {
fn generate(&self, bmson: &Bmson<'a>) -> Option<BaseBpm> {
std::iter::once(bmson.info.init_bpm)
.chain(bmson.bpm_events.iter().map(|ev| ev.bpm))
.max()
.map(BaseBpm::new)
}
}
#[cfg(feature = "bmson")]
impl<'a> BaseBpmGenerator<Bmson<'a>> for ManualBpmGenerator {
fn generate(&self, _bmson: &Bmson<'a>) -> Option<BaseBpm> {
Some(self.0)
}
}