scale_serialization/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2///!
3///! # Scales
4///!
5///! Dynamic SCALE Serialization using `scale-info` type information.
6#[macro_use]
7extern crate alloc;
8
9#[cfg(feature = "experimental-serializer")]
10mod serializer;
11mod value;
12
13pub use bytes::Bytes;
14#[cfg(feature = "json")]
15pub use serde_json::Value as JsonValue;
16#[cfg(feature = "experimental-serializer")]
17pub use serializer::{to_bytes, to_bytes_with_info, to_vec, to_vec_with_info, Serializer};
18pub use value::Value;
19
20use prelude::*;
21use scale_info::{form::PortableForm as Portable, PortableRegistry};
22
23mod prelude {
24    pub use alloc::{
25        collections::BTreeMap,
26        string::{String, ToString},
27        vec::Vec,
28    };
29    pub use core::ops::Deref;
30}
31
32type Type = scale_info::Type<Portable>;
33type Field = scale_info::Field<Portable>;
34type Variant = scale_info::Variant<Portable>;
35type TypeId = u32;
36
37macro_rules! is_tuple {
38    ($it:ident) => {
39        $it.fields().first().and_then(Field::name).is_none()
40    };
41}
42
43/// A convenient representation of the scale-info types to a format
44/// that matches serde model more closely
45#[rustfmt::skip]
46#[derive(Debug, Clone, serde::Serialize)]
47#[cfg_attr(feature = "codec", derive(codec::Encode))]
48pub enum SpecificType {
49    Bool,
50    U8, U16, U32, U64, U128,
51    I8, I16, I32, I64, I128,
52    Bytes,
53    Char,
54    Str,
55    Sequence(TypeId),
56    Map(TypeId, TypeId),
57    Tuple(TupleOrArray),
58    Struct(Vec<(String, TypeId)>), StructUnit, StructNewType(TypeId), StructTuple(Vec<TypeId>),
59    Variant(String, Vec<Variant>, Option<u8>),
60}
61
62impl From<(&Type, &PortableRegistry)> for SpecificType {
63    fn from((ty, registry): (&Type, &PortableRegistry)) -> Self {
64        use scale_info::{TypeDef, TypeDefComposite, TypeDefPrimitive};
65        type Def = TypeDef<Portable>;
66
67        macro_rules! resolve {
68            ($ty:expr) => {
69                registry.resolve($ty.id()).unwrap()
70            };
71        }
72        let is_map = |ty: &Type| -> bool { ty.path().segments() == ["BTreeMap"] };
73        let map_types = |ty: &TypeDefComposite<Portable>| -> (TypeId, TypeId) {
74            let field = ty.fields().first().expect("map");
75            // Type information of BTreeMap is weirdly packed
76            if let Def::Sequence(s) = resolve!(field.ty()).type_def() {
77                if let Def::Tuple(t) = resolve!(s.type_param()).type_def() {
78                    assert_eq!(t.fields().len(), 2);
79                    let key_ty = t.fields().first().expect("key").id();
80                    let val_ty = t.fields().last().expect("val").id();
81                    return (key_ty, val_ty);
82                }
83            }
84            unreachable!()
85        };
86
87        let name = ty
88            .path()
89            .segments()
90            .last()
91            .cloned()
92            .unwrap_or_else(|| "".into());
93
94        match ty.type_def() {
95            Def::Composite(c) => {
96                let fields = c.fields();
97                if fields.is_empty() {
98                    Self::StructUnit
99                } else if is_map(ty) {
100                    let (k, v) = map_types(c);
101                    Self::Map(k, v)
102                } else if fields.len() == 1 && fields.first().unwrap().name().is_none() {
103                    Self::StructNewType(fields.first().unwrap().ty().id())
104                } else if is_tuple!(c) {
105                    Self::StructTuple(fields.iter().map(|f| f.ty().id()).collect())
106                } else {
107                    Self::Struct(
108                        fields
109                            .iter()
110                            .map(|f| (f.name().unwrap().deref().into(), f.ty().id()))
111                            .collect(),
112                    )
113                }
114            }
115            Def::Variant(v) => Self::Variant(name.into(), v.variants().into(), None),
116            Def::Sequence(s) => {
117                let ty = resolve!(s.type_param());
118                if ty.path().segments() != ["u8"] {
119                    Self::Sequence(s.type_param().id())
120                } else {
121                    Self::Bytes
122                }
123            }
124            Def::Array(a) => Self::Tuple(TupleOrArray::Array(a.type_param().id(), a.len())),
125            Def::Tuple(t) => Self::Tuple(TupleOrArray::Tuple(
126                t.fields().iter().map(|ty| ty.id()).collect(),
127            )),
128            Def::Primitive(p) => match p {
129                TypeDefPrimitive::U8 => Self::U8,
130                TypeDefPrimitive::U16 => Self::U16,
131                TypeDefPrimitive::U32 => Self::U32,
132                TypeDefPrimitive::U64 => Self::U64,
133                TypeDefPrimitive::U128 => Self::U128,
134                TypeDefPrimitive::I8 => Self::I8,
135                TypeDefPrimitive::I16 => Self::I16,
136                TypeDefPrimitive::I32 => Self::I32,
137                TypeDefPrimitive::I64 => Self::I64,
138                TypeDefPrimitive::I128 => Self::I128,
139                TypeDefPrimitive::Bool => Self::Bool,
140                TypeDefPrimitive::Str => Self::Str,
141                TypeDefPrimitive::Char => Self::Char,
142                TypeDefPrimitive::U256 => unimplemented!(),
143                TypeDefPrimitive::I256 => unimplemented!(),
144            },
145            Def::Compact(_c) => todo!(),
146            Def::BitSequence(_b) => todo!(),
147        }
148    }
149}
150
151// Utilities for enum variants
152impl SpecificType {
153    fn pick(&self, index: u8) -> Self {
154        match self {
155            SpecificType::Variant(name, variant, Some(_)) => {
156                Self::Variant(name.to_string(), variant.to_vec(), Some(index))
157            }
158            SpecificType::Variant(name, variants, None) => {
159                let v = variants.iter().find(|v| v.index() == index).unwrap();
160                Self::Variant(name.clone(), vec![v.clone()], Some(index))
161            }
162            _ => panic!("Only for enum variants"),
163        }
164    }
165
166    #[cfg(feature = "experimental-serializer")]
167    fn pick_mut<F, A, B>(&mut self, selection: A, get_field: F) -> &Self
168    where
169        F: Fn(&Variant) -> B,
170        A: AsRef<[u8]> + PartialEq + core::fmt::Debug,
171        B: AsRef<[u8]> + PartialEq + core::fmt::Debug,
172    {
173        match self {
174            SpecificType::Variant(_, _, Some(_)) => self,
175            SpecificType::Variant(_, ref mut variants, idx @ None) => {
176                let i = variants
177                    .iter()
178                    .map(|v| get_field(v))
179                    .position(|f| f.as_ref() == selection.as_ref())
180                    .expect("index") as u8;
181                variants.retain(|v| v.index() == i);
182                *idx = Some(i);
183                self
184            }
185            _ => panic!("Only for enum variants"),
186        }
187    }
188
189    #[cfg(feature = "experimental-serializer")]
190    fn variant_id(&self) -> u8 {
191        match self {
192            SpecificType::Variant(_, _, Some(id)) => *id,
193            _ => panic!("Only for enum variants"),
194        }
195    }
196}
197
198#[derive(Debug)]
199enum EnumVariant<'a> {
200    OptionNone,
201    OptionSome(TypeId),
202    Unit(u8, &'a str),
203    NewType(u8, &'a str, TypeId),
204    Tuple(u8, &'a str, Vec<TypeId>),
205    Struct(u8, &'a str, Vec<(&'a str, TypeId)>),
206}
207
208impl<'a> From<&'a SpecificType> for EnumVariant<'a> {
209    fn from(ty: &'a SpecificType) -> Self {
210        match ty {
211            SpecificType::Variant(name, variants, Some(idx)) => {
212                let variant = variants.first().expect("single variant");
213                let fields = variant.fields();
214                let vname = variant.name().as_ref();
215
216                if fields.is_empty() {
217                    if name == "Option" && vname == "None" {
218                        Self::OptionNone
219                    } else {
220                        Self::Unit(*idx, &vname)
221                    }
222                } else if is_tuple!(variant) {
223                    if fields.len() == 1 {
224                        let ty = fields.first().map(|f| f.ty().id()).unwrap();
225                        return if name == "Option" && variant.name() == &"Some" {
226                            Self::OptionSome(ty)
227                        } else {
228                            Self::NewType(*idx, &vname, ty)
229                        };
230                    } else {
231                        let fields = fields.iter().map(|f| f.ty().id()).collect();
232                        Self::Tuple(*idx, &vname, fields)
233                    }
234                } else {
235                    let fields = fields
236                        .iter()
237                        .map(|f| (f.name().unwrap().deref(), f.ty().id()))
238                        .collect();
239                    Self::Struct(*idx, &vname, fields)
240                }
241            }
242            _ => panic!("Only for enum variants"),
243        }
244    }
245}
246
247#[derive(Debug, Clone, serde::Serialize)]
248#[cfg_attr(feature = "codec", derive(codec::Encode))]
249pub enum TupleOrArray {
250    Array(TypeId, u32),
251    Tuple(Vec<TypeId>),
252}
253impl TupleOrArray {
254    fn len(&self) -> usize {
255        match self {
256            Self::Array(_, len) => *len as usize,
257            Self::Tuple(fields) => fields.len(),
258        }
259    }
260
261    fn type_id(&self, i: usize) -> TypeId {
262        match self {
263            Self::Array(ty, _) => *ty,
264            Self::Tuple(fields) => fields[i],
265        }
266    }
267}