lotus_lib/package/
package_collection.rs

1use std::io;
2use std::path::PathBuf;
3
4use crate::cache_pair::CachePair;
5use crate::package::package::Package;
6
7/// A collection of packages.
8pub struct PackageCollection<T: CachePair> {
9    directory: PathBuf,
10    is_post_ensmallening: bool,
11    packages: Vec<Package<T>>,
12}
13
14impl<T: CachePair> PackageCollection<T> {
15    /// Creates a new package collection from the specified directory.
16    ///
17    /// # Errors
18    ///
19    /// Returns an error if the directory does not exist or if the directory cannot be read.
20    pub fn new<P>(directory: P, is_post_ensmallening: bool) -> Result<Self, io::Error>
21    where
22        P: Into<PathBuf>,
23    {
24        let directory = directory.into();
25
26        let mut packages = Vec::new();
27        for entry in std::fs::read_dir(&directory).unwrap() {
28            let entry = entry?;
29            let file_name = entry.file_name().into_string().unwrap();
30
31            // Check if the file has enough characters to be a package 7 characters counts for the
32            // shortest possible package name of 1 character : H.1.toc
33            if file_name.len() < 7 {
34                continue;
35            }
36
37            // Check if the file is a valid header .toc file
38            if !file_name.starts_with("H.") || !file_name.ends_with(".toc") {
39                continue;
40            }
41
42            let package_name = file_name[2..file_name.len() - 4].to_string();
43
44            let package = Package::<T>::new(&directory, package_name, is_post_ensmallening);
45            packages.push(package);
46        }
47
48        Ok(Self {
49            directory,
50            is_post_ensmallening,
51            packages,
52        })
53    }
54
55    /// Returns whether the package is post-ensmallening.
56    ///
57    /// This is used to determine how to decompress the data from before "The Great Ensmallening"
58    /// update of Warframe.
59    pub fn is_post_ensmallening(&self) -> bool {
60        self.is_post_ensmallening
61    }
62
63    /// Returns a reference to the package with the specified name if found.
64    pub fn borrow(&self, package_name: &str) -> Option<&Package<T>> {
65        self.packages
66            .iter()
67            .find(|package| package.name() == package_name)
68    }
69
70    /// Returns a mutable reference to the package with the specified name if found.
71    pub fn borrow_mut(&mut self, package_name: &str) -> Option<&mut Package<T>> {
72        self.packages
73            .iter_mut()
74            .find(|package| package.name() == package_name)
75    }
76
77    /// Returns the package with the specified name if found.
78    pub fn take(&mut self, package_name: &str) -> Option<Package<T>> {
79        let index = self
80            .packages
81            .iter()
82            .position(|package| package.name() == package_name)?;
83        Some(self.packages.remove(index))
84    }
85
86    /// Returns the directory of the package collection.
87    pub fn directory(&self) -> &PathBuf {
88        &self.directory
89    }
90
91    /// Returns the packages within the package collection.
92    pub fn packages(&self) -> &Vec<Package<T>> {
93        &self.packages
94    }
95}