use super::{super::prompt::Prompter, ProcessContext, TokenProcessor, parse_hex_values};
use crate::bms::ParseErrorWithRange;
use crate::bms::{
model::volume::VolumeObjects,
parse::{ParseWarning, Result},
prelude::*,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct VolumeProcessor;
impl TokenProcessor for VolumeProcessor {
type Output = VolumeObjects;
fn process<P: Prompter>(
&self,
ctx: &mut ProcessContext<'_, '_, P>,
) -> core::result::Result<Self::Output, ParseErrorWithRange> {
let mut objects = VolumeObjects::default();
ctx.all_tokens(|token, prompter| match token.content() {
Token::Header { name, args } => {
Ok(Self::on_header(name.as_ref(), args.as_ref(), &mut objects)
.map_or_else(|warn| vec![warn.into_wrapper(token)], |()| Vec::new()))
}
Token::Message {
track,
channel,
message,
} => Ok(Self::on_message(
*track,
*channel,
&message.as_ref().into_wrapper(token),
prompter,
&mut objects,
)
.unwrap_or_else(|warn| vec![warn.into_wrapper(token)])),
Token::NotACommand(_) => Ok(Vec::new()),
})?;
Ok(objects)
}
}
impl VolumeProcessor {
fn on_header(name: &str, args: &str, volume: &mut VolumeObjects) -> Result<()> {
if name.eq_ignore_ascii_case("VOLWAV") {
let volume_value = args
.parse()
.map_err(|_| ParseWarning::SyntaxError("expected integer".into()))?;
let volume_obj = Volume {
relative_percent: volume_value,
};
volume.volume = volume_obj;
}
Ok(())
}
fn on_message(
track: Track,
channel: Channel,
message: &SourceRangeMixin<&str>,
prompter: &impl Prompter,
objects: &mut VolumeObjects,
) -> Result<Vec<ParseWarningWithRange>> {
let mut warnings: Vec<ParseWarningWithRange> = Vec::new();
match channel {
Channel::BgmVolume => {
let (pairs, w) = parse_hex_values(track, message);
warnings.extend(w);
for (time, volume_value) in pairs {
objects.push_bgm_volume_change(
BgmVolumeObj {
time,
volume: volume_value,
},
prompter,
)?;
}
}
Channel::KeyVolume => {
let (pairs, w) = parse_hex_values(track, message);
warnings.extend(w);
for (time, volume_value) in pairs {
objects.push_key_volume_change(
KeyVolumeObj {
time,
volume: volume_value,
},
prompter,
)?;
}
}
_ => {}
}
Ok(warnings)
}
}