osu_db/
collection.rs

1//! Parsing for the `collection.db` file, containing all user collections.
2
3use std::convert::identity;
4
5use crate::prelude::*;
6
7/// A structure representing the `collection.db` file.
8/// Contains a list of collections.
9#[cfg_attr(feature = "ser-de", derive(Serialize, Deserialize))]
10#[derive(Clone, Debug, PartialEq)]
11pub struct CollectionList {
12    pub version: u32,
13    pub collections: Vec<Collection>,
14}
15impl CollectionList {
16    /// Read a collection list from its raw bytes.
17    pub fn from_bytes(bytes: &[u8]) -> Result<CollectionList, Error> {
18        Ok(collections(bytes).map(|(_rem, collections)| collections)?)
19    }
20
21    /// Read a collection list from a `collection.db` file.
22    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<CollectionList, Error> {
23        Self::from_bytes(&fs::read(path)?)
24    }
25
26    /// Writes the collection list to an arbitrary writer.
27    pub fn to_writer<W: Write>(&self, mut out: W) -> io::Result<()> {
28        self.wr(&mut out)
29    }
30
31    /// Similar to `to_writer` but writes the collection database to a file (ie. `collection.db`).
32    pub fn to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
33        self.to_writer(BufWriter::new(File::create(path)?))
34    }
35}
36
37/// A single collection.
38/// Contains a list of beatmap hashes that fall within this collection.
39#[cfg_attr(feature = "ser-de", derive(Serialize, Deserialize))]
40#[derive(Clone, Debug, PartialEq)]
41pub struct Collection {
42    pub name: Option<String>,
43    pub beatmap_hashes: Vec<Option<String>>,
44}
45
46fn collections(bytes: &[u8]) -> IResult<&[u8], CollectionList> {
47    let (rem, version) = int(bytes)?;
48    let (rem, collections) = length_count(map(int, identity), collection)(rem)?;
49
50    let list = CollectionList {
51        version,
52        collections,
53    };
54
55    Ok((rem, list))
56}
57
58fn collection(bytes: &[u8]) -> IResult<&[u8], Collection> {
59    let (rem, name) = opt_string(bytes)?;
60    let (rem, beatmap_hashes) = length_count(map(int, identity), opt_string)(rem)?;
61
62    let collection = Collection {
63        name,
64        beatmap_hashes,
65    };
66
67    Ok((rem, collection))
68}
69
70writer!(CollectionList [this,out] {
71    this.version.wr(out)?;
72    PrefixedList(&this.collections).wr(out)?;
73});
74
75writer!(Collection [this,out] {
76    this.name.wr(out)?;
77    PrefixedList(&this.beatmap_hashes).wr(out)?;
78});