cargo_mobile2/
device.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
use crate::util::cli::{Report, Reportable};
use std::{
    error::Error,
    fmt::{self, Debug, Display},
    io,
};

#[derive(Debug, thiserror::Error)]
pub enum PromptErrorCause<T: Display> {
    #[error(transparent)]
    DetectionFailed(T),
    #[error(transparent)]
    PromptFailed(io::Error),
    #[error("No connected devices detected")]
    NoneDetected,
}

#[derive(Debug)]
pub struct PromptError<T: Display> {
    name: &'static str,
    cause: PromptErrorCause<T>,
}

impl<T: Display> Display for PromptError<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match &self.cause {
            PromptErrorCause::DetectionFailed(err) => write!(f, "{}", err),
            PromptErrorCause::PromptFailed(err) => {
                write!(f, "Failed to prompt for {} device: {}", self.name, err)
            }
            PromptErrorCause::NoneDetected => write!(
                f,
                "Failed to prompt for {} device: No connected devices detected",
                self.name
            ),
        }
    }
}

impl<T: Debug + Display> Error for PromptError<T> {}

impl<T: Debug + Display> Reportable for PromptError<T> {
    fn report(&self) -> Report {
        match &self.cause {
            PromptErrorCause::DetectionFailed(err) => {
                Report::error("failed to detect devices", err)
            }
            PromptErrorCause::PromptFailed(err) => {
                Report::error(format!("Failed to prompt for {} device", self.name), err)
            }
            PromptErrorCause::NoneDetected => Report::error(
                format!("Failed to prompt for {} device", self.name),
                format!("No connected {} devices detected", self.name),
            ),
        }
    }
}

impl<T: Debug + Display> PromptError<T> {
    pub fn new(name: &'static str, cause: PromptErrorCause<T>) -> Self {
        Self { name, cause }
    }

    pub fn detection_failed(name: &'static str, err: T) -> Self {
        Self::new(name, PromptErrorCause::DetectionFailed(err))
    }

    pub fn prompt_failed(name: &'static str, err: io::Error) -> Self {
        Self::new(name, PromptErrorCause::PromptFailed(err))
    }

    pub fn none_detected(name: &'static str) -> Self {
        Self::new(name, PromptErrorCause::NoneDetected)
    }
}

#[macro_export]
macro_rules! define_device_prompt {
    ($func:path, $e:ty, $name:ident) => {
        fn device_prompt<'a>(env: &'_ Env) -> Result<Device<'a>, $crate::device::PromptError<$e>> {
            let device_list = $func(env).map_err(|cause| {
                $crate::device::PromptError::detection_failed(stringify!($name), cause)
            })?;
            if device_list.len() > 0 {
                let index = if device_list.len() > 1 {
                    prompt::list(
                        concat!("Detected ", stringify!($name), " devices"),
                        device_list.iter(),
                        "device",
                        None,
                        "Device",
                    )
                    .map_err(|cause| {
                        $crate::device::PromptError::prompt_failed(stringify!($name), cause)
                    })?
                } else {
                    0
                };
                let device = device_list.into_iter().nth(index).unwrap();
                println!(
                    "Detected connected device: {} with target {:?}",
                    device,
                    device.target().triple,
                );
                Ok(device)
            } else {
                Err($crate::device::PromptError::none_detected(stringify!(
                    $name
                )))
            }
        }
    };
}