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