1use alloc::{
4 collections::BTreeMap,
5 string::{String, ToString},
6 vec,
7 vec::Vec,
8};
9use indexmap::IndexMap;
10
11pub type Gemspec = Specification;
12
13#[cfg(all(feature = "alloc", feature = "serde"))]
14pub type Map<K, V = serde_json::Value> = IndexMap<K, V>;
15
16#[cfg_attr(feature = "serde", serde_with::serde_as)]
26#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
27#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
28#[cfg_attr(feature = "serde", serde(default))]
29pub struct Specification<T = Metadata> {
30 #[cfg_attr(feature = "serde", serde(alias = "author"))]
32 #[cfg_attr(feature = "serde", serde_as(as = "OneOrMany<_, PreferMany>"))]
33 pub authors: Vec<String>,
34
35 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
37 pub bindir: Option<String>,
38
39 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
41 pub cert_chain: Option<Vec<String>>,
42
43 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
45 pub dependencies: Option<Vec<Dependency>>,
46
47 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
49 pub description: Option<String>,
50
51 #[cfg_attr(
53 feature = "serde",
54 serde(alias = "emails", skip_serializing_if = "Vec::is_empty")
55 )]
56 #[cfg_attr(feature = "serde", serde_as(as = "OneOrMany<_, PreferOne>"))]
57 pub email: Vec<String>, #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
61 pub executables: Option<Vec<String>>,
62
63 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
65 pub extensions: Option<Vec<String>>,
66
67 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
69 pub extensions_dir: Option<String>,
70
71 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
73 pub extra_rdoc_files: Option<Vec<String>>,
74
75 pub files: Vec<String>,
77
78 pub homepage: Option<String>,
80
81 #[cfg_attr(
83 feature = "serde",
84 serde(alias = "license", skip_serializing_if = "Vec::is_empty")
85 )]
86 #[cfg_attr(feature = "serde", serde_as(as = "OneOrMany<_, PreferMany>"))]
87 pub licenses: Vec<String>, #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
91 pub metadata: Option<T>,
92
93 pub name: String,
95
96 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
98 pub platform: Option<Platform>,
99
100 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
102 pub post_install_message: Option<String>,
103
104 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
106 pub rdoc_options: Option<Vec<String>>,
107
108 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
110 pub require_paths: Option<Vec<String>>,
111
112 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
114 pub required_ruby_version: Option<Requirement>,
115
116 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
118 pub required_rubygems_version: Option<Requirement>,
119
120 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
122 pub requirements: Option<Vec<String>>,
123
124 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
126 pub rubygems_version: Option<String>,
127
128 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
130 pub signing_key: Option<String>,
131
132 pub summary: String,
134
135 pub version: Version,
137}
138
139#[cfg(all(feature = "serde"))]
140impl<T: serde::Serialize> Specification<T> {
141 pub fn try_to_string(&self) -> Result<String, serde_norway::Error> {
142 serde_norway::to_string(self)
143 }
144}
145
146#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
148#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
149#[cfg_attr(feature = "serde", serde(default))]
150pub struct Dependency {
151 pub name: String,
152 pub r#type: String,
153 pub prerelease: bool,
154 pub requirement: Requirement,
155 pub version_requirements: Requirement,
156}
157
158impl Dependency {
159 pub fn development(name: impl Into<String>, requirement: (&str, &str)) -> Self {
160 let requirement = Requirement::from(requirement);
161 Self::new(name, "development", false, requirement.clone(), requirement)
162 }
163
164 pub fn new(
165 name: impl Into<String>,
166 r#type: impl Into<String>,
167 prerelease: bool,
168 requirement: Requirement,
169 version_requirements: Requirement,
170 ) -> Self {
171 Self {
172 name: name.into(),
173 r#type: r#type.into(),
174 prerelease,
175 requirement,
176 version_requirements,
177 }
178 }
179}
180
181#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
183#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
184#[cfg_attr(feature = "serde", serde(default))]
185pub struct Requirement {
186 pub requirements: Vec<(String, Version)>,
187}
188
189impl From<(&str, &str)> for Requirement {
190 fn from((input0, input1): (&str, &str)) -> Self {
191 From::from((input0.to_string(), input1.to_string()))
192 }
193}
194
195impl From<(String, String)> for Requirement {
196 fn from((input0, input1): (String, String)) -> Self {
197 From::from((input0, Version::from(input1)))
198 }
199}
200
201impl From<(String, Version)> for Requirement {
202 fn from((input0, input1): (String, Version)) -> Self {
203 Self {
204 requirements: vec![(input0, input1)],
205 }
206 }
207}
208
209#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
211#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
212#[cfg_attr(feature = "serde", serde(default))]
213pub struct Version {
214 pub version: String,
215}
216
217impl From<String> for Version {
218 fn from(version: String) -> Self {
219 Self { version }
220 }
221}
222
223#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
224#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
225#[cfg_attr(
226 feature = "serde",
227 serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))
228)]
229pub enum Platform {
230 #[default]
231 Ruby,
232 Current,
233 #[cfg_attr(feature = "serde", serde(untagged))]
234 Other(String),
235}
236
237#[derive(Clone, Debug, Default, Eq, PartialEq)]
239#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
240#[cfg_attr(feature = "serde", serde(default))]
241pub struct Metadata {
242 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
244 pub bug_tracker_uri: Option<String>,
245
246 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
248 pub changelog_uri: Option<String>,
249
250 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
252 pub documentation_uri: Option<String>,
253
254 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
256 pub funding_uri: Option<String>,
257
258 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
260 pub homepage_uri: Option<String>,
261
262 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
264 pub mailing_list_uri: Option<String>,
265
266 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
268 pub source_code_uri: Option<String>,
269
270 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
272 pub wiki_uri: Option<String>,
273
274 #[cfg(all(feature = "alloc", feature = "serde"))]
275 #[cfg_attr(
276 feature = "serde",
277 serde(flatten, skip_serializing_if = "Map::is_empty")
278 )]
279 pub other: Map<String>,
280}