Skip to main content

miden_project/
profile.rs

1use alloc::string::ToString;
2use core::borrow::Borrow;
3
4use miden_assembly_syntax::debuginfo::Spanned;
5
6use crate::*;
7
8/// Represents configuration options for a specific build profile, e.g. `release`
9#[derive(Debug, Clone)]
10pub struct Profile {
11    /// The name of this profile, e.g. `release`
12    name: Span<Arc<str>>,
13    /// Whether to emit debugging information for this profile
14    debug: bool,
15    /// Whether or not to trim file paths in debug information, making them relative to the current
16    /// working directory.
17    trim_paths: bool,
18    /// Custom metadata associated with this profile
19    ///
20    /// This is intended for third-party/downstream tooling which need to support per-profile
21    /// config.
22    metadata: Metadata,
23}
24
25impl Default for Profile {
26    /// Constructs the default 'dev' profile in a debug-friendly configuration
27    fn default() -> Self {
28        Self {
29            name: Span::unknown("dev".to_string().into_boxed_str().into()),
30            debug: true,
31            trim_paths: false,
32            metadata: Default::default(),
33        }
34    }
35}
36
37/// Constructors
38impl Profile {
39    /// Create a new profile called `name`, with all configuration options set to their defaults.
40    pub fn new(name: Span<Arc<str>>) -> Self {
41        Self { name, ..Default::default() }
42    }
43
44    /// Create a profile called `name`, with all configuration options inherited from `parent`
45    ///
46    /// NOTE: Any changes made to `parent` after this new profile is created are _not_ automatically
47    /// inherited - the "inheritance" here is simply used to initialize the options this profile
48    /// starts with.
49    pub fn inherit(name: Span<Arc<str>>, parent: &Self) -> Self {
50        Self { name, ..parent.clone() }
51    }
52
53    /// Get the default `release` profile
54    pub fn release() -> Self {
55        Self {
56            name: Span::unknown("release".to_string().into_boxed_str().into()),
57            debug: false,
58            trim_paths: true,
59            metadata: Default::default(),
60        }
61    }
62
63    #[cfg(feature = "serde")]
64    pub fn from_ast(
65        ast: &ast::Profile,
66        source: Arc<SourceFile>,
67        inheritable: &[Profile],
68    ) -> Result<Self, Report> {
69        use crate::ast::ProjectFileError;
70
71        let ast::Profile {
72            inherits,
73            name,
74            debug,
75            trim_paths,
76            metadata,
77        } = ast;
78
79        let mut profile = match inherits.as_ref() {
80            Some(parent) => {
81                if let Some(parent) = inheritable.iter().find(|p| p.name() == parent.inner()) {
82                    Profile::inherit(name.clone(), parent)
83                } else {
84                    return Err(ProjectFileError::UnknownProfile {
85                        name: parent.inner().clone(),
86                        source_file: source,
87                        span: parent.span(),
88                    }
89                    .into());
90                }
91            },
92            None => Profile::new(name.clone()),
93        };
94
95        if let Some(debug) = *debug {
96            profile.enable_debug_info(debug);
97        }
98
99        if let Some(trim_paths) = *trim_paths {
100            profile.enable_trim_paths(trim_paths);
101        }
102
103        if !metadata.is_empty() {
104            profile.extend(metadata.iter().map(|(k, v)| (k.clone(), v.clone())));
105        }
106
107        Ok(profile)
108    }
109
110    /// Merge configuration from `other` into `self`.
111    ///
112    /// This has the effect of overriding any options in `self` which have different values in
113    /// `other`.
114    pub fn merge(&mut self, other: &Self) {
115        let Self { name: _, debug, trim_paths, metadata } = self;
116
117        *debug = other.debug;
118        *trim_paths = other.trim_paths;
119        for (k, v2) in other.metadata.iter() {
120            if let Some(v) = metadata.get_mut(k) {
121                match &mut **v {
122                    Value::Table(table) => {
123                        if let Value::Table(table2) = v2.inner() {
124                            table.extend(table2.iter().map(|(k, v)| (k.clone(), v.clone())));
125                        } else {
126                            *v = v2.clone();
127                        }
128                    },
129                    _ => {
130                        *v = v2.clone();
131                    },
132                }
133            } else {
134                metadata.insert(k.clone(), v2.clone());
135            }
136        }
137    }
138}
139
140/// Mutations
141impl Profile {
142    /// Enable emission of debug information under this profile
143    pub fn enable_debug_info(&mut self, yes: bool) -> &mut Self {
144        self.debug = yes;
145        self
146    }
147
148    /// Enable trimmming of file paths in debug info under this profile
149    pub fn enable_trim_paths(&mut self, yes: bool) -> &mut Self {
150        self.trim_paths = yes;
151        self
152    }
153}
154
155/// Accessors
156impl Profile {
157    /// Get the name of this profile
158    pub fn name(&self) -> &Arc<str> {
159        &self.name
160    }
161
162    /// Returns true if this profile is configured so that we should emit debug information.
163    pub const fn should_emit_debug_info(&self) -> bool {
164        self.debug
165    }
166
167    /// Returns true if this profile is configured so that we should trim file paths in debug
168    /// information to be relative to the current working directory.
169    pub const fn should_trim_paths(&self) -> bool {
170        self.trim_paths
171    }
172
173    /// Returns true if `key` is defined in the custom metadata associated with this profile.
174    #[inline]
175    pub fn contains_key<Q>(&self, key: &Q) -> bool
176    where
177        Q: ?Sized + Ord,
178        Span<Arc<str>>: Borrow<Q> + Ord,
179    {
180        self.metadata.contains_key(key)
181    }
182
183    /// Returns the value associated with `key` in the custom metadata associated with this profile.
184    ///
185    /// Returns `None` if no value is found for `key`.
186    #[inline]
187    pub fn get<Q>(&self, key: &Q) -> Option<&Span<Value>>
188    where
189        Q: ?Sized + Ord,
190        Span<Arc<str>>: Borrow<Q> + Ord,
191    {
192        self.metadata.get(key)
193    }
194}
195
196impl Extend<(Span<Arc<str>>, Span<Value>)> for Profile {
197    fn extend<T: IntoIterator<Item = (Span<Arc<str>>, Span<Value>)>>(&mut self, iter: T) {
198        self.metadata.extend(iter);
199    }
200}
201
202impl Spanned for Profile {
203    fn span(&self) -> SourceSpan {
204        self.name.span()
205    }
206}