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