1use std::path::PathBuf;
2use std::sync::Arc;
3
4use nameof::name_of;
5use tracing_options::TracingOptions;
6
7use super::Host;
8use crate::rust_crate::build::BuildParams;
9use crate::{HostTargetType, ServiceBuilder};
10
11pub mod build;
12pub mod ports;
13
14pub mod service;
15pub use service::*;
16
17#[cfg(feature = "profile-folding")]
18pub(crate) mod flamegraph;
19pub mod tracing_options;
20
21#[derive(PartialEq, Clone)]
22pub enum CrateTarget {
23 Default,
24 Bin(String),
25 Example(String),
26}
27
28#[derive(Clone)]
35pub struct RustCrate {
36 src: PathBuf,
37 workspace_root: PathBuf,
38 target: CrateTarget,
39 profile: Option<String>,
40 rustflags: Option<String>,
41 target_dir: Option<PathBuf>,
42 build_env: Vec<(String, String)>,
43 is_dylib: bool,
44 no_default_features: bool,
45 features: Option<Vec<String>>,
46 config: Vec<String>,
47 tracing: Option<TracingOptions>,
48 args: Vec<String>,
49 display_name: Option<String>,
50}
51
52impl RustCrate {
53 pub fn new(src: impl Into<PathBuf>, workspace_root: impl Into<PathBuf>) -> Self {
59 Self {
60 src: src.into(),
61 workspace_root: workspace_root.into(),
62 target: CrateTarget::Default,
63 profile: None,
64 rustflags: None,
65 target_dir: None,
66 build_env: vec![],
67 is_dylib: false,
68 no_default_features: false,
69 features: None,
70 config: vec![],
71 tracing: None,
72 args: vec![],
73 display_name: None,
74 }
75 }
76
77 pub fn bin(mut self, bin: impl Into<String>) -> Self {
80 if self.target != CrateTarget::Default {
81 panic!("{} already set", name_of!(target in Self));
82 }
83
84 self.target = CrateTarget::Bin(bin.into());
85 self
86 }
87
88 pub fn example(mut self, example: impl Into<String>) -> Self {
91 if self.target != CrateTarget::Default {
92 panic!("{} already set", name_of!(target in Self));
93 }
94
95 self.target = CrateTarget::Example(example.into());
96 self
97 }
98
99 pub fn profile(mut self, profile: impl Into<String>) -> Self {
102 if self.profile.is_some() {
103 panic!("{} already set", name_of!(profile in Self));
104 }
105
106 self.profile = Some(profile.into());
107 self
108 }
109
110 pub fn rustflags(mut self, rustflags: impl Into<String>) -> Self {
111 if self.rustflags.is_some() {
112 panic!("{} already set", name_of!(rustflags in Self));
113 }
114
115 self.rustflags = Some(rustflags.into());
116 self
117 }
118
119 pub fn target_dir(mut self, target_dir: impl Into<PathBuf>) -> Self {
120 if self.target_dir.is_some() {
121 panic!("{} already set", name_of!(target_dir in Self));
122 }
123
124 self.target_dir = Some(target_dir.into());
125 self
126 }
127
128 pub fn build_env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
129 self.build_env.push((key.into(), value.into()));
130 self
131 }
132
133 pub fn set_is_dylib(mut self, is_dylib: bool) -> Self {
134 self.is_dylib = is_dylib;
135 self
136 }
137
138 pub fn no_default_features(mut self) -> Self {
139 self.no_default_features = true;
140 self
141 }
142
143 pub fn features(mut self, features: impl IntoIterator<Item = impl Into<String>>) -> Self {
144 if self.features.is_none() {
145 self.features = Some(vec![]);
146 }
147
148 self.features
149 .as_mut()
150 .unwrap()
151 .extend(features.into_iter().map(|s| s.into()));
152
153 self
154 }
155
156 pub fn config(mut self, config: impl Into<String>) -> Self {
157 self.config.push(config.into());
158 self
159 }
160
161 pub fn tracing(mut self, perf: impl Into<TracingOptions>) -> Self {
162 if self.tracing.is_some() {
163 panic!("{} already set", name_of!(tracing in Self));
164 }
165
166 self.tracing = Some(perf.into());
167 self
168 }
169
170 pub fn args(mut self, args: impl IntoIterator<Item = impl Into<String>>) -> Self {
172 self.args.extend(args.into_iter().map(|s| s.into()));
173 self
174 }
175
176 pub fn display_name(mut self, display_name: impl Into<String>) -> Self {
178 if self.display_name.is_some() {
179 panic!("{} already set", name_of!(display_name in Self));
180 }
181
182 self.display_name = Some(display_name.into());
183 self
184 }
185
186 pub fn get_build_params(&self, target: HostTargetType) -> BuildParams {
187 let (bin, example) = match &self.target {
188 CrateTarget::Default => (None, None),
189 CrateTarget::Bin(bin) => (Some(bin.clone()), None),
190 CrateTarget::Example(example) => (None, Some(example.clone())),
191 };
192
193 BuildParams::new(
194 self.src.clone(),
195 self.workspace_root.clone(),
196 bin,
197 example,
198 self.profile.clone(),
199 self.rustflags.clone(),
200 self.target_dir.clone(),
201 self.build_env.clone(),
202 self.no_default_features,
203 target,
204 self.is_dylib,
205 self.features.clone(),
206 self.config.clone(),
207 )
208 }
209}
210
211impl ServiceBuilder for RustCrate {
212 type Service = RustCrateService;
213 fn build(self, id: usize, on: Arc<dyn Host>) -> Self::Service {
214 let build_params = self.get_build_params(on.target_type());
215
216 RustCrateService::new(
217 id,
218 on,
219 build_params,
220 self.tracing,
221 Some(self.args),
222 self.display_name,
223 vec![],
224 )
225 }
226}