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
use std::error::Error as StdError;
use std::fmt;
use std::io::Error as IOError;

use tokio_dl_stream_to_disk::error::Error as TDSTDError;
use tokio_dl_stream_to_disk::error::ErrorKind as TDSTDErrorKind;

#[derive(Debug)]
pub enum ErrorKind {
    FileExists,
    DirectoryExists,
    DirectoryMissing,
    InvalidApp,
    Authentication,
    TermsOfService,
    PermissionDenied,
    InvalidResponse,
    LoginRequired,
    IO(IOError),
    Str(String),
    Other(Box<dyn StdError>),
}

#[derive(Debug)]
pub struct Error {
    kind: ErrorKind,
}

impl Error {
    pub fn new(k: ErrorKind) -> Error {
        Error { kind: k }
    }

    pub fn kind(&self) -> &ErrorKind {
        &self.kind
    }
}

impl From<IOError> for Error {
    fn from(err: IOError) -> Error {
        Error {
            kind: ErrorKind::IO(err),
        }
    }
}

impl From<Box<dyn StdError>> for Error {
    fn from(err: Box<dyn StdError>) -> Error {
        Error {
            kind: ErrorKind::Other(err),
        }
    }
}

impl From<TDSTDError> for Error {
    fn from(err: TDSTDError) -> Error {
        match err.kind() {
            TDSTDErrorKind::FileExists => Error {
                kind: ErrorKind::FileExists,
            },
            TDSTDErrorKind::DirectoryMissing => Error {
                kind: ErrorKind::DirectoryMissing,
            },
            TDSTDErrorKind::PermissionDenied => Error {
                kind: ErrorKind::PermissionDenied,
            },
            TDSTDErrorKind::InvalidResponse => Error {
                kind: ErrorKind::InvalidResponse,
            },
            TDSTDErrorKind::IO(_) => {
                let err = err.into_inner_io().unwrap();
                Error {
                    kind: ErrorKind::IO(err),
                }
            }
            TDSTDErrorKind::Other(_) => {
                let err = err.into_inner_other().unwrap();
                Error {
                    kind: ErrorKind::Other(err),
                }
            }
        }
    }
}

impl From<&str> for Error {
    fn from(err: &str) -> Error {
        Error {
            kind: ErrorKind::Str(err.to_string()),
        }
    }
}

impl From<String> for Error {
    fn from(err: String) -> Error {
        Error {
            kind: ErrorKind::Str(err),
        }
    }
}

impl StdError for Error {}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.kind() {
            ErrorKind::FileExists => write!(f, "File already exists"),
            ErrorKind::InvalidApp => write!(f, "Invalid app response"),
            ErrorKind::DirectoryExists => write!(f, "Directory already exists"),
            ErrorKind::DirectoryMissing => write!(f, "Destination path provided is not a valid directory"),
            ErrorKind::Authentication => write!(f, "Could not authenticate with Google. Please provide a new oAuth token."),
            ErrorKind::TermsOfService => write!(f, "Must accept Google Play Terms of Service before proceeding."),
            ErrorKind::PermissionDenied => write!(f, "Cannot create file: permission denied"),
            ErrorKind::InvalidResponse => write!(f, "Invalid response from the remote host"),
            ErrorKind::LoginRequired => write!(f, "Logging in is required for this action"),
            ErrorKind::IO(err) => err.fmt(f),
            ErrorKind::Str(err) => err.fmt(f),
            ErrorKind::Other(err) => err.fmt(f),
        }
    }
}