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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//! Error types and implementations for [Invocation] interaction(s).
//!
//! [Invocation]: crate::Invocation

use crate::{
    task::instruction::{Args, Input},
    Unit,
};
use libipld::Ipld;
use serde::de::Error as DeError;
use std::io;

/// Generic error type for [Invocation] use cases.
///
/// [Invocation]: crate::Invocation
#[derive(thiserror::Error, Debug)]
pub enum Error<T> {
    /// Error encoding structure to a [Cid].
    ///
    /// [Cid]: libipld::cid::Cid
    #[error("failed to encode CID: {0}")]
    CidEncode(#[from] libipld::cid::Error),
    /// Error thrown when condition or dynamic check is not met.
    #[error("condition not met: {0}")]
    ConditionNotMet(String),
    /// Failure to decode/encode from/to DagCbor.
    ///
    /// The underlying error is a [anyhow::Error], per the
    /// [DagCborCodec] implementation.
    ///
    /// [DagCborCodec]: libipld::cbor::DagCborCodec
    #[error("failed to decode/encode DAG-CBOR: {0}")]
    DagCborTranslation(#[from] anyhow::Error),
    /// Error converting from [Ipld] structure via [serde].
    ///
    /// Transparently forwards from [libipld::error::SerdeError]'s `source` and
    /// `Display` methods through to an underlying error.
    #[error("cannot convert from Ipld structure: {0}")]
    FromIpld(#[from] libipld::error::SerdeError),
    /// Invalid match discriminant or enumeration.
    #[error("invalid discriminant {0:#?}")]
    InvalidDiscriminant(T),
    /// Error related to a missing a field in a structure or key
    /// in a map.
    #[error("no {0} field set")]
    MissingField(String),
    /// Error during parsing a [Url].
    ///
    /// Transparently forwards from [url::ParseError]'s `source` and
    /// `Display` methods through to an underlying error.
    ///
    /// [Url]: url::Url
    #[error(transparent)]
    ParseResource(#[from] url::ParseError),
    /// Generic unknown error.
    #[error("unknown error")]
    Unknown,
    /// Unexpcted [Ipld] type.
    #[error("unexpected Ipld type: {0:#?}")]
    UnexpectedIpldType(Ipld),
    /// Error when attempting to interpret a sequence of [u8]
    /// as a string.
    ///
    /// Transparently forwards from [std::str::Utf8Error]'s `source` and
    /// `Display` methods through to an underlying error.
    #[error(transparent)]
    Utf8(#[from] std::str::Utf8Error),
    /// Propagated IO error.
    #[error("error writing data to console: {0}")]
    Io(#[from] io::Error),
}

impl<T> Error<T> {
    /// Return a [SerdeError] when returning an [Ipld] structure
    /// that's not expected at the call-site.
    ///
    /// [SerdeError]: libipld::error::SerdeError
    pub fn unexpected_ipld(ipld: Ipld) -> Self {
        Error::UnexpectedIpldType(ipld)
    }

    /// Return an `invalid type` [SerdeError] when not matching an expected
    /// [Ipld] list/sequence type.
    ///
    /// [SerdeError]: libipld::error::SerdeError
    pub fn not_an_ipld_list() -> Self {
        Error::FromIpld(libipld::error::SerdeError::invalid_type(
            serde::de::Unexpected::Seq,
            &"an Ipld list / sequence",
        ))
    }
}

impl From<Error<Unit>> for Error<String> {
    fn from(_err: Error<Unit>) -> Self {
        Error::Unknown
    }
}

impl From<Error<String>> for Error<Unit> {
    fn from(_err: Error<String>) -> Error<Unit> {
        Error::Unknown
    }
}

impl<T> From<std::convert::Infallible> for Error<T> {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}

/// Error type for parsing [Invocation] [Input]s.
///
/// [Invocation]: crate::Invocation
#[derive(thiserror::Error, Debug)]
pub enum InputParseError<T> {
    /// Error converting from [Ipld] structure via [serde].
    ///
    /// Transparently forwards from [libipld::error::SerdeError]'s `source` and
    /// `Display` methods through to an underlying error.
    #[error("cannot convert from Ipld structure: {0}")]
    FromIpld(#[from] libipld::error::SerdeError),
    /// Error converting from [Ipld] structure into [Args].
    #[error("cannot convert from Ipld structure into arguments: {0:#?}")]
    IpldToArgs(Args<T>),
    /// Unexpected [Input] in [Task] structure.
    ///
    /// [Task]: crate::Task
    #[error("unexpected task input: {0:#?}")]
    UnexpectedTaskInput(Input<T>),
    /// Bubble-up conversion and other general [Invocation errors].
    ///
    /// [Invocation errors]: Error
    #[error(transparent)]
    Invocation(#[from] Error<T>),
}

impl<T> From<std::convert::Infallible> for InputParseError<T> {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}

/// Error type for resolving promised [Cid]s within [Invocation] [Input]s.
///
/// [Cid]: libipld::Cid
/// [Invocation]: crate::Invocation
#[derive(thiserror::Error, Debug)]
pub enum ResolveError {
    /// Generic runtime error.
    ///
    /// Transparently forwards from [anyhow::Error]'s `source` and
    /// `Display` methods through to an underlying error.
    #[error(transparent)]
    Runtime(#[from] anyhow::Error),
    /// Transport error when attempting to resolve [Invocation] [Input]'s [Cid].
    ///
    /// [Cid]: libipld::Cid
    /// [Invocation]: crate::Invocation
    #[error("transport error during resolve phase of input Cid: {0}")]
    Transport(String),
    /// Unable to resolve a [Cid] within an [Invocation]'s [Input].
    ///
    /// [Cid]: libipld::Cid
    /// [Invocation]: crate::Invocation
    #[error("error resolving input Cid: {0}")]
    UnresolvedCid(String),
}

impl From<std::convert::Infallible> for ResolveError {
    fn from(err: std::convert::Infallible) -> Self {
        match err {}
    }
}