1 //! Package collections
2 
3 use crate::error::{Error, ErrorKind};
4 use serde::{de, ser, Deserialize, Serialize};
5 use std::{fmt, str::FromStr};
6 
7 /// Collections of packages (`crates` vs `rust`).
8 ///
9 /// Advisories are either filed against crates published to https://crates.io
10 /// or packages provided by the Rust language itself (e.g. `std`, `rustdoc`)
11 #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
12 pub enum Collection {
13     /// Crates published through crates.io
14     Crates,
15 
16     /// Rust core vulnerabilities
17     Rust,
18 }
19 
20 impl Collection {
21     /// Get all collections as a slice
all() -> &'static [Self]22     pub fn all() -> &'static [Self] {
23         &[Collection::Crates, Collection::Rust]
24     }
25 
26     /// Get a `str` representing the kind of package
as_str(&self) -> &str27     pub fn as_str(&self) -> &str {
28         match self {
29             Collection::Crates => "crates",
30             Collection::Rust => "rust",
31         }
32     }
33 }
34 
35 impl fmt::Display for Collection {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result36     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37         write!(f, "{}", self.as_str())
38     }
39 }
40 
41 impl FromStr for Collection {
42     type Err = Error;
43 
from_str(s: &str) -> Result<Self, Error>44     fn from_str(s: &str) -> Result<Self, Error> {
45         Ok(match s {
46             "crates" => Collection::Crates,
47             "rust" => Collection::Rust,
48             other => fail!(ErrorKind::Parse, "invalid package type: {}", other),
49         })
50     }
51 }
52 
53 impl<'de> Deserialize<'de> for Collection {
deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error>54     fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
55         use de::Error;
56         let string = String::deserialize(deserializer)?;
57         string.parse().map_err(D::Error::custom)
58     }
59 }
60 
61 impl Serialize for Collection {
serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error>62     fn serialize<S: ser::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63         self.to_string().serialize(serializer)
64     }
65 }
66 
67 #[cfg(test)]
68 mod tests {
69     use super::Collection;
70 
71     #[test]
parse_crate()72     fn parse_crate() {
73         let crate_kind = "crates".parse::<Collection>().unwrap();
74         assert_eq!(Collection::Crates, crate_kind);
75         assert_eq!("crates", crate_kind.as_str());
76     }
77 
78     #[test]
parse_rust()79     fn parse_rust() {
80         let rust_kind = "rust".parse::<Collection>().unwrap();
81         assert_eq!(Collection::Rust, rust_kind);
82         assert_eq!("rust", rust_kind.as_str());
83     }
84 
85     #[test]
parse_other()86     fn parse_other() {
87         assert!("foobar".parse::<Collection>().is_err());
88     }
89 }
90