plux_rs/
bundle.rs

1use std::{cmp::Ordering, ffi::OsStr, fmt::Display};
2
3use semver::Version;
4use serde::{Deserialize, Serialize};
5
6use crate::{utils::BundleFromError, Depend, Info, Plugin};
7
8#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
9pub struct Bundle {
10    pub id: String,
11    pub version: Version,
12    pub format: String,
13}
14
15impl Bundle {
16    pub fn from_filename<S>(filename: &S) -> Result<Self, BundleFromError>
17    where
18        S: AsRef<OsStr> + ?Sized,
19    {
20        let mut path = filename
21            .as_ref()
22            .to_str()
23            .ok_or(BundleFromError::OsStrToStrFailed)?
24            .to_string();
25
26        let format = path
27            .drain(path.rfind('.').ok_or(BundleFromError::FormatFailed)? + 1..)
28            .collect::<String>();
29        let version = path
30            .drain(path.rfind("-v").ok_or(BundleFromError::VersionFailed)? + 2..path.len() - 1)
31            .collect::<String>();
32        let id = path
33            .drain(..path.rfind("-v").ok_or(BundleFromError::IDFailed)?)
34            .collect::<String>();
35
36        if format.is_empty() {
37            return Err(BundleFromError::FormatFailed);
38        }
39        if version.is_empty() {
40            return Err(BundleFromError::VersionFailed);
41        }
42        if id.is_empty() {
43            return Err(BundleFromError::IDFailed);
44        }
45
46        Ok(Self {
47            id,
48            version: Version::parse(version.as_str())?,
49            format,
50        })
51    }
52}
53
54impl<ID: AsRef<str>> PartialEq<(ID, &Version)> for Bundle {
55    fn eq(&self, (id, version): &(ID, &Version)) -> bool {
56        self.id == *id.as_ref() && self.version == **version
57    }
58}
59
60impl<O: Send + Sync, I: Info> PartialEq<Plugin<'_, O, I>> for Bundle {
61    fn eq(&self, other: &Plugin<'_, O, I>) -> bool {
62        self.id == other.info.bundle.id && self.version == other.info.bundle.version
63    }
64}
65
66impl PartialEq<Depend> for Bundle {
67    fn eq(&self, Depend { id: name, version }: &Depend) -> bool {
68        self.id == *name && version.matches(&self.version)
69    }
70}
71
72impl<ID: AsRef<str>> PartialOrd<(ID, &Version)> for Bundle {
73    fn partial_cmp(&self, (id, version): &(ID, &Version)) -> Option<Ordering> {
74        match self.id == *id.as_ref() {
75            true => self.version.partial_cmp(*version),
76            false => None,
77        }
78    }
79}
80
81impl<O: Send + Sync, I: Info> PartialOrd<Plugin<'_, O, I>> for Bundle {
82    fn partial_cmp(&self, other: &Plugin<'_, O, I>) -> Option<Ordering> {
83        match self.id == other.info.bundle.id {
84            true => self.version.partial_cmp(&other.info.bundle.version),
85            false => None,
86        }
87    }
88}
89
90impl Display for Bundle {
91    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
92        write!(f, "{}-v{}.{}", self.id, self.version, self.format)
93    }
94}