1use std::fmt::{Display, Formatter};
5
6use derive_setters::Setters;
7
8use crate::{private, Input, RustFlags, Step, Use};
9
10#[derive(Clone)]
11pub enum Version {
12 Stable,
13 Nightly,
14 Custom((u64, u64, u64)),
15}
16
17impl Display for Version {
18 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
19 match self {
20 Version::Stable => write!(f, "stable"),
21 Version::Nightly => write!(f, "nightly"),
22 Version::Custom(s) => write!(f, "{}.{}.{}", s.0, s.1, s.2),
23 }
24 }
25}
26
27impl Version {
28 pub fn new(major: u64, minor: u64, patch: u64) -> Self {
29 Version::Custom((major, minor, patch))
30 }
31}
32
33#[derive(Clone, Debug)]
34pub enum Component {
35 Clippy,
36 Rustfmt,
37 RustDoc,
38}
39
40impl Display for Component {
41 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
42 let val = match self {
43 Component::Clippy => "clippy",
44 Component::Rustfmt => "rustfmt",
45 Component::RustDoc => "rust-doc",
46 };
47 write!(f, "{val}")
48 }
49}
50
51#[derive(Clone)]
52pub enum Arch {
53 X86_64,
54 Aarch64,
55 Arm,
56 Wasm32,
57}
58
59impl Display for Arch {
60 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
61 let val = match self {
62 Arch::X86_64 => "x86_64",
63 Arch::Aarch64 => "aarch64",
64 Arch::Arm => "arm",
65 Arch::Wasm32 => "wasm32",
66 };
67 write!(f, "{val}")
68 }
69}
70
71#[derive(Clone)]
72pub enum Vendor {
73 Unknown,
74 Apple,
75 PC,
76}
77
78impl Display for Vendor {
79 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
80 let val = match self {
81 Vendor::Unknown => "unknown",
82 Vendor::Apple => "apple",
83 Vendor::PC => "pc",
84 };
85 write!(f, "{val}")
86 }
87}
88
89#[derive(Clone)]
90pub enum System {
91 Unknown,
92 Windows,
93 Linux,
94 Darwin,
95}
96
97impl Display for System {
98 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
99 let val = match self {
100 System::Unknown => "unknown",
101 System::Windows => "windows",
102 System::Linux => "linux",
103 System::Darwin => "darwin",
104 };
105 write!(f, "{val}")
106 }
107}
108
109#[derive(Clone)]
110pub enum Abi {
111 Unknown,
112 Gnu,
113 Msvc,
114 Musl,
115}
116
117impl Display for Abi {
118 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
119 let val = match self {
120 Abi::Unknown => "unknown",
121 Abi::Gnu => "gnu",
122 Abi::Msvc => "msvc",
123 Abi::Musl => "musl",
124 };
125 write!(f, "{val}")
126 }
127}
128
129#[derive(Clone, Setters)]
130pub struct Target {
131 pub arch: Arch,
132 pub vendor: Vendor,
133 pub system: System,
134 pub abi: Option<Abi>,
135}
136
137#[derive(Default, Clone, Setters)]
143#[setters(
144 strip_option,
145 into,
146 generate_delegates(ty = "Step<Toolchain>", field = "marker")
147)]
148pub struct Toolchain {
149 pub version: Vec<Version>,
150 #[setters(skip)]
151 pub target: Option<Target>,
152 pub components: Vec<Component>,
153 pub cache: Option<bool>,
154 pub cache_directories: Vec<String>,
155 pub cache_workspaces: Vec<String>,
156 pub cache_on_failure: Option<bool>,
157 pub cache_key: Option<String>,
158 pub matcher: Option<bool>,
159 pub rust_flags: Option<RustFlags>,
160 pub override_default: Option<bool>,
161}
162
163impl Toolchain {
164 pub fn add_version(mut self, version: Version) -> Self {
165 self.version.push(version);
166 self
167 }
168
169 pub fn add_component(mut self, component: Component) -> Self {
170 self.components.push(component);
171 self
172 }
173
174 pub fn add_stable(mut self) -> Self {
175 self.version.push(Version::Stable);
176 self
177 }
178
179 pub fn add_nightly(mut self) -> Self {
180 self.version.push(Version::Nightly);
181 self
182 }
183
184 pub fn add_clippy(mut self) -> Self {
185 self.components.push(Component::Clippy);
186 self
187 }
188
189 pub fn add_fmt(mut self) -> Self {
190 self.components.push(Component::Rustfmt);
191 self
192 }
193
194 pub fn target(mut self, arch: Arch, vendor: Vendor, system: System, abi: Option<Abi>) -> Self {
195 self.target = Some(Target { arch, vendor, system, abi });
196 self
197 }
198}
199
200impl From<Toolchain> for Step<Use> {
201 fn from(value: Toolchain) -> Self {
202 let mut step = Step::new("Setup Rust Toolchain").uses(
203 "actions-rust-lang",
204 "setup-rust-toolchain",
205 "v1",
206 );
207
208 let toolchain = value
209 .version
210 .iter()
211 .map(|t| match t {
212 Version::Stable => "stable".to_string(),
213 Version::Nightly => "nightly".to_string(),
214 Version::Custom((major, minor, patch)) => {
215 format!("{major}.{minor}.{patch}")
216 }
217 })
218 .reduce(|acc, a| format!("{acc}, {a}"));
219
220 let mut input = Input::default();
221
222 if let Some(toolchain) = toolchain {
223 input = input.add("toolchain", toolchain);
224 }
225
226 if let Some(target) = value.target {
227 let target = format!(
228 "{}-{}-{}{}",
229 target.arch,
230 target.vendor,
231 target.system,
232 target.abi.map(|v| v.to_string()).unwrap_or_default(),
233 );
234
235 input = input.add("target", target);
236 }
237
238 if !value.components.is_empty() {
239 let components = value
240 .components
241 .iter()
242 .map(|c| c.to_string())
243 .reduce(|acc, a| format!("{acc}, {a}"))
244 .unwrap_or_default();
245
246 input = input.add("components", components);
247 }
248
249 if let Some(cache) = value.cache {
250 input = input.add("cache", cache);
251 }
252
253 if !value.cache_directories.is_empty() {
254 let cache_directories = value.cache_directories.join("\n");
255 input = input.add("cache-directories", cache_directories);
256 }
257
258 if !value.cache_workspaces.is_empty() {
259 let cache_workspaces = value
260 .cache_workspaces
261 .iter()
262 .fold("".to_string(), |acc, a| format!("{acc}\n{a}"));
263
264 input = input.add("cache-workspaces", cache_workspaces);
265 }
266
267 if let Some(cache_on_failure) = value.cache_on_failure {
268 input = input.add("cache-on-failure", cache_on_failure);
269 }
270
271 if let Some(cache_key) = value.cache_key {
272 input = input.add("cache-key", cache_key);
273 }
274
275 if let Some(matcher) = value.matcher {
276 input = input.add("matcher", matcher);
277 }
278
279 if let Some(rust_flags) = value.rust_flags {
280 input = input.add("rust-flags", rust_flags.to_string());
281 }
282
283 if let Some(override_default) = value.override_default {
284 input = input.add("override", override_default);
285 }
286
287 if !input.is_empty() {
288 step = step.with(input);
289 }
290 step
291 }
292}
293
294impl private::Sealed for Toolchain {}