disco_quick/
reader.rs

1pub use crate::artist::ArtistsReader;
2pub use crate::label::LabelsReader;
3pub use crate::master::MastersReader;
4pub use crate::release::ReleasesReader;
5use flate2::read::GzDecoder;
6use quick_xml::events::Event;
7use quick_xml::Error as XmlError;
8use std::fmt;
9use std::fs::File;
10use std::io::{BufRead, BufReader, Error as IoError};
11use std::path::Path;
12use thiserror::Error;
13
14pub type XmlReader = quick_xml::Reader<Box<dyn BufRead>>;
15
16pub fn get_xml_reader(path: &Path) -> Result<XmlReader, IoError> {
17    let file = File::open(path)?;
18    let gz = GzDecoder::new(file);
19    let reader: Box<dyn BufRead> = if gz.header().is_some() {
20        Box::new(BufReader::new(gz))
21    } else {
22        let file = File::open(path)?;
23        Box::new(BufReader::new(file))
24    };
25    Ok(quick_xml::Reader::from_reader(reader))
26}
27
28pub enum DiscogsReader {
29    Artists(Box<ArtistsReader>),
30    Labels(Box<LabelsReader>),
31    Masters(Box<MastersReader>),
32    Releases(Box<ReleasesReader>),
33}
34
35impl DiscogsReader {
36    pub fn from_path(path: &Path) -> Result<DiscogsReader, ReaderError> {
37        let mut xml_reader = get_xml_reader(path)?;
38        let mut buf = Vec::with_capacity(4096);
39        let start_event = loop {
40            match xml_reader.read_event_into(&mut buf)? {
41                Event::Start(ev) => break ev,
42                Event::Eof => return Err(ReaderError::NoStartTag),
43                _ => continue,
44            }
45        };
46        let reader = match start_event.name().as_ref() {
47            b"artists" => DiscogsReader::Artists(Box::new(ArtistsReader::new(xml_reader, buf))),
48            b"labels" => DiscogsReader::Labels(Box::new(LabelsReader::new(xml_reader, buf))),
49            b"masters" => DiscogsReader::Masters(Box::new(MastersReader::new(xml_reader, buf))),
50            b"releases" => DiscogsReader::Releases(Box::new(ReleasesReader::new(xml_reader, buf))),
51            _ => {
52                return Err(ReaderError::InvalidStartTag);
53            }
54        };
55        Ok(reader)
56    }
57}
58
59#[derive(Error, Debug)]
60pub enum ReaderError {
61    #[error(transparent)]
62    IoError(#[from] IoError),
63    #[error(transparent)]
64    XmlError(#[from] XmlError),
65    #[error("No start tag present in file")]
66    NoStartTag,
67    #[error("Invalid start tag present in file")]
68    InvalidStartTag,
69}
70
71impl fmt::Display for DiscogsReader {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        let name = match &self {
74            DiscogsReader::Artists(_) => "artists",
75            DiscogsReader::Labels(_) => "labels",
76            DiscogsReader::Masters(_) => "masters",
77            DiscogsReader::Releases(_) => "releases",
78        };
79        write!(f, "{name}")
80    }
81}