1use super::{
18 env_types::EnvTypesTranscoder,
19 scon::Value,
20 CompositeTypeFields,
21};
22use anyhow::Result;
23use itertools::Itertools;
24use scale::{
25 Compact,
26 Encode,
27 Output,
28};
29use scale_info::{
30 form::{
31 Form,
32 PortableForm,
33 },
34 Field,
35 PortableRegistry,
36 TypeDef,
37 TypeDefCompact,
38 TypeDefPrimitive,
39 TypeDefTuple,
40 TypeDefVariant,
41};
42use std::{
43 convert::{
44 TryFrom,
45 TryInto,
46 },
47 error::Error,
48 fmt::Debug,
49 str::FromStr,
50};
51
52pub struct Encoder<'a> {
53 registry: &'a PortableRegistry,
54 env_types: &'a EnvTypesTranscoder,
55}
56
57impl<'a> Encoder<'a> {
58 pub fn new(
59 registry: &'a PortableRegistry,
60 env_types: &'a EnvTypesTranscoder,
61 ) -> Self {
62 Self {
63 registry,
64 env_types,
65 }
66 }
67
68 pub fn encode<O>(&self, type_id: u32, value: &Value, output: &mut O) -> Result<()>
69 where
70 O: Output + Debug,
71 {
72 let ty = self.registry.resolve(type_id).ok_or_else(|| {
73 anyhow::anyhow!("Failed to resolve type with id '{:?}'", type_id)
74 })?;
75
76 tracing::debug!(
77 "Encoding value `{:?}` with type id `{:?}` and definition `{:?}`",
78 value,
79 type_id,
80 ty.type_def,
81 );
82 if !self.env_types.try_encode(type_id, value, output)? {
83 match &ty.type_def {
84 TypeDef::Composite(composite) => {
85 self.encode_composite(&composite.fields, value, output)
86 }
87 TypeDef::Variant(variant) => {
88 self.encode_variant_type(variant, value, output)
89 }
90 TypeDef::Array(array) => {
91 self.encode_seq(&array.type_param, value, false, output)
92 }
93 TypeDef::Tuple(tuple) => self.encode_tuple(tuple, value, output),
94 TypeDef::Sequence(sequence) => {
95 self.encode_seq(&sequence.type_param, value, true, output)
96 }
97 TypeDef::Primitive(primitive) => {
98 self.encode_primitive(primitive, value, output)
99 }
100 TypeDef::Compact(compact) => self.encode_compact(compact, value, output),
101 TypeDef::BitSequence(_) => {
102 Err(anyhow::anyhow!("bitvec encoding not yet supported"))
103 }
104 }?;
105 }
106 Ok(())
107 }
108
109 fn encode_composite<O: Output + Debug>(
110 &self,
111 fields: &[Field<PortableForm>],
112 value: &Value,
113 output: &mut O,
114 ) -> Result<()> {
115 let struct_type = CompositeTypeFields::from_fields(fields)?;
116
117 match value {
118 Value::Map(map) => {
119 match struct_type {
120 CompositeTypeFields::Unnamed(fields) => {
121 for (field, value) in fields.iter().zip(map.values()) {
122 self.encode(field.ty.id, value, output)?;
123 }
124 Ok(())
125 }
126 CompositeTypeFields::NoFields => Ok(()),
127 CompositeTypeFields::Named(named_fields) => {
128 for named_field in named_fields {
129 let field_name = named_field.name();
130 let value = map.get_by_str(field_name).ok_or_else(|| {
131 anyhow::anyhow!("Missing a field named `{}`", field_name)
132 })?;
133 self.encode(named_field.field().ty.id, value, output)
134 .map_err(|e| {
135 anyhow::anyhow!(
136 "Error encoding field `{}`: {}",
137 field_name,
138 e
139 )
140 })?;
141 }
142 Ok(())
143 }
144 }
145 }
146 Value::Tuple(tuple) => {
147 match struct_type {
148 CompositeTypeFields::Unnamed(fields) => {
149 for (field, value) in fields.iter().zip(tuple.values()) {
150 self.encode(field.ty.id, value, output)?;
151 }
152 Ok(())
153 }
154 CompositeTypeFields::NoFields => Ok(()),
155 CompositeTypeFields::Named(_) => {
156 Err(anyhow::anyhow!("Type is a struct requiring named fields"))
157 }
158 }
159 }
160 v => {
161 if let Ok(single_field) = fields.iter().exactly_one() {
162 self.encode(single_field.ty.id, value, output)
163 } else {
164 Err(anyhow::anyhow!(
165 "Expected a Map or a Tuple or a single Value for a composite data type, found {:?}",
166 v
167 ))
168 }
169 }
170 }
171 }
172
173 fn encode_tuple<O: Output + Debug>(
174 &self,
175 tuple: &TypeDefTuple<PortableForm>,
176 value: &Value,
177 output: &mut O,
178 ) -> Result<()> {
179 match value {
180 Value::Tuple(tuple_val) => {
181 for (field_type, value) in tuple.fields.iter().zip(tuple_val.values()) {
182 self.encode(field_type.id, value, output)?;
183 }
184 Ok(())
185 }
186 v => {
187 if let Ok(single_field) = tuple.fields.iter().exactly_one() {
188 self.encode(single_field.id, value, output)
189 } else {
190 Err(anyhow::anyhow!(
191 "Expected a Tuple or a single Value for a tuple data type, found {:?}",
192 v
193 ))
194 }
195 }
196 }
197 }
198
199 fn encode_variant_type<O: Output + Debug>(
200 &self,
201 variant_def: &TypeDefVariant<PortableForm>,
202 value: &Value,
203 output: &mut O,
204 ) -> Result<()> {
205 let variant_ident = match value {
206 Value::Map(map) => {
207 map.ident().ok_or_else(|| {
208 anyhow::anyhow!("Missing enum variant identifier for map")
209 })
210 }
211 Value::Tuple(tuple) => {
212 tuple.ident().ok_or_else(|| {
213 anyhow::anyhow!("Missing enum variant identifier for tuple")
214 })
215 }
216 v => Err(anyhow::anyhow!("Invalid enum variant value '{:?}'", v)),
217 }?;
218
219 let (index, variant) = variant_def
220 .variants
221 .iter()
222 .find_position(|v| v.name == variant_ident)
223 .ok_or_else(|| anyhow::anyhow!("No variant '{}' found", variant_ident))?;
224
225 let index: u8 = index
226 .try_into()
227 .map_err(|_| anyhow::anyhow!("Variant index > 255"))?;
228 output.push_byte(index);
229
230 self.encode_composite(&variant.fields, value, output)
231 }
232
233 fn encode_seq<O: Output + Debug>(
234 &self,
235 ty: &<PortableForm as Form>::Type,
236 value: &Value,
237 encode_len: bool,
238 output: &mut O,
239 ) -> Result<()> {
240 match value {
241 Value::Seq(values) => {
242 if encode_len {
243 Compact(values.len() as u32).encode_to(output);
244 }
245 for value in values.elems() {
246 self.encode(ty.id, value, output)?;
247 }
248 }
249 Value::Hex(hex) => {
250 if encode_len {
251 Compact(hex.bytes().len() as u32).encode_to(output);
252 }
253 for byte in hex.bytes() {
254 output.push_byte(*byte);
255 }
256 }
257 value => {
258 return Err(anyhow::anyhow!("{:?} cannot be encoded as an array", value))
259 }
260 }
261 Ok(())
262 }
263
264 fn encode_primitive<O: Output + Debug>(
265 &self,
266 primitive: &TypeDefPrimitive,
267 value: &Value,
268 output: &mut O,
269 ) -> Result<()> {
270 match primitive {
271 TypeDefPrimitive::Bool => {
272 if let Value::Bool(b) = value {
273 b.encode_to(output);
274 Ok(())
275 } else {
276 Err(anyhow::anyhow!("Expected a bool value"))
277 }
278 }
279 TypeDefPrimitive::Char => {
280 Err(anyhow::anyhow!("scale codec not implemented for char"))
281 }
282 TypeDefPrimitive::Str => {
283 if let Value::String(s) = value {
284 s.encode_to(output);
285 Ok(())
286 } else {
287 Err(anyhow::anyhow!("Expected a String value\n\
288 On the command-line, String values need to be wrapped in escaped quotes: \
289 \\\"…\\\"."))
290 }
291 }
292 TypeDefPrimitive::U8 => encode_uint::<u8, O>(value, "u8", output),
293 TypeDefPrimitive::U16 => encode_uint::<u16, O>(value, "u16", output),
294 TypeDefPrimitive::U32 => encode_uint::<u32, O>(value, "u32", output),
295 TypeDefPrimitive::U64 => encode_uint::<u64, O>(value, "u64", output),
296 TypeDefPrimitive::U128 => encode_uint::<u128, O>(value, "u128", output),
297 TypeDefPrimitive::U256 => {
298 Err(anyhow::anyhow!("U256 currently not supported"))
299 }
300 TypeDefPrimitive::I8 => encode_int::<i8, O>(value, "i8", output),
301 TypeDefPrimitive::I16 => encode_int::<i16, O>(value, "i16", output),
302 TypeDefPrimitive::I32 => encode_int::<i32, O>(value, "i32", output),
303 TypeDefPrimitive::I64 => encode_int::<i64, O>(value, "i64", output),
304 TypeDefPrimitive::I128 => encode_int::<i128, O>(value, "i128", output),
305 TypeDefPrimitive::I256 => {
306 Err(anyhow::anyhow!("I256 currently not supported"))
307 }
308 }
309 }
310
311 fn encode_compact<O: Output + Debug>(
312 &self,
313 compact: &TypeDefCompact<PortableForm>,
314 value: &Value,
315 output: &mut O,
316 ) -> Result<()> {
317 let mut encode_compact_primitive =
318 |primitive: &TypeDefPrimitive, value: &Value| {
319 match primitive {
320 TypeDefPrimitive::U8 => {
321 let uint = uint_from_value::<u8>(value, "u8")?;
322 Compact(uint).encode_to(output);
323 Ok(())
324 }
325 TypeDefPrimitive::U16 => {
326 let uint = uint_from_value::<u16>(value, "u16")?;
327 Compact(uint).encode_to(output);
328 Ok(())
329 }
330 TypeDefPrimitive::U32 => {
331 let uint = uint_from_value::<u32>(value, "u32")?;
332 Compact(uint).encode_to(output);
333 Ok(())
334 }
335 TypeDefPrimitive::U64 => {
336 let uint = uint_from_value::<u64>(value, "u64")?;
337 Compact(uint).encode_to(output);
338 Ok(())
339 }
340 TypeDefPrimitive::U128 => {
341 let uint = uint_from_value::<u128>(value, "u128")?;
342 Compact(uint).encode_to(output);
343 Ok(())
344 }
345 _ => {
346 Err(anyhow::anyhow!(
347 "Compact encoding not supported for {:?}",
348 primitive
349 ))
350 }
351 }
352 };
353
354 let ty = self
355 .registry
356 .resolve(compact.type_param.id)
357 .ok_or_else(|| {
358 anyhow::anyhow!(
359 "Failed to resolve type with id '{:?}'",
360 compact.type_param.id
361 )
362 })?;
363 match &ty.type_def {
364 TypeDef::Primitive(primitive) => encode_compact_primitive(primitive, value),
365 TypeDef::Composite(composite) => {
366 match &composite.fields[..] {
367 [field] => {
368 let type_id = field.ty.id;
369 let field_ty =
370 self.registry.resolve(type_id).ok_or_else(|| {
371 anyhow::anyhow!(
372 "Failed to resolve type with id `{:?}`",
373 type_id
374 )
375 })?;
376 if let TypeDef::Primitive(primitive) = &field_ty.type_def {
377 let field_values: Vec<_> = match value {
378 Value::Map(map) => Ok(map.values().collect()),
379 Value::Tuple(tuple) => Ok(tuple.values().collect()),
380 x => Err(anyhow::anyhow!(
381 "Compact composite value must be a Map or a Tuple. Found {}",
382 x
383 )),
384 }?;
385 if field_values.len() == 1 {
386 let field_value = field_values[0];
387 encode_compact_primitive(primitive, field_value)
388 } else {
389 Err(anyhow::anyhow!(
390 "Compact composite value must have a single field"
391 ))
392 }
393 } else {
394 Err(anyhow::anyhow!(
395 "Composite type must have a single primitive field"
396 ))
397 }
398 }
399 _ => Err(anyhow::anyhow!("Composite type must have a single field")),
400 }
401 }
402 _ => {
403 Err(anyhow::anyhow!(
404 "Compact type must be a primitive or a composite type"
405 ))
406 }
407 }
408 }
409}
410
411fn uint_from_value<T>(value: &Value, expected: &str) -> Result<T>
412where
413 T: TryFrom<u128> + TryFromHex + FromStr,
414 <T as TryFrom<u128>>::Error: Error + Send + Sync + 'static,
415 <T as FromStr>::Err: Error + Send + Sync + 'static,
416{
417 match value {
418 Value::UInt(i) => {
419 let uint = (*i).try_into()?;
420 Ok(uint)
421 }
422 Value::String(s) => {
423 let sanitized = s.replace(&['_', ','][..], "");
424 let uint = T::from_str(&sanitized)?;
425 Ok(uint)
426 }
427 Value::Hex(hex) => {
428 let uint = T::try_from_hex(hex.as_str())?;
429 Ok(uint)
430 }
431 _ => {
432 Err(anyhow::anyhow!(
433 "Expected a {} or a String value, got {}",
434 expected,
435 value
436 ))
437 }
438 }
439}
440
441fn encode_uint<T, O>(value: &Value, expected: &str, output: &mut O) -> Result<()>
442where
443 T: TryFrom<u128> + TryFromHex + FromStr + Encode,
444 <T as TryFrom<u128>>::Error: Error + Send + Sync + 'static,
445 <T as FromStr>::Err: Error + Send + Sync + 'static,
446 O: Output,
447{
448 let uint: T = uint_from_value(value, expected)?;
449 uint.encode_to(output);
450 Ok(())
451}
452
453fn encode_int<T, O>(value: &Value, expected: &str, output: &mut O) -> Result<()>
454where
455 T: TryFrom<i128> + TryFrom<u128> + FromStr + Encode,
456 <T as TryFrom<i128>>::Error: Error + Send + Sync + 'static,
457 <T as TryFrom<u128>>::Error: Error + Send + Sync + 'static,
458 <T as FromStr>::Err: Error + Send + Sync + 'static,
459 O: Output,
460{
461 let int = match value {
462 Value::Int(i) => {
463 let i: T = (*i).try_into()?;
464 Ok(i)
465 }
466 Value::UInt(u) => {
467 let i: T = (*u).try_into()?;
468 Ok(i)
469 }
470 Value::String(s) => {
471 let sanitized = s.replace(&['_', ','][..], "");
472 let i = T::from_str(&sanitized)?;
473 Ok(i)
474 }
475 _ => {
476 Err(anyhow::anyhow!(
477 "Expected a {} or a String value, got {}",
478 expected,
479 value
480 ))
481 }
482 }?;
483 int.encode_to(output);
484 Ok(())
485}
486
487pub trait TryFromHex: Sized {
489 fn try_from_hex(hex: &str) -> Result<Self>;
491}
492
493macro_rules! impl_try_from_hex {
494 ( $($ty:ident),* ) => { $(
495 impl TryFromHex for $ty {
496 fn try_from_hex(hex: &str) -> Result<Self> {
497 $ty::from_str_radix(hex, 16).map_err(Into::into)
498 }
499 }
500 )* }
501}
502
503impl_try_from_hex!(u8, u16, u32, u64, u128);