1use std::collections::HashMap;
2use std::path::PathBuf;
3use std::sync::Arc;
4
5use nameof::name_of;
6use tracing_options::TracingOptions;
7
8use super::Host;
9use crate::rust_crate::build::BuildParams;
10use crate::{HostTargetType, ServiceBuilder};
11
12pub mod build;
13pub mod ports;
14
15pub mod service;
16pub use service::*;
17
18#[cfg(feature = "profile-folding")]
19pub(crate) mod flamegraph;
20pub mod tracing_options;
21
22#[derive(PartialEq, Clone)]
23pub enum CrateTarget {
24 Default,
25 Bin(String),
26 Example(String),
27}
28
29#[derive(Clone)]
36pub struct RustCrate {
37 src: PathBuf,
38 workspace_root: PathBuf,
39 target: CrateTarget,
40 profile: Option<String>,
41 rustflags: Option<String>,
42 target_dir: Option<PathBuf>,
43 build_env: Vec<(String, String)>,
44 dylib_package: Option<String>,
47 no_default_features: bool,
48 features: Option<Vec<String>>,
49 config: Vec<String>,
50 tracing: Option<TracingOptions>,
51 args: Vec<String>,
52 display_name: Option<String>,
53 env: HashMap<String, String>,
54 pin_to_core: Option<usize>,
55}
56
57impl RustCrate {
58 pub fn new(src: impl Into<PathBuf>, workspace_root: impl Into<PathBuf>) -> Self {
64 Self {
65 src: src.into(),
66 workspace_root: workspace_root.into(),
67 target: CrateTarget::Default,
68 profile: None,
69 rustflags: None,
70 target_dir: None,
71 build_env: vec![],
72 dylib_package: None,
73 no_default_features: false,
74 features: None,
75 config: vec![],
76 tracing: None,
77 args: vec![],
78 display_name: None,
79 env: HashMap::new(),
80 pin_to_core: None,
81 }
82 }
83
84 pub fn bin(mut self, bin: impl Into<String>) -> Self {
87 assert!(
88 self.target == CrateTarget::Default,
89 "{} already set",
90 name_of!(target in Self)
91 );
92
93 self.target = CrateTarget::Bin(bin.into());
94 self
95 }
96
97 pub fn example(mut self, example: impl Into<String>) -> Self {
100 assert!(
101 self.target == CrateTarget::Default,
102 "{} already set",
103 name_of!(target in Self)
104 );
105
106 self.target = CrateTarget::Example(example.into());
107 self
108 }
109
110 pub fn profile(mut self, profile: impl Into<String>) -> Self {
113 assert!(
114 self.profile.is_none(),
115 "{} already set",
116 name_of!(profile in Self)
117 );
118
119 self.profile = Some(profile.into());
120 self
121 }
122
123 pub fn rustflags(mut self, rustflags: impl Into<String>) -> Self {
124 assert!(
125 self.rustflags.is_none(),
126 "{} already set",
127 name_of!(rustflags in Self)
128 );
129
130 self.rustflags = Some(rustflags.into());
131 self
132 }
133
134 pub fn target_dir(mut self, target_dir: impl Into<PathBuf>) -> Self {
135 assert!(
136 self.target_dir.is_none(),
137 "{} already set",
138 name_of!(target_dir in Self)
139 );
140
141 self.target_dir = Some(target_dir.into());
142 self
143 }
144
145 pub fn build_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
146 self.build_env.push((key.into(), value.into()));
147 self
148 }
149
150 #[must_use]
153 pub fn dylib_package(mut self, dylib_package: impl Into<String>) -> Self {
154 self.dylib_package = Some(dylib_package.into());
155 self
156 }
157
158 #[must_use]
159 pub fn no_default_features(mut self) -> Self {
160 self.no_default_features = true;
161 self
162 }
163
164 pub fn features(mut self, features: impl IntoIterator<Item = impl Into<String>>) -> Self {
165 if self.features.is_none() {
166 self.features = Some(vec![]);
167 }
168
169 self.features
170 .as_mut()
171 .unwrap()
172 .extend(features.into_iter().map(|s| s.into()));
173
174 self
175 }
176
177 pub fn config(mut self, config: impl Into<String>) -> Self {
178 self.config.push(config.into());
179 self
180 }
181
182 pub fn tracing(mut self, perf: impl Into<TracingOptions>) -> Self {
183 assert!(
184 self.tracing.is_none(),
185 "{} already set",
186 name_of!(tracing in Self)
187 );
188
189 self.tracing = Some(perf.into());
190 self
191 }
192
193 pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
195 self.args.extend(args.into_iter().map(|s| s.into()));
196 self
197 }
198
199 pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
201 assert!(
202 self.display_name.is_none(),
203 "{} already set",
204 name_of!(display_name in Self)
205 );
206
207 self.display_name = Some(display_name.into());
208 self
209 }
210
211 pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
213 self.env.insert(key.into(), value.into());
214 self
215 }
216
217 #[must_use]
218 pub fn pin_to_core(mut self, core: usize) -> Self {
219 self.pin_to_core = Some(core);
220 self
221 }
222
223 pub fn get_build_params(&self, target: HostTargetType) -> BuildParams {
224 let (bin, example) = match &self.target {
225 CrateTarget::Default => (None, None),
226 CrateTarget::Bin(bin) => (Some(bin.clone()), None),
227 CrateTarget::Example(example) => (None, Some(example.clone())),
228 };
229
230 BuildParams::new(
231 self.src.clone(),
232 self.workspace_root.clone(),
233 bin,
234 example,
235 self.profile.clone(),
236 self.rustflags.clone(),
237 self.target_dir.clone(),
238 self.build_env.clone(),
239 self.no_default_features,
240 target,
241 self.dylib_package.clone(),
242 self.features.clone(),
243 self.config.clone(),
244 )
245 }
246}
247
248impl ServiceBuilder for RustCrate {
249 type Service = RustCrateService;
250 fn build(self, id: usize, on: Arc<dyn Host>) -> Self::Service {
251 let build_params = self.get_build_params(on.target_type());
252
253 RustCrateService::new(
254 id,
255 on,
256 build_params,
257 self.tracing,
258 Some(self.args),
259 self.display_name,
260 vec![],
261 self.env,
262 self.pin_to_core,
263 )
264 }
265}