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 is_dylib: bool,
45 no_default_features: bool,
46 features: Option<Vec<String>>,
47 config: Vec<String>,
48 tracing: Option<TracingOptions>,
49 args: Vec<String>,
50 display_name: Option<String>,
51 env: HashMap<String, String>,
52 pin_to_core: Option<usize>,
53}
54
55impl RustCrate {
56 pub fn new(src: impl Into<PathBuf>, workspace_root: impl Into<PathBuf>) -> Self {
62 Self {
63 src: src.into(),
64 workspace_root: workspace_root.into(),
65 target: CrateTarget::Default,
66 profile: None,
67 rustflags: None,
68 target_dir: None,
69 build_env: vec![],
70 is_dylib: false,
71 no_default_features: false,
72 features: None,
73 config: vec![],
74 tracing: None,
75 args: vec![],
76 display_name: None,
77 env: HashMap::new(),
78 pin_to_core: None,
79 }
80 }
81
82 pub fn bin(mut self, bin: impl Into<String>) -> Self {
85 if self.target != CrateTarget::Default {
86 panic!("{} already set", name_of!(target in Self));
87 }
88
89 self.target = CrateTarget::Bin(bin.into());
90 self
91 }
92
93 pub fn example(mut self, example: impl Into<String>) -> Self {
96 if self.target != CrateTarget::Default {
97 panic!("{} already set", name_of!(target in Self));
98 }
99
100 self.target = CrateTarget::Example(example.into());
101 self
102 }
103
104 pub fn profile(mut self, profile: impl Into<String>) -> Self {
107 if self.profile.is_some() {
108 panic!("{} already set", name_of!(profile in Self));
109 }
110
111 self.profile = Some(profile.into());
112 self
113 }
114
115 pub fn rustflags(mut self, rustflags: impl Into<String>) -> Self {
116 if self.rustflags.is_some() {
117 panic!("{} already set", name_of!(rustflags in Self));
118 }
119
120 self.rustflags = Some(rustflags.into());
121 self
122 }
123
124 pub fn target_dir(mut self, target_dir: impl Into<PathBuf>) -> Self {
125 if self.target_dir.is_some() {
126 panic!("{} already set", name_of!(target_dir in Self));
127 }
128
129 self.target_dir = Some(target_dir.into());
130 self
131 }
132
133 pub fn build_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
134 self.build_env.push((key.into(), value.into()));
135 self
136 }
137
138 pub fn set_is_dylib(mut self, is_dylib: bool) -> Self {
139 self.is_dylib = is_dylib;
140 self
141 }
142
143 pub fn no_default_features(mut self) -> Self {
144 self.no_default_features = true;
145 self
146 }
147
148 pub fn features(mut self, features: impl IntoIterator<Item = impl Into<String>>) -> Self {
149 if self.features.is_none() {
150 self.features = Some(vec![]);
151 }
152
153 self.features
154 .as_mut()
155 .unwrap()
156 .extend(features.into_iter().map(|s| s.into()));
157
158 self
159 }
160
161 pub fn config(mut self, config: impl Into<String>) -> Self {
162 self.config.push(config.into());
163 self
164 }
165
166 pub fn tracing(mut self, perf: impl Into<TracingOptions>) -> Self {
167 if self.tracing.is_some() {
168 panic!("{} already set", name_of!(tracing in Self));
169 }
170
171 self.tracing = Some(perf.into());
172 self
173 }
174
175 pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
177 self.args.extend(args.into_iter().map(|s| s.into()));
178 self
179 }
180
181 pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
183 if self.display_name.is_some() {
184 panic!("{} already set", name_of!(display_name in Self));
185 }
186
187 self.display_name = Some(display_name.into());
188 self
189 }
190
191 pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
193 self.env.insert(key.into(), value.into());
194 self
195 }
196
197 pub fn pin_to_core(mut self, core: usize) -> Self {
198 self.pin_to_core = Some(core);
199 self
200 }
201
202 pub fn get_build_params(&self, target: HostTargetType) -> BuildParams {
203 let (bin, example) = match &self.target {
204 CrateTarget::Default => (None, None),
205 CrateTarget::Bin(bin) => (Some(bin.clone()), None),
206 CrateTarget::Example(example) => (None, Some(example.clone())),
207 };
208
209 BuildParams::new(
210 self.src.clone(),
211 self.workspace_root.clone(),
212 bin,
213 example,
214 self.profile.clone(),
215 self.rustflags.clone(),
216 self.target_dir.clone(),
217 self.build_env.clone(),
218 self.no_default_features,
219 target,
220 self.is_dylib,
221 self.features.clone(),
222 self.config.clone(),
223 )
224 }
225}
226
227impl ServiceBuilder for RustCrate {
228 type Service = RustCrateService;
229 fn build(self, id: usize, on: Arc<dyn Host>) -> Self::Service {
230 let build_params = self.get_build_params(on.target_type());
231
232 RustCrateService::new(
233 id,
234 on,
235 build_params,
236 self.tracing,
237 Some(self.args),
238 self.display_name,
239 vec![],
240 self.env,
241 self.pin_to_core,
242 )
243 }
244}