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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
use std::num::ParseIntError;
use serde_json::Value;
use thiserror::Error;
#[cfg(doc)]
use casper_types::{account::AccountHash, CLValue, Key, NamedArg, PublicKey, URef};
use casper_types::{
bytesrepr::Error as BytesreprError, crypto::Error as CryptoError, CLType, KeyFromStrError,
URefFromStrError,
};
/// Error associated with parsing a JSON arg into a [`NamedArg`].
#[derive(Error, Debug)]
#[error(
"failed to construct a CLValue of type {cl_type:?} from {json_value} for arg {arg_name}: \
{details}"
)]
pub struct Error {
/// The name of the relevant argument.
pub arg_name: String,
/// The `CLType` into which the value should be parsed.
pub cl_type: CLType,
/// The JSON value from which parsing failed.
pub json_value: Value,
/// Details of the error.
pub details: ErrorDetails,
}
impl Error {
pub(super) fn new(
arg_name: String,
cl_type: CLType,
json_value: Value,
details: ErrorDetails,
) -> Self {
Error {
arg_name,
cl_type,
json_value,
details,
}
}
}
/// Details of an error associated with parsing a JSON arg into a [`NamedArg`].
#[derive(Error, Debug)]
pub enum ErrorDetails {
/// bytesrepr error while constructing a [`CLValue`].
#[error("failed bytesrepr encoding: {0}")]
Bytesrepr(BytesreprError),
/// Cannot convert the given JSON Number to an `i32`.
#[error("cannot convert given JSON Number to `i32`")]
CannotParseToI32,
/// Cannot convert the given JSON Number to an `i64`.
#[error("cannot convert given JSON Number to `i64`")]
CannotParseToI64,
/// Cannot convert the given JSON Number to a `u8`.
#[error("cannot convert given JSON Number to `u8`")]
CannotParseToU8,
/// Cannot convert the given JSON Number to a `u32`.
#[error("cannot convert given JSON Number to `u32`")]
CannotParseToU32,
/// Cannot convert the given JSON Number to a `u64`.
#[error("cannot convert given JSON Number to `u64`")]
CannotParseToU64,
/// Error parsing an integer from a decimal string representation.
#[error(transparent)]
ParseInt(#[from] ParseIntError),
/// Error parsing a big integer from a decimal string representation.
#[error(transparent)]
ParseBigint(#[from] uint::FromDecStrErr),
/// Error parsing a [`Key`] from a formatted string representation.
#[error("failed parsing a Key: {0}")]
ParseKeyFromString(KeyFromStrError),
/// JSON Object representing a [`Key`] must have the structure
/// `{"<KEY VARIANT>":"<KEY AS FORMATTED STRING>"}`, but the given one does not have just one
/// field.
#[error(
"invalid number of fields: JSON Object representing a Key must have exactly one field, the \
name of the Key variant mapped to the Key as a formatted string"
)]
KeyObjectHasInvalidNumberOfFields,
/// JSON Object representing a [`Key`] must have the structure
/// `{"<KEY VARIANT>":"<KEY AS FORMATTED STRING>"}`, but the given one does not have a String
/// value.
#[error(
"invalid field type: JSON Object representing a Key must have exactly one field, the name \
of the Key variant mapped to the Key as a formatted string"
)]
KeyObjectHasInvalidFieldType,
/// JSON Object representing a [`Key`] must have the structure
/// `{"<KEY VARIANT>":"<KEY AS FORMATTED STRING>"}`, but the given one does match any valid
/// `Key` variant.
#[error(
"invalid Key variant: JSON Object representing a Key must have exactly one field, the name \
of the Key variant mapped to the Key as a formatted string"
)]
KeyObjectHasInvalidVariant,
/// Error parsing a [`URef`] from a formatted string representation.
#[error("failed parsing a URef: {0}")]
ParseURef(URefFromStrError),
/// Error parsing a [`PublicKey`] from a formatted string representation.
#[error(transparent)]
ParsePublicKey(#[from] CryptoError),
/// Error parsing a hex string.
#[error(transparent)]
HexDecode(#[from] base16::DecodeError),
/// Number of hex-decoded bytes not as expected.
#[error("number of hex-decoded bytes ({actual_length}) not as expected ({expected_length})")]
ByteArrayLengthMismatch {
/// The expected number of bytes.
expected_length: u32,
/// The actual number of bytes.
actual_length: u32,
},
/// JSON Object representing a `Result` must have the structure `{"Ok":<VALUE>}` or
/// `{"Err":<VALUE>}`, but the given one does not have just one field.
#[error(
"invalid number of fields: JSON Object representing a Result must have exactly one field \
named 'Ok' or 'Err'"
)]
ResultObjectHasInvalidNumberOfFields,
/// JSON Object representing a `Result` must have the structure `{"Ok":<VALUE>}` or
/// `{"Err":<VALUE>}`, but the given one is neither `"Ok"` nor `"Err"`.
#[error(
"invalid Result variant: JSON Object representing a Result must have exactly one field \
named 'Ok' or 'Err'"
)]
ResultObjectHasInvalidVariant,
/// `CLType::Map`s can only be represented as JSON Objects if the map's key type is a string or
/// number.
#[error(
"invalid map key type ({0:?}): only maps with key types of string or number can be \
represented as JSON Objects, maps with more complex key types must use a JSON Array"
)]
MapTypeNotValidAsObject(CLType),
/// JSON Array representing a `CLType::Map` must have all entries with the structure
/// `{"key":<VALUE>,"value":<VALUE>}`, but the given one has an entry which is not an Object.
#[error("invalid entry type: JSON Array representing a Map must have all entries as Objects")]
MapArrayHasInvalidEntryType,
/// JSON Object representing a map entry must have the structure
/// `{"key":<VALUE>,"value":<VALUE>}`, but the given one does not have exactly two fields.
#[error(
"invalid number of fields: JSON Object representing a Map entry must have exactly two \
fields, named 'key' and 'value'"
)]
MapEntryObjectHasInvalidNumberOfFields,
/// JSON Object representing a map entry must have the structure
/// `{"key":<VALUE>,"value":<VALUE>}`, but the given one does not have `"key"`.
#[error(
"missing key field: JSON Object representing a Map entry must have exactly two fields, \
named 'key' and 'value'"
)]
MapEntryObjectMissingKeyField,
/// JSON Object representing a map entry must have the structure
/// `{"key":<VALUE>,"value":<VALUE>}`, but the given one does not have `"value"`.
#[error(
"missing value field: JSON Object representing a Map entry must have exactly two fields, \
named 'key' and 'value'"
)]
MapEntryObjectMissingValueField,
/// Number of tuple entries not as expected.
#[error("number of tuple entries ({actual}) not as expected ({expected})")]
TupleEntryCountMismatch {
/// The expected number of tuple entries.
expected: usize,
/// The actual number of tuple entries.
actual: usize,
},
/// The given `CLType` fundamentally cannot be constructed from the given type of JSON value.
#[error("the given CLType cannot be constructed from the given type of JSON value")]
IncompatibleType,
}
impl From<KeyFromStrError> for ErrorDetails {
fn from(error: KeyFromStrError) -> Self {
ErrorDetails::ParseKeyFromString(error)
}
}
impl From<URefFromStrError> for ErrorDetails {
fn from(error: URefFromStrError) -> Self {
ErrorDetails::ParseURef(error)
}
}
impl From<BytesreprError> for ErrorDetails {
fn from(error: BytesreprError) -> Self {
ErrorDetails::Bytesrepr(error)
}
}