1use core::borrow::Borrow;
4
5use alloc::{borrow::Cow, vec::Vec};
6use serde::Deserialize;
7
8use super::{Author, ResolverVersion, RustEdition};
9use crate::{Table, Value};
10
11#[derive(Debug, Deserialize, Clone, PartialEq)]
13pub struct Package<'p> {
14 name: Cow<'p, str>,
15 #[serde(borrow)]
16 version: Option<WorkspaceInheritable<Cow<'p, str>>>,
17 edition: Option<WorkspaceInheritable<RustEdition>>,
18 #[serde(rename = "rust-version")]
19 rust_version: Option<WorkspaceInheritable<Cow<'p, str>>>,
20 authors: Option<WorkspaceInheritable<Vec<Author<'p>>>>,
21 description: Option<WorkspaceInheritable<Cow<'p, str>>>,
22 documentation: Option<WorkspaceInheritable<Cow<'p, str>>>,
23 readme: Option<WorkspaceInheritable<Cow<'p, str>>>,
24 homepage: Option<WorkspaceInheritable<Cow<'p, str>>>,
25 repository: Option<WorkspaceInheritable<Cow<'p, str>>>,
26 license: Option<WorkspaceInheritable<Cow<'p, str>>>,
27 license_file: Option<WorkspaceInheritable<Cow<'p, str>>>,
28 keywords: Option<WorkspaceInheritable<Vec<Cow<'p, str>>>>,
29 categories: Option<WorkspaceInheritable<Vec<Cow<'p, str>>>>,
30 workspace: Option<Cow<'p, str>>,
31 build: Option<Cow<'p, str>>,
32 links: Option<Cow<'p, str>>,
33 publish: Option<WorkspaceInheritable<bool>>,
34 metadata: Option<Table<'p>>,
35 include: Option<WorkspaceInheritable<Vec<Cow<'p, str>>>>,
36 exclude: Option<WorkspaceInheritable<Vec<Cow<'p, str>>>>,
37 #[serde(rename = "default-run")]
38 default_run: Option<Cow<'p, str>>,
39 autobins: Option<bool>,
40 autoexamples: Option<bool>,
41 autotests: Option<bool>,
42 autobenches: Option<bool>,
43 resolver: Option<ResolverVersion>,
44}
45
46impl<'p> Package<'p> {
47 pub fn name(&self) -> &str {
49 &self.name
50 }
51
52 pub fn version(&self) -> Option<WorkspaceInheritable<&str>> {
54 self.version.as_ref().map(WorkspaceInheritable::borrow)
55 }
56
57 pub fn edition(&self) -> Option<&WorkspaceInheritable<RustEdition>> {
59 self.edition.as_ref()
60 }
61
62 pub fn rust_version(&self) -> Option<WorkspaceInheritable<&str>> {
64 self.rust_version.as_ref().map(WorkspaceInheritable::borrow)
65 }
66
67 pub fn authors(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &Author<'_>>>> {
69 self.authors
70 .as_ref()
71 .map(WorkspaceInheritable::borrow_iteratable)
72 }
73
74 pub fn description(&self) -> Option<WorkspaceInheritable<&str>> {
76 self.description.as_ref().map(WorkspaceInheritable::borrow)
77 }
78
79 pub fn documentation(&self) -> Option<WorkspaceInheritable<&str>> {
81 self.documentation
82 .as_ref()
83 .map(WorkspaceInheritable::borrow)
84 }
85
86 pub fn readme(&self) -> Option<WorkspaceInheritable<&str>> {
88 self.readme.as_ref().map(WorkspaceInheritable::borrow)
89 }
90
91 pub fn homepage(&self) -> Option<WorkspaceInheritable<&str>> {
93 self.homepage.as_ref().map(WorkspaceInheritable::borrow)
94 }
95
96 pub fn repository(&self) -> Option<WorkspaceInheritable<&str>> {
98 self.repository.as_ref().map(WorkspaceInheritable::borrow)
99 }
100
101 pub fn license(&self) -> Option<WorkspaceInheritable<&str>> {
103 self.license.as_ref().map(WorkspaceInheritable::borrow)
104 }
105
106 pub fn license_file(&self) -> Option<WorkspaceInheritable<&str>> {
108 self.license_file.as_ref().map(WorkspaceInheritable::borrow)
109 }
110
111 pub fn keywords(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
113 self.keywords
114 .as_ref()
115 .map(WorkspaceInheritable::borrow_iteratable)
116 }
117
118 pub fn categories(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
120 self.categories
121 .as_ref()
122 .map(WorkspaceInheritable::borrow_iteratable)
123 }
124
125 pub fn workspace(&self) -> Option<&str> {
127 self.workspace.as_deref()
128 }
129
130 pub fn build(&self) -> Option<&str> {
132 self.build.as_deref()
133 }
134
135 pub fn links(&self) -> Option<&str> {
137 self.links.as_deref()
138 }
139
140 pub fn publish(&self) -> Option<WorkspaceInheritable<bool>> {
142 self.publish.clone()
143 }
144
145 pub fn metadata(&self) -> Option<&Table<'p>> {
147 self.metadata.as_ref()
148 }
149
150 pub fn include(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
152 self.include
153 .as_ref()
154 .map(WorkspaceInheritable::borrow_iteratable)
155 }
156
157 pub fn exclude(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
159 self.exclude
160 .as_ref()
161 .map(WorkspaceInheritable::borrow_iteratable)
162 }
163
164 pub fn default_run(&self) -> Option<&str> {
166 self.default_run.as_deref()
167 }
168
169 pub fn autobins(&self) -> Option<bool> {
171 self.autobins
172 }
173
174 pub fn autoexamples(&self) -> Option<bool> {
176 self.autoexamples
177 }
178
179 pub fn autotests(&self) -> Option<bool> {
181 self.autotests
182 }
183
184 pub fn autobenches(&self) -> Option<bool> {
186 self.autobenches
187 }
188
189 pub fn resolver(&self) -> Option<ResolverVersion> {
191 self.resolver
192 }
193}
194
195#[derive(Debug, Clone, PartialEq)]
197pub enum WorkspaceInheritable<W> {
198 Uninherited(W),
200 Inherited,
202}
203
204impl<W> WorkspaceInheritable<W> {
205 pub fn uninherited(self) -> Option<W> {
207 match self {
208 Self::Uninherited(value) => Some(value),
209 Self::Inherited => None,
210 }
211 }
212
213 pub fn uninherited_ref(&self) -> Option<&W> {
215 match self {
216 Self::Uninherited(value) => Some(value),
217 Self::Inherited => None,
218 }
219 }
220
221 pub fn inherited(&self) -> bool {
223 matches!(self, Self::Inherited)
224 }
225
226 fn borrow<Borrowed: ?Sized>(&self) -> WorkspaceInheritable<&Borrowed>
227 where
228 W: AsRef<Borrowed>,
229 {
230 match self {
231 WorkspaceInheritable::Uninherited(d) => WorkspaceInheritable::Uninherited(d.as_ref()),
232 WorkspaceInheritable::Inherited => WorkspaceInheritable::Inherited,
233 }
234 }
235}
236
237impl<T> WorkspaceInheritable<Vec<T>> {
238 fn borrow_iteratable<'w, U>(&'w self) -> WorkspaceInheritable<impl Iterator<Item = &'w U>>
239 where
240 T: Borrow<U>,
241 U: 'w + ?Sized,
242 {
243 match self {
244 WorkspaceInheritable::Uninherited(d) => {
245 WorkspaceInheritable::Uninherited(d.iter().map(Borrow::borrow))
246 }
247 WorkspaceInheritable::Inherited => WorkspaceInheritable::Inherited,
248 }
249 }
250}
251
252impl<W> From<W> for WorkspaceInheritable<W> {
253 fn from(value: W) -> Self {
254 Self::Uninherited(value)
255 }
256}
257
258impl<'value, 'de: 'value, W> Deserialize<'de> for WorkspaceInheritable<W>
259where
260 W: TryFrom<Value<'value>, Error = crate::Error>,
261{
262 fn deserialize<D>(deserializer: D) -> Result<WorkspaceInheritable<W>, D::Error>
263 where
264 D: serde::Deserializer<'de>,
265 {
266 match <Value<'value>>::deserialize(deserializer)? {
267 Value::Table(table) => {
268 table
269 .get("workspace")
270 .and_then(|v| (v == &Value::Boolean(true)).then_some(()))
271 .ok_or_else(|| serde::de::Error::missing_field("workspace"))?;
272 Ok(Self::Inherited)
273 }
274 value => value
275 .try_into()
276 .map(Self::Uninherited)
277 .map_err(serde::de::Error::custom),
278 }
279 }
280}