Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

gleam / compiler-core / src / requirement.rs
4.9 kB 183 lines
1use std::fmt; 2use std::str::FromStr; 3 4use crate::Error; 5use crate::error::Result; 6use crate::io::make_relative; 7use camino::{Utf8Path, Utf8PathBuf}; 8use ecow::EcoString; 9use hexpm::version::Range; 10use serde::Deserialize; 11use serde::de::{self, Deserializer, MapAccess, Visitor}; 12use serde::ser::{Serialize, SerializeMap, Serializer}; 13 14#[derive(Deserialize, Debug, PartialEq, Eq, Clone)] 15#[serde(untagged, remote = "Self", deny_unknown_fields)] 16pub enum Requirement { 17 Hex { 18 #[serde(deserialize_with = "deserialise_range")] 19 version: Range, 20 }, 21 22 Path { 23 path: Utf8PathBuf, 24 }, 25 26 Git { 27 git: EcoString, 28 #[serde(rename = "ref")] 29 ref_: EcoString, 30 }, 31} 32 33impl Requirement { 34 pub fn hex(range: &str) -> Result<Requirement> { 35 Ok(Requirement::Hex { 36 version: Range::new(range.to_string()).map_err(|e| Error::InvalidVersionFormat { 37 input: range.to_string(), 38 error: e.to_string(), 39 })?, 40 }) 41 } 42 43 pub fn path(path: &str) -> Requirement { 44 Requirement::Path { path: path.into() } 45 } 46 47 pub fn git(url: &str, ref_: &str) -> Requirement { 48 Requirement::Git { 49 git: url.into(), 50 ref_: ref_.into(), 51 } 52 } 53 54 pub fn to_toml(&self, root_path: &Utf8Path) -> String { 55 match self { 56 Requirement::Hex { version: range } => { 57 format!(r#"{{ version = "{range}" }}"#) 58 } 59 Requirement::Path { path } => { 60 format!( 61 r#"{{ path = "{}" }}"#, 62 make_relative(root_path, path).as_str().replace('\\', "/") 63 ) 64 } 65 Requirement::Git { git: url, ref_ } => { 66 format!(r#"{{ git = "{url}", ref = "{ref_}" }}"#) 67 } 68 } 69 } 70} 71 72// Serialization 73 74impl Serialize for Requirement { 75 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 76 where 77 S: Serializer, 78 { 79 let mut map = serializer.serialize_map(Some(1))?; 80 match self { 81 Requirement::Hex { version: range } => map.serialize_entry("version", range)?, 82 Requirement::Path { path } => map.serialize_entry("path", path)?, 83 Requirement::Git { git: url, ref_ } => { 84 map.serialize_entry("git", url)?; 85 map.serialize_entry("ref", ref_)?; 86 } 87 } 88 map.end() 89 } 90} 91 92// Deserialization 93 94fn deserialise_range<'de, D>(deserializer: D) -> Result<Range, D::Error> 95where 96 D: Deserializer<'de>, 97{ 98 let version = String::deserialize(deserializer)?; 99 Range::new(version).map_err(de::Error::custom) 100} 101 102#[derive(Debug, Copy, Clone)] 103pub struct Void; 104 105impl FromStr for Requirement { 106 type Err = Error; 107 108 fn from_str(s: &str) -> Result<Self, Self::Err> { 109 Requirement::hex(s) 110 } 111} 112 113struct RequirementVisitor; 114 115impl<'de> Visitor<'de> for RequirementVisitor { 116 type Value = Requirement; 117 118 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { 119 formatter.write_str("string or map") 120 } 121 122 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> 123 where 124 E: de::Error, 125 { 126 match value.parse::<Requirement>() { 127 Ok(value) => Ok(value), 128 Err(error) => Err(de::Error::custom(error)), 129 } 130 } 131 132 fn visit_map<M>(self, visitor: M) -> Result<Self::Value, M::Error> 133 where 134 M: MapAccess<'de>, 135 { 136 Requirement::deserialize(de::value::MapAccessDeserializer::new(visitor)) 137 } 138} 139 140impl<'de> Deserialize<'de> for Requirement { 141 fn deserialize<D>(deserializer: D) -> Result<Requirement, D::Error> 142 where 143 D: Deserializer<'de>, 144 { 145 deserializer.deserialize_any(RequirementVisitor) 146 } 147} 148 149#[cfg(test)] 150mod tests { 151 152 use super::*; 153 use std::collections::HashMap; 154 155 #[test] 156 fn read_requirement() { 157 let toml = r#" 158 short = "~> 0.5" 159 hex = { version = "~> 1.0.0" } 160 local = { path = "/path/to/package" } 161 github = { git = "https://github.com/gleam-lang/otp.git", ref = "4d34935" } 162 "#; 163 let deps: HashMap<String, Requirement> = toml::from_str(toml).unwrap(); 164 assert_eq!(deps["short"], Requirement::hex("~> 0.5").unwrap()); 165 assert_eq!(deps["hex"], Requirement::hex("~> 1.0.0").unwrap()); 166 assert_eq!(deps["local"], Requirement::path("/path/to/package")); 167 assert_eq!( 168 deps["github"], 169 Requirement::git("https://github.com/gleam-lang/otp.git", "4d34935") 170 ); 171 } 172 173 #[test] 174 fn read_wrong_version() { 175 let toml = r#" 176 short = ">= 2.0 and < 3.0.0" 177 "#; 178 179 let error = 180 toml::from_str::<HashMap<String, Requirement>>(toml).expect_err("invalid version"); 181 insta::assert_snapshot!(error.to_string()); 182 } 183}