Skip to main content

miden_project/ast/
dependency.rs

1use super::{parsing::SetSourceId, *};
2use crate::{Linkage, SourceId, Span, Uri, VersionRequirement};
3
4/// Represents information about a project dependency needed to resolve it to a Miden package
5#[derive(Debug, Clone)]
6#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
7#[cfg_attr(feature = "serde", serde(deny_unknown_fields))]
8pub struct DependencySpec {
9    /// The name of the dependency package
10    #[cfg_attr(feature = "serde", serde(default, skip))]
11    pub name: Span<Arc<str>>,
12    /// The version requirement specified for this dependency
13    #[cfg_attr(
14        feature = "serde",
15        serde(rename = "version", alias = "digest", skip_serializing_if = "Option::is_none")
16    )]
17    pub version_or_digest: Option<VersionRequirement>,
18    /// Whether or not the version requirement is inherited from the containing workspace
19    #[cfg_attr(
20        feature = "serde",
21        serde(default, skip_serializing_if = "does_not_inherit_from_workspace")
22    )]
23    pub workspace: bool,
24    /// If present, specifies the path from which this dependency should be loaded
25    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
26    pub path: Option<Span<Uri>>,
27    /// If present, specifies the URI of the git repository to clone in order to load this
28    /// dependency.
29    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
30    pub git: Option<Span<Uri>>,
31    /// If present, specifies the branch of the git repository to checkout when loading this
32    /// dependency from the URI specified by `git`.
33    ///
34    /// NOTE: This field is only valid when specified along with `git`, and may not be used in
35    /// conjunction with `rev`.
36    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
37    pub branch: Option<Span<Arc<str>>>,
38    /// If present, specifies the revision of the git repository to checkout when loading this
39    /// dependency from the URI specified by `git`.
40    ///
41    /// NOTE: This field is only valid when specified along with `git`, and may not be used in
42    /// conjunction with `branch`.
43    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
44    pub rev: Option<Span<Arc<str>>>,
45    /// If present, specifies the desired linkage for this dependency during assembly
46    #[cfg_attr(feature = "serde", serde(default, skip_serializing_if = "Option::is_none"))]
47    pub linkage: Option<Span<Linkage>>,
48}
49
50#[inline(always)]
51fn does_not_inherit_from_workspace(is_workspace_dependency: &bool) -> bool {
52    !(*is_workspace_dependency)
53}
54
55impl DependencySpec {
56    /// Returns the version constraint to apply to this dependency
57    pub fn version(&self) -> Option<&VersionRequirement> {
58        self.version_or_digest.as_ref()
59    }
60
61    /// Returns true if this dependency inherits its version requirement from a parent workspace
62    pub fn inherits_workspace_version(&self) -> bool {
63        self.workspace
64    }
65
66    /// Returns true if this dependency must be resolved using a host-provided resolver
67    pub fn is_host_resolved(&self) -> bool {
68        self.git.is_none() && self.path.is_none()
69    }
70
71    /// Returns true if this dependency specifies a local filesystem path
72    pub fn is_path(&self) -> bool {
73        self.path.is_some() && self.git.is_none()
74    }
75
76    /// Returns true if this dependency specifies a git repository
77    pub fn is_git(&self) -> bool {
78        self.git.is_some()
79    }
80}
81
82impl SetSourceId for DependencySpec {
83    fn set_source_id(&mut self, source_id: SourceId) {
84        self.name.set_source_id(source_id);
85        if let Some(version_or_digest) = self.version_or_digest.as_mut() {
86            version_or_digest.set_source_id(source_id);
87        }
88
89        if let Some(path) = self.path.as_mut() {
90            path.set_source_id(source_id);
91        }
92
93        if let Some(git) = self.git.as_mut() {
94            git.set_source_id(source_id);
95        }
96
97        if let Some(branch) = self.branch.as_mut() {
98            branch.set_source_id(source_id);
99        }
100
101        if let Some(rev) = self.rev.as_mut() {
102            rev.set_source_id(source_id);
103        }
104    }
105}
106
107#[cfg(feature = "serde")]
108pub use self::serialization::deserialize_dependency_map;
109
110#[cfg(feature = "serde")]
111mod serialization {
112    use alloc::sync::Arc;
113
114    use miden_assembly_syntax::debuginfo::Span;
115    use serde::de::{MapAccess, Visitor};
116
117    use super::DependencySpec;
118    use crate::Map;
119
120    struct DependencyMapVisitor;
121
122    impl<'de> Visitor<'de> for DependencyMapVisitor {
123        type Value = Map<Span<Arc<str>>, Span<DependencySpec>>;
124
125        fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
126            formatter.write_str("a dependency map")
127        }
128
129        fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
130        where
131            M: MapAccess<'de>,
132        {
133            let mut map = Self::Value::default();
134
135            while let Some((key, mut value)) =
136                access.next_entry::<Span<Arc<str>>, Span<DependencySpec>>()?
137            {
138                value.name = key.clone();
139                map.insert(key, value);
140            }
141
142            Ok(map)
143        }
144    }
145
146    #[allow(clippy::type_complexity)]
147    pub fn deserialize_dependency_map<'de, D>(
148        deserializer: D,
149    ) -> Result<Map<Span<Arc<str>>, Span<DependencySpec>>, D::Error>
150    where
151        D: serde::Deserializer<'de>,
152    {
153        deserializer.deserialize_map(DependencyMapVisitor)
154    }
155}