tomling/cargo/
package.rs

1//! Cargo package information.
2
3use 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/// The package information.
12#[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    /// The package name.
48    pub fn name(&self) -> &str {
49        &self.name
50    }
51
52    /// The package version.
53    pub fn version(&self) -> Option<WorkspaceInheritable<&str>> {
54        self.version.as_ref().map(WorkspaceInheritable::borrow)
55    }
56
57    /// The Rust edition.
58    pub fn edition(&self) -> Option<&WorkspaceInheritable<RustEdition>> {
59        self.edition.as_ref()
60    }
61
62    /// The required Rust version.
63    pub fn rust_version(&self) -> Option<WorkspaceInheritable<&str>> {
64        self.rust_version.as_ref().map(WorkspaceInheritable::borrow)
65    }
66
67    /// The list of authors.
68    pub fn authors(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &Author<'_>>>> {
69        self.authors
70            .as_ref()
71            .map(WorkspaceInheritable::borrow_iteratable)
72    }
73
74    /// The package description.
75    pub fn description(&self) -> Option<WorkspaceInheritable<&str>> {
76        self.description.as_ref().map(WorkspaceInheritable::borrow)
77    }
78
79    /// The package documentation URL.
80    pub fn documentation(&self) -> Option<WorkspaceInheritable<&str>> {
81        self.documentation
82            .as_ref()
83            .map(WorkspaceInheritable::borrow)
84    }
85
86    /// The path to the README file.
87    pub fn readme(&self) -> Option<WorkspaceInheritable<&str>> {
88        self.readme.as_ref().map(WorkspaceInheritable::borrow)
89    }
90
91    /// The package homepage URL.
92    pub fn homepage(&self) -> Option<WorkspaceInheritable<&str>> {
93        self.homepage.as_ref().map(WorkspaceInheritable::borrow)
94    }
95
96    /// The package repository URL.
97    pub fn repository(&self) -> Option<WorkspaceInheritable<&str>> {
98        self.repository.as_ref().map(WorkspaceInheritable::borrow)
99    }
100
101    /// The package license.
102    pub fn license(&self) -> Option<WorkspaceInheritable<&str>> {
103        self.license.as_ref().map(WorkspaceInheritable::borrow)
104    }
105
106    /// The path to the license file.
107    pub fn license_file(&self) -> Option<WorkspaceInheritable<&str>> {
108        self.license_file.as_ref().map(WorkspaceInheritable::borrow)
109    }
110
111    /// The package keywords.
112    pub fn keywords(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
113        self.keywords
114            .as_ref()
115            .map(WorkspaceInheritable::borrow_iteratable)
116    }
117
118    /// The package categories.
119    pub fn categories(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
120        self.categories
121            .as_ref()
122            .map(WorkspaceInheritable::borrow_iteratable)
123    }
124
125    /// The workspace path.
126    pub fn workspace(&self) -> Option<&str> {
127        self.workspace.as_deref()
128    }
129
130    /// The build script path.
131    pub fn build(&self) -> Option<&str> {
132        self.build.as_deref()
133    }
134
135    /// The package links.
136    pub fn links(&self) -> Option<&str> {
137        self.links.as_deref()
138    }
139
140    /// Whether the package should be published.
141    pub fn publish(&self) -> Option<WorkspaceInheritable<bool>> {
142        self.publish.clone()
143    }
144
145    /// The package metadata.
146    pub fn metadata(&self) -> Option<&Table<'p>> {
147        self.metadata.as_ref()
148    }
149
150    /// The paths to include.
151    pub fn include(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
152        self.include
153            .as_ref()
154            .map(WorkspaceInheritable::borrow_iteratable)
155    }
156
157    /// The paths to exclude.
158    pub fn exclude(&self) -> Option<WorkspaceInheritable<impl Iterator<Item = &str>>> {
159        self.exclude
160            .as_ref()
161            .map(WorkspaceInheritable::borrow_iteratable)
162    }
163
164    /// The default run command.
165    pub fn default_run(&self) -> Option<&str> {
166        self.default_run.as_deref()
167    }
168
169    /// Whether to automatically build binaries.
170    pub fn autobins(&self) -> Option<bool> {
171        self.autobins
172    }
173
174    /// Whether to automatically build examples.
175    pub fn autoexamples(&self) -> Option<bool> {
176        self.autoexamples
177    }
178
179    /// Whether to automatically build tests.
180    pub fn autotests(&self) -> Option<bool> {
181        self.autotests
182    }
183
184    /// Whether to automatically build benchmarks.
185    pub fn autobenches(&self) -> Option<bool> {
186        self.autobenches
187    }
188
189    /// The resolver version.
190    pub fn resolver(&self) -> Option<ResolverVersion> {
191        self.resolver
192    }
193}
194
195/// The property inheritable from the workspace.
196#[derive(Debug, Clone, PartialEq)]
197pub enum WorkspaceInheritable<W> {
198    /// The value.
199    Uninherited(W),
200    /// Inherit from the workspace.
201    Inherited,
202}
203
204impl<W> WorkspaceInheritable<W> {
205    /// Get the value if it is uninherited.
206    pub fn uninherited(self) -> Option<W> {
207        match self {
208            Self::Uninherited(value) => Some(value),
209            Self::Inherited => None,
210        }
211    }
212
213    /// Get a reference to the value if it is uninherited.
214    pub fn uninherited_ref(&self) -> Option<&W> {
215        match self {
216            Self::Uninherited(value) => Some(value),
217            Self::Inherited => None,
218        }
219    }
220
221    /// If it is inherited from the workspace.
222    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}