1use std::{ops::Deref, process::Command};
2
3pub struct Targets(Vec<u8>);
4
5impl Targets {
6 pub fn iter(&self) -> Result<TargetsIter, std::str::Utf8Error> {
7 std::str::from_utf8(&self.0)
8 .map(str::lines)
9 .map(TargetsIter)
10 }
11
12 pub fn collect_strs(&self) -> Result<CollectedTargetsStrs, std::str::Utf8Error> {
13 std::str::from_utf8(&self.0)
14 .map(str::lines)
15 .map(|targets| targets.collect())
16 .map(CollectedTargetsStrs::from_vec)
17 }
18}
19
20pub struct TargetsIter<'a>(std::str::Lines<'a>);
21
22impl<'a> Iterator for TargetsIter<'a> {
23 type Item = &'a str;
24
25 fn next(&mut self) -> Option<Self::Item> {
26 self.0.next()
27 }
28}
29
30pub struct CollectedTargetsStrs<'a>(Vec<&'a str>);
31
32impl<'a> CollectedTargetsStrs<'a> {
33 fn from_vec(vec: Vec<&'a str>) -> Self {
34 #[cfg(debug_assertions)]
35 for window in vec.windows(2) {
36 assert!(
37 window[0] < window[1],
38 "The targets from `go tool dist list` were expected to be sorted lexicographically."
39 );
40 }
41 Self(vec)
42 }
43}
44
45impl<'a> CollectedTargetsStrs<'a> {
46 pub fn contains(&self, target: &str) -> bool {
47 self.0.binary_search(&target).is_ok()
48 }
49}
50
51impl<'a> Deref for CollectedTargetsStrs<'a> {
52 type Target = [&'a str];
53
54 fn deref(&self) -> &Self::Target {
55 self.0.as_slice()
56 }
57}
58
59#[doc = include_str!("../examples/targets.rs")]
67pub fn from_cli() -> Result<Targets, std::io::Error> {
69 let output = Command::new("go")
70 .arg("tool")
71 .arg("dist")
72 .arg("list")
73 .output()?;
74
75 Ok(Targets(output.stdout))
76}