diff --git a/src/versions.rs b/src/versions.rs index 1a027ac..d5ce579 100644 --- a/src/versions.rs +++ b/src/versions.rs @@ -3,7 +3,7 @@ use crate::crates::CrateId; use crate::users::UserId; use chrono::{DateTime, Utc}; -use semver::Version; +use semver::{BuildMetadata, Op, Version, VersionReq}; use serde::de::{Deserializer, Unexpected, Visitor}; use serde_derive::{Deserialize, Serialize}; use std::borrow::Borrow; @@ -11,6 +11,7 @@ use std::cmp::Ordering; use std::collections::BTreeMap as Map; use std::fmt; use std::hash::{Hash, Hasher}; +use std::str::FromStr; /// Primary key of **versions.csv**. #[derive(Serialize, Deserialize, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug)] @@ -44,6 +45,8 @@ pub struct Row { pub checksum: Option<[u8; 32]>, #[serde(default)] pub links: Option, + #[serde(deserialize_with = "rust_version")] + pub rust_version: Option, } impl Ord for Row { @@ -185,3 +188,58 @@ where { deserializer.deserialize_str(ChecksumVisitor) } + +struct RustVersionVisitor; + +impl<'de> Visitor<'de> for RustVersionVisitor { + type Value = Option; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a compiler version number") + } + + fn visit_str(self, string: &str) -> Result + where + E: serde::de::Error, + { + match VersionReq::from_str(string) { + Ok(mut req) if req.comparators.len() == 1 => { + let req = req.comparators.pop().unwrap(); + if req.op == Op::Caret { + Ok(Some(Version { + major: req.major, + minor: req.minor.unwrap_or(0), + patch: req.patch.unwrap_or(0), + pre: req.pre, + build: BuildMetadata::EMPTY, + })) + } else { + Ok(None) + } + } + Ok(_) => Ok(None), + Err(parse_error) => Err(E::custom(parse_error)), + } + } + + fn visit_some(self, deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_str(self) + } + + fn visit_none(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } +} + +fn rust_version<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + deserializer.deserialize_option(RustVersionVisitor) +}