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