use super::{
builder::CueProbeBuilder,
remark::RemarkIter,
track::{TrackListProbe, Tracks},
};
use crate::{
core::{AlbumFile, Command, CueStr},
error::{CueLibError, ParseError, ParseErrorKind},
internal::{lexer::CueLexer, tokenizer::Tokenizer},
};
pub struct CuesheetProbe<'a> {
pub(super) catalog: Option<CueStr<'a>>,
pub(super) cdtextfile: Option<CueStr<'a>>,
pub(super) file: Option<AlbumFile<'a>>,
pub(super) performer: Option<CueStr<'a>>,
pub(super) songwriter: Option<CueStr<'a>>,
pub(super) title: Option<CueStr<'a>>,
pub(super) tracks_probe: TrackListProbe<'a>,
pub(super) album_buffer: &'a str,
}
impl<'a> CuesheetProbe<'a> {
pub fn new(cuesheet: &'a str) -> Result<Self, CueLibError> {
let tokenizer = Tokenizer::new(cuesheet);
let mut lexer = CueLexer::new(tokenizer);
let mut builder = CueProbeBuilder::new();
let mut album_buffer_end = 0;
'PARSER: while let Some(command) = lexer.next_command()? {
match command {
Command::Catalog { value } => builder.set_catalog(value),
Command::CdTextFile { value } => builder.set_cdtextfile(value),
Command::File { value } => builder.set_file(value),
Command::Title { value } => builder.set_title(value),
Command::Performer { value } => builder.set_performer(value),
Command::SongWriter { value } => builder.set_songwriter(value),
Command::Remark { .. } => Ok(()),
Command::Track { value } => {
builder
.set_tracks_probe(TrackListProbe::new(lexer.snapshot(), value))
.map_err(|kind| ParseError::new_with_position(kind, lexer.position()))?;
break 'PARSER;
}
_ => Err(ParseErrorKind::InvalidCommandUsage),
}
.map_err(|kind| ParseError::new_with_line(kind, lexer.position().line))?;
album_buffer_end = lexer.cursor_position();
}
let probe = builder
.build(&cuesheet[0..album_buffer_end])
.map_err(|kind| ParseError::new_with_position(kind, lexer.position()))?;
Ok(probe)
}
pub fn verify(cuesheet: &str) -> Result<(), CueLibError> {
let probe = CuesheetProbe::new(cuesheet)?;
let mut tracks = probe.tracks();
while let Some(track) = tracks.next_track()? {
let mut indexes = track.sub_indexes();
while let Some(_) = indexes.next_index()? {
continue;
}
}
Ok(())
}
#[inline]
pub const fn album_title(&self) -> Option<CueStr<'a>> {
self.title
}
#[inline]
pub const fn performer(&self) -> Option<CueStr<'a>> {
self.performer
}
#[inline]
pub const fn catalog(&self) -> Option<CueStr<'a>> {
self.catalog
}
#[inline]
pub const fn songwriter(&self) -> Option<CueStr<'a>> {
self.songwriter
}
#[inline]
pub const fn cdtextfile(&self) -> Option<CueStr<'a>> {
self.cdtextfile
}
#[inline]
pub const fn file_info(&self) -> Option<AlbumFile<'a>> {
self.file
}
#[inline]
pub const fn tracks(&self) -> Tracks<'a> {
self.tracks_probe.iter()
}
#[inline]
pub const fn remarks(&self) -> RemarkIter<'a> {
RemarkIter::new(self.album_buffer)
}
#[cfg(feature = "metadata")]
#[inline]
pub fn vorbis_comments(&self) -> crate::probe::vorbis_remark::VorbisRemarkIter<'a> {
self.remarks().into()
}
}