cargo_mobile2/
target.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::util;
use std::{
    collections::BTreeMap,
    fmt::{self, Debug, Display},
    process::ExitStatus,
};

pub trait TargetTrait<'a>: Debug + Sized {
    const DEFAULT_KEY: &'static str;

    fn all() -> &'a BTreeMap<&'a str, Self>;

    fn name_list() -> Vec<&'a str>;

    fn default_ref() -> &'a Self {
        Self::all()
            .get(Self::DEFAULT_KEY)
            .expect("developer error: no target matched `DEFAULT_KEY`")
    }

    fn for_name(name: &str) -> Option<&'a Self> {
        Self::all().get(name)
    }

    fn for_arch(arch: &str) -> Option<&'a Self> {
        Self::all().values().find(|target| target.arch() == arch)
    }

    fn triple(&'a self) -> &'a str;

    fn arch(&'a self) -> &'a str;

    fn install(&'a self) -> Result<ExitStatus, std::io::Error> {
        util::rustup_add(self.triple())
    }

    fn install_all() -> Result<(), std::io::Error>
    where
        Self: 'a,
    {
        for target in Self::all().values() {
            target.install()?;
        }
        Ok(())
    }
}

#[derive(Debug)]
pub struct TargetInvalid {
    pub(crate) name: String,
    pub(crate) possible: Vec<String>,
}

impl Display for TargetInvalid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "Target {:?} is invalid; the possible targets are {:?}",
            self.name, self.possible,
        )
    }
}

#[allow(clippy::type_complexity)]
pub fn get_targets<'a, Iter, I, T, U>(
    targets: Iter,
    // we use `dyn` so the type doesn't need to be known when this is `None`
    fallback: Option<(&'a dyn Fn(U) -> Option<&'a T>, U)>,
) -> Result<Vec<&'a T>, TargetInvalid>
where
    Iter: ExactSizeIterator<Item = &'a I>,
    I: AsRef<str> + 'a,
    T: TargetTrait<'a>,
{
    let targets_empty = targets.len() == 0;
    Ok(if !targets_empty {
        targets
            .map(|name| {
                T::for_name(name.as_ref()).ok_or_else(|| TargetInvalid {
                    name: name.as_ref().to_owned(),
                    possible: T::all().keys().map(|key| key.to_string()).collect(),
                })
            })
            .collect::<Result<_, _>>()?
    } else {
        let target = fallback
            .and_then(|(get_target, arg)| get_target(arg))
            .unwrap_or_else(|| {
                log::info!("falling back on default target ({})", T::DEFAULT_KEY);
                T::default_ref()
            });
        vec![target]
    })
}

pub fn call_for_targets_with_fallback<'a, Iter, I, T, U, E, F>(
    targets: Iter,
    fallback: &'a dyn Fn(U) -> Option<&'a T>,
    arg: U,
    mut f: F,
) -> Result<Result<(), E>, TargetInvalid>
where
    Iter: ExactSizeIterator<Item = &'a I>,
    I: AsRef<str> + 'a,
    T: TargetTrait<'a>,
    F: FnMut(&T) -> Result<(), E>,
{
    get_targets(targets, Some((fallback, arg))).map(|targets| {
        for target in targets {
            f(target)?;
        }
        Ok(())
    })
}

pub fn call_for_targets<'a, Iter, I, T, E, F>(
    targets: Iter,
    f: F,
) -> Result<Result<(), E>, TargetInvalid>
where
    Iter: ExactSizeIterator<Item = &'a I>,
    I: AsRef<str> + 'a,
    T: TargetTrait<'a> + 'a,
    F: Fn(&T) -> Result<(), E>,
{
    get_targets::<_, _, _, ()>(targets, None).map(|targets| {
        for target in targets {
            f(target)?;
        }
        Ok(())
    })
}