1#![deny(missing_docs)]
2#![warn(rustdoc::broken_intra_doc_links)]
3#![deny(rustdoc::private_intra_doc_links)]
4#![warn(rust_2018_idioms)]
5#![doc = concat!(
6 "Structured access to the output of `scarb metadata --format-version ",
7 env!("CARGO_PKG_VERSION_MAJOR"),
8 "`.
9")]
10use std::collections::{BTreeMap, HashMap};
21use std::fmt;
22use std::ops::Index;
23use std::path::PathBuf;
24
25use camino::{Utf8Path, Utf8PathBuf};
26#[cfg(feature = "builder")]
27use derive_builder::Builder;
28use semver::{Version, VersionReq};
29use serde::{Deserialize, Serialize};
30
31#[cfg(feature = "command")]
32pub use command::*;
33pub use version_pin::*;
34
35#[cfg(feature = "command")]
36mod command;
37mod version_pin;
38
39#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
45#[serde(transparent)]
46pub struct PackageId {
47 pub repr: String,
49}
50
51impl From<String> for PackageId {
52 fn from(repr: String) -> Self {
53 Self { repr }
54 }
55}
56
57impl fmt::Display for PackageId {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 fmt::Display::fmt(&self.repr, f)
60 }
61}
62
63#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
67#[serde(transparent)]
68pub struct SourceId {
69 pub repr: String,
71}
72
73impl From<String> for SourceId {
74 fn from(repr: String) -> Self {
75 Self { repr }
76 }
77}
78
79impl fmt::Display for SourceId {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 fmt::Display::fmt(&self.repr, f)
82 }
83}
84
85#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
91#[serde(transparent)]
92pub struct CompilationUnitId {
93 pub repr: String,
95}
96
97impl From<String> for CompilationUnitId {
98 fn from(repr: String) -> Self {
99 Self { repr }
100 }
101}
102
103impl fmt::Display for CompilationUnitId {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 fmt::Display::fmt(&self.repr, f)
106 }
107}
108
109#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
115#[serde(transparent)]
116pub struct CompilationUnitComponentId {
117 pub repr: String,
119}
120
121impl From<String> for CompilationUnitComponentId {
122 fn from(repr: String) -> Self {
123 Self { repr }
124 }
125}
126
127impl fmt::Display for CompilationUnitComponentId {
128 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129 fmt::Display::fmt(&self.repr, f)
130 }
131}
132
133fn current_profile_default() -> String {
134 "release".to_string()
135}
136fn profiles_default() -> Vec<String> {
137 vec!["release".to_string()]
138}
139
140#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
142#[cfg_attr(feature = "builder", derive(Builder))]
143#[cfg_attr(feature = "builder", builder(setter(into)))]
144#[non_exhaustive]
145pub struct Metadata {
146 #[cfg_attr(feature = "builder", builder(setter(skip)))]
150 pub version: VersionPin,
151
152 pub app_exe: Option<PathBuf>,
154
155 pub app_version_info: VersionInfo,
157
158 pub target_dir: Option<Utf8PathBuf>,
161
162 #[serde(default)]
170 pub runtime_manifest: Utf8PathBuf,
171
172 pub workspace: WorkspaceMetadata,
174
175 pub packages: Vec<PackageMetadata>,
180
181 pub compilation_units: Vec<CompilationUnitMetadata>,
183
184 #[serde(default = "current_profile_default")]
186 pub current_profile: String,
187
188 #[serde(default = "profiles_default")]
190 pub profiles: Vec<String>,
191
192 #[cfg_attr(feature = "builder", builder(default))]
194 #[serde(flatten)]
195 pub extra: HashMap<String, serde_json::Value>,
196}
197
198#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
200#[cfg_attr(feature = "builder", derive(Builder))]
201#[cfg_attr(feature = "builder", builder(setter(into)))]
202#[non_exhaustive]
203pub struct WorkspaceMetadata {
204 pub manifest_path: Utf8PathBuf,
206
207 pub root: Utf8PathBuf,
209
210 pub members: Vec<PackageId>,
212
213 #[cfg_attr(feature = "builder", builder(default))]
215 #[serde(flatten)]
216 pub extra: HashMap<String, serde_json::Value>,
217}
218
219#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
221#[cfg_attr(feature = "builder", derive(Builder))]
222#[cfg_attr(feature = "builder", builder(setter(into)))]
223#[non_exhaustive]
224pub struct PackageMetadata {
225 pub id: PackageId,
227
228 pub name: String,
230
231 pub version: Version,
233
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub edition: Option<String>,
237
238 pub source: SourceId,
240
241 pub manifest_path: Utf8PathBuf,
243
244 pub root: Utf8PathBuf,
246
247 pub dependencies: Vec<DependencyMetadata>,
249
250 pub targets: Vec<TargetMetadata>,
252
253 #[serde(flatten)]
255 pub manifest_metadata: ManifestMetadata,
256
257 #[serde(default)]
259 pub experimental_features: Vec<String>,
260
261 #[cfg_attr(feature = "builder", builder(default))]
263 #[serde(flatten)]
264 pub extra: HashMap<String, serde_json::Value>,
265}
266
267#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
269#[serde(rename_all = "kebab-case")]
270pub enum DepKind {
271 Dev,
273}
274
275#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
280#[cfg_attr(feature = "builder", derive(Builder))]
281#[cfg_attr(feature = "builder", builder(setter(into)))]
282#[non_exhaustive]
283pub struct DependencyMetadata {
284 pub name: String,
286 pub version_req: VersionReq,
288 pub source: SourceId,
290 pub kind: Option<DepKind>,
292 pub features: Option<Vec<String>>,
294 pub default_features: Option<bool>,
296
297 #[cfg_attr(feature = "builder", builder(default))]
299 #[serde(flatten)]
300 pub extra: HashMap<String, serde_json::Value>,
301}
302
303#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
305#[cfg_attr(feature = "builder", derive(Builder))]
306#[cfg_attr(feature = "builder", builder(setter(into)))]
307#[non_exhaustive]
308pub struct TargetMetadata {
309 pub kind: String,
311 pub name: String,
313 pub source_path: Utf8PathBuf,
315 pub params: serde_json::Value,
319
320 #[cfg_attr(feature = "builder", builder(default))]
322 #[serde(flatten)]
323 pub extra: HashMap<String, serde_json::Value>,
324}
325
326#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
328#[cfg_attr(feature = "builder", derive(Builder))]
329#[cfg_attr(feature = "builder", builder(setter(into)))]
330#[non_exhaustive]
331pub struct CompilationUnitMetadata {
332 pub id: CompilationUnitId,
334
335 pub package: PackageId,
337
338 pub target: TargetMetadata,
340
341 pub compiler_config: serde_json::Value,
345
346 #[serde(rename = "components_data")]
349 pub components: Vec<CompilationUnitComponentMetadata>,
350
351 #[serde(default)]
353 pub cairo_plugins: Vec<CompilationUnitCairoPluginMetadata>,
354
355 #[serde(default)]
357 pub cfg: Vec<Cfg>,
358
359 #[cfg_attr(feature = "builder", builder(default))]
361 #[serde(flatten)]
362 pub extra: HashMap<String, serde_json::Value>,
363}
364
365#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
370#[cfg_attr(feature = "builder", derive(Builder))]
371#[cfg_attr(feature = "builder", builder(setter(into)))]
372#[non_exhaustive]
373pub struct CompilationUnitComponentMetadata {
374 pub package: PackageId,
376 pub name: String,
380 pub source_path: Utf8PathBuf,
382 #[serde(default)]
386 pub cfg: Option<Vec<Cfg>>,
387 pub id: Option<CompilationUnitComponentId>,
389 pub discriminator: Option<String>,
394 pub dependencies: Option<Vec<CompilationUnitComponentDependencyMetadata>>,
397
398 #[cfg_attr(feature = "builder", builder(default))]
400 #[serde(flatten)]
401 pub extra: HashMap<String, serde_json::Value>,
402}
403
404#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
406#[cfg_attr(feature = "builder", derive(Builder))]
407#[cfg_attr(feature = "builder", builder(setter(into)))]
408#[non_exhaustive]
409pub struct CompilationUnitComponentDependencyMetadata {
410 pub id: CompilationUnitComponentId,
414
415 #[cfg_attr(feature = "builder", builder(default))]
417 #[serde(flatten)]
418 pub extra: HashMap<String, serde_json::Value>,
419}
420
421#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
423#[cfg_attr(feature = "builder", derive(Builder))]
424#[cfg_attr(feature = "builder", builder(setter(into)))]
425#[non_exhaustive]
426pub struct CompilationUnitCairoPluginMetadata {
427 pub package: PackageId,
429
430 pub component_dependency_id: Option<CompilationUnitComponentId>,
434
435 pub prebuilt_allowed: Option<bool>,
437
438 #[cfg_attr(feature = "builder", builder(default))]
440 #[serde(flatten)]
441 pub extra: HashMap<String, serde_json::Value>,
442}
443
444#[derive(Clone, Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
446#[cfg_attr(feature = "builder", derive(Builder))]
447#[cfg_attr(feature = "builder", builder(setter(into)))]
448#[non_exhaustive]
449pub struct ManifestMetadata {
450 pub authors: Option<Vec<String>>,
452 pub description: Option<String>,
454 pub documentation: Option<String>,
456 pub homepage: Option<String>,
458 pub keywords: Option<Vec<String>>,
460 pub license: Option<String>,
465 pub license_file: Option<String>,
467 pub readme: Option<String>,
470 pub repository: Option<String>,
472 pub urls: Option<BTreeMap<String, String>>,
474 pub tool: Option<BTreeMap<String, serde_json::Value>>,
476}
477
478#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
480#[cfg_attr(feature = "builder", derive(Builder))]
481#[cfg_attr(feature = "builder", builder(setter(into)))]
482#[non_exhaustive]
483pub struct VersionInfo {
484 pub version: Version,
486 pub commit_info: Option<CommitInfo>,
488 pub cairo: CairoVersionInfo,
490
491 #[cfg_attr(feature = "builder", builder(default))]
493 #[serde(flatten)]
494 pub extra: HashMap<String, serde_json::Value>,
495}
496
497#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
499#[cfg_attr(feature = "builder", derive(Builder))]
500#[cfg_attr(feature = "builder", builder(setter(into)))]
501#[non_exhaustive]
502pub struct CairoVersionInfo {
503 pub version: Version,
505 pub commit_info: Option<CommitInfo>,
507
508 #[cfg_attr(feature = "builder", builder(default))]
510 #[serde(flatten)]
511 pub extra: HashMap<String, serde_json::Value>,
512}
513
514#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
516#[cfg_attr(feature = "builder", derive(Builder))]
517#[cfg_attr(feature = "builder", builder(setter(into)))]
518#[non_exhaustive]
519pub struct CommitInfo {
520 pub short_commit_hash: String,
522 pub commit_hash: String,
524 pub commit_date: Option<String>,
526}
527
528#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
530#[serde(untagged)]
531pub enum Cfg {
532 KV(String, String),
534 Name(String),
536}
537
538impl Metadata {
539 pub fn get_package(&self, id: &PackageId) -> Option<&PackageMetadata> {
541 self.packages.iter().find(|p| p.id == *id)
542 }
543
544 pub fn is_builtin_plugin(&self, plugin: &CompilationUnitCairoPluginMetadata) -> Option<bool> {
546 self.get_package(&plugin.package)?
547 .targets
548 .iter()
549 .find(|&target| target.kind == "cairo-plugin")
550 .map(|target| {
551 target
552 .params
553 .get("builtin")
554 .and_then(|value| value.as_bool())
555 .unwrap_or_default()
556 })
557 }
558
559 pub fn get_compilation_unit(&self, id: &CompilationUnitId) -> Option<&CompilationUnitMetadata> {
561 self.compilation_units.iter().find(|p| p.id == *id)
562 }
563}
564
565impl<'a> Index<&'a PackageId> for Metadata {
566 type Output = PackageMetadata;
567
568 fn index(&self, idx: &'a PackageId) -> &Self::Output {
569 self.get_package(idx)
570 .unwrap_or_else(|| panic!("no package with this ID: {idx}"))
571 }
572}
573
574impl<'a> Index<&'a CompilationUnitId> for Metadata {
575 type Output = CompilationUnitMetadata;
576
577 fn index(&self, idx: &'a CompilationUnitId) -> &Self::Output {
578 self.get_compilation_unit(idx)
579 .unwrap_or_else(|| panic!("no compilation unit with this ID: {idx}"))
580 }
581}
582
583impl PackageMetadata {
584 pub fn tool_metadata(&self, tool_name: &str) -> Option<&serde_json::Value> {
587 self.manifest_metadata.tool.as_ref()?.get(tool_name)
588 }
589}
590
591impl TargetMetadata {
592 pub fn source_root(&self) -> &Utf8Path {
594 self.source_path
595 .parent()
596 .expect("Source path is guaranteed to point to a file.")
597 }
598}
599
600impl CompilationUnitComponentMetadata {
601 pub fn source_root(&self) -> &Utf8Path {
603 self.source_path
604 .parent()
605 .expect("Source path is guaranteed to point to a file.")
606 }
607}
608
609impl<'a> Index<&'a CompilationUnitComponentId> for CompilationUnitMetadata {
610 type Output = CompilationUnitComponentMetadata;
611
612 fn index(&self, idx: &'a CompilationUnitComponentId) -> &Self::Output {
613 self.components
614 .iter()
615 .find(|p| p.id.as_ref() == Some(idx))
616 .unwrap_or_else(|| panic!("no compilation unit with this ID: {idx}"))
617 }
618}