scale_info/
lib.rs

1// Copyright 2019-2022 Parity Technologies (UK) Ltd.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#![cfg_attr(not(feature = "std"), no_std)]
16#![deny(missing_docs)]
17
18//! Efficient and space-efficient serialization of Rust types.
19//!
20//! This library provides structures to easily retrieve compile-time type
21//! information at runtime and also to serialize this information in a
22//! space-efficient form, aka `PortableForm`.
23//!
24//! # Registry
25//!
26//! At the heart of its functionality is the [`Registry`](`crate::Registry`)
27//! that acts as a cache for known types in order to efficiently deduplicate
28//! types and ensure a space-efficient serialization.
29//!
30//! # Type Information
31//!
32//! Information about types is provided via the [`TypeInfo`](`crate::TypeInfo`)
33//! trait.
34//!
35//! This trait should be implemented for all types that are serializable.
36//! `scale-info` provides implementations for all commonly used Rust standard
37//! types and a derive macro for implementing of custom types.
38//!
39//! ## Deriving `TypeInfo`
40//!
41//! Enable the `derive` feature of this crate:
42//!
43//! ```toml
44//! scale-info = { version = "2.0.0", features = ["derive"] }
45//! ```
46//!
47//! ```ignore
48//! use scale_info::TypeInfo;
49//!
50//! #[derive(TypeInfo)]
51//! struct MyStruct {
52//!     a: u32,
53//!     b: MyEnum,
54//! }
55//!
56//! #[derive(TypeInfo)]
57//! enum MyEnum {
58//!     A(bool),
59//!     B { f: Vec<u8> },
60//!     C,
61//! }
62//! ```
63//!
64//! ### Attributes
65//!
66//! #### `#[scale_info(bounds(..))]`
67//!
68//! Replace the auto-generated `where` clause bounds for the derived `TypeInfo` implementation.
69//!
70//! ```ignore
71//! #[derive(TypeInfo)]
72//! #[scale_info(bounds(T: TypeInfo + 'static))]
73//! struct MyStruct<T> {
74//!     a: Vec<T>,
75//! }
76//! ```
77//!
78//! The derive macro automatically adds `TypeInfo` bounds for all type parameters, and all field
79//! types containing type parameters or associated types.
80//!
81//! This is naive and sometimes adds unnecessary bounds, since on a syntactical level there is no
82//! way to differentiate between a generic type constructor and a type alias with a generic argument
83//! e.g.
84//!
85//! ```ignore
86//! trait MyTrait {
87//!     type A;
88//! }
89//!
90//! type MyAlias<T> = <T as MyTrait>::A;
91//!
92//! #[derive(TypeInfo)]
93//! struct MyStruct<T> {
94//!     a: MyAlias<T>,
95//!     b: Vec<T>,
96//! }
97//! ```
98//!
99//! So for the above, since a `MyAlias<T>: TypeInfo` bound is required, and we can't distinguish
100//! between `MyAlias<T>` and `Vec<T>`, then the `TypeInfo` bound is simply added for all
101//! fields which contain any type param. In this case the redundant `Vec<T>: TypeInfo`
102//! would be added.
103//!
104//! This is usually okay, but in some circumstances can cause problems, for example with the
105//! [`overflow evaluating the requirement`] error [here](https://github.com/paritytech/scale-info/blob/master/test_suite/tests/ui/pass_custom_bounds_fix_overflow.rs).
106//!
107//! The `bounds` attribute provides an ["escape hatch"](https://serde.rs/attr-bound.html) to allow
108//! the programmer control of the `where` clause on the generated `impl`, to solve this and other
109//! issues that can't be foreseen by the auto-generated bounds heuristic.
110//!
111//! #### `#[scale_info(skip_type_params(..))]`
112//!
113//! Remove the requirement for the specified type params to implement `TypeInfo`.
114//!
115//! Consider a simple example of a type parameter which is used for associated types, but the type
116//! itself does not carry any type information. Consider this common pattern:
117//!
118//! ```ignore
119//! trait Config {
120//!     type Balance;
121//! }
122//!
123//! struct Runtime; // doesn't implement `TypeInfo`
124//!
125//! impl Config for Runtime {
126//!     type Balance = u64;
127//! }
128//!
129//! #[allow(unused)]
130//! #[derive(TypeInfo)]
131//! #[scale_info(skip_type_params(T))]
132//! struct A<T: Config> {
133//!     balance: T::Balance,
134//!     marker: core::marker::PhantomData<T>,
135//! }
136//!
137//! fn assert_type_info<T: scale_info::TypeInfo + 'static>() {}
138//!
139//! fn main() {
140//!     // without the `skip_type_params` attribute this will fail.
141//!     assert_type_info::<A<Runtime>>();
142//! }
143//! ```
144//!
145//! By default, the derived `TypeInfo` implementation will add the type of all type parameters to
146//! the `TypeParameter` specification e.g.
147//!
148//! `type_params(vec![TypeParameter::new("T", Some(MetaType::new::<T>()))])`
149//!
150//! In the example above, this will cause a compiler error because `Runtime` is the concrete tyoe
151//! for `T`, which does not satisfy the `TypeInfo` requirement of `MetaType::new::<T>()`.
152//!
153//! Simply adding a `TypeInfo` derive to `Runtime` is one way of solving this, but that could be
154//! misleading (why does it need `TypeInfo` if a value of that type is never encoded?), and can
155//! sometimes require adding `TypeInfo` bounds in other impl blocks.
156//!
157//! The `skip_type_params` attribute solves this, providing an additional "escape hatch" which
158//! prevents the given type parameter's type information being required:
159//!
160//! `type_params(vec![TypeParameter::new("T", None)])`
161//!
162//! The generated type params do not now require `T` to implement `TypeInfo`, so the auto-generated
163//! bound is not added to the generated `TypeInfo` `where` clause.
164//!
165//! #### Combining `bounds` and `skip_type_params`
166//!
167//! These two attributes can complement one another, particularly in the case where using `bounds`
168//! would still require manually adding a `TypeInfo` bound for the type parameter:
169//!
170//! ```ignore
171//! #[derive(TypeInfo)]
172//! #[scale_info(bounds(), skip_type_params(T))]
173//! struct A<T> {
174//!     marker: core::marker::PhantomData<T>,
175//! }
176//! ```
177//!
178//! Without `skip_type_params` in the example above, it would require the `TypeInfo` bounds for `T`
179//! to be added manually e.g. `#[scale_info(bounds(T: TypeInfo + 'static))]`. Since the intention of
180//! the empty bounds is to **remove** all type bounds, then the addition of `skip_type_params`
181//! allows this to compile successfully.
182//!
183//! ##### Precedence
184//!
185//! When used independently, both attributes modify the `where` clause of the derived `TypeInfo`
186//! impl. When used together, the predicates supplied in the `bounds` attribute replaces *all*
187//! auto-generated bounds, and `skip_type_params` will have no effect on the resulting `where`
188//! clause.
189//!
190//! **Note:** When using `bounds` without `skip_type_params`, it is therefore required to manually
191//! add a `TypeInfo` bound for any non skipped type parameters. The compiler will let you know.
192//!
193//! #### `#[scale_info(capture_docs = "default|always|never")]`
194//!
195//! Docs for types, fields and variants can all be captured by the `docs` feature being enabled.
196//! This can be overridden using the `capture_docs` attribute:
197//!
198//! `#[scale_info(capture_docs = "default")]` will capture docs iff the `docs` feature is enabled.
199//! This is the default if `capture_docs` is not specified.
200//!
201//! `#[scale_info(capture_docs = "always")]` will capture docs for the annotated type even if the
202//! `docs` feature is *not* enabled.
203//!
204//! `#[scale_info(capture_docs = "never")]` will *not* capture docs for the annotated type even if
205//! the `docs` is enabled.
206//!
207//! This is useful e.g. when compiling metadata into a Wasm blob, and it is desirable to keep the
208//! binary size as small as possible, so the `docs` feature would be disabled. In case the docs for
209//! some types is necessary they could be enabled on a per-type basis with the above attribute.
210//!
211//! #### `#[scale_info(crate = path::to::crate)]`
212//!
213//! Specify a path to the scale-info crate instance to use when referring to the APIs from generated
214//! code. This is normally only applicable when invoking re-exported scale-info derives from a public
215//! macro in a different crate. For example:
216//! ```ignore
217//! use scale_info_reexport::info::TypeInfo;
218//!
219//! #[derive(TypeInfo)]
220//! #[scale_info(crate = scale_info_reexport::info)]
221//! enum TestEnum {
222//!     FirstVariant,
223//!     SecondVariant,
224//! }
225//! ```
226//!
227//! #### `#[scale_info(replace_segment("search", "replace"))]`
228//!
229//! Specify to rename a segment in the `path` returned by the [`TypeInfo::path`] function.
230//! Normally the path is generated by using the `module_path!` macro. This path includes
231//! the crate name and all the modules up to the declaration of the type. Sometimes it
232//! is useful to replace one of these segments to ensure that for example a renaming
233//! of the crate isn't propagated to downstream users. Be aware that if a `crate-name`
234//! contains an hypen, the actual segment is `crate_name`. The `replace` name needs
235//! to be a valid Rust identifier. The attribute is allowed to be passed multiple
236//! times to replace multiple segments.
237//!
238//! Example:
239//! ```ignore
240//! use scale_info_reexport::info::TypeInfo;
241//!
242//! #[derive(TypeInfo)]
243//! #[scale_info(replace_segment("something", "better_name"))]
244//! #[scale_info(replace_segment("TestEnum", "BetterEnumName"))]
245//! enum TestEnum {
246//!     FirstVariant,
247//!     SecondVariant,
248//! }
249//! ```
250//!
251//! # Forms
252//!
253//! To bridge between compile-time type information and runtime the
254//! [`MetaForm`](`crate::form::MetaForm`) is used to easily retrieve all
255//! information needed to uniquely identify types.
256//!
257//! The `MetaForm` and its associated `Registry` can be transformed into the
258//! space-efficient form by the [`IntoPortable`](`crate::IntoPortable`) trait; it is
259//! used internally by the [`Registry`](`crate::Registry`) in order to convert
260//! the expanded types into their space-efficient form.
261//!
262//! # Symbols and Namespaces
263//!
264//! To differentiate two types sharing the same name, namespaces are used.
265//! Commonly the namespace is equal to the one where the type has been defined
266//! in. For Rust prelude types such as [`Option`](`std::option::Option`) and
267//! [`Result`](`std::result::Result`) the root namespace (empty namespace) is
268//! used.
269//!
270//! To use this library simply use the [`MetaForm`](`crate::form::MetaForm`)
271//! initially with your own data structures; make them generic over the
272//! [`Form`](`crate::form::Form`) trait just as has been done in this crate with
273//! [`TypeInfo`](`crate::TypeInfo`) in order to get a simple implementation of
274//! [`IntoPortable`](`crate::IntoPortable`). Use a single instance of the
275//! [`Registry`](`crate::Registry`) for compaction and provide this registry
276//! instance upon serialization.
277//!
278//! A usage example can be found in ink! here:
279//! https://github.com/paritytech/ink/blob/master/abi/src/specs.rs
280
281/// Takes a number of types and returns a vector that contains their respective
282/// [`MetaType`](`crate::MetaType`) instances.
283///
284/// This is useful for places that require inputs of iterators over [`MetaType`](`crate::MetaType`)
285/// instances and provide a way out of code bloat in these scenarios.
286///
287/// # Example
288///
289/// ```
290/// # use scale_info::tuple_meta_type;
291/// assert_eq!(
292///     tuple_meta_type!(i32, [u8; 32], String),
293///     {
294///         use scale_info::MetaType;
295///         let mut vec = Vec::new();
296///         vec.push(MetaType::new::<i32>());
297///         vec.push(MetaType::new::<[u8; 32]>());
298///         vec.push(MetaType::new::<String>());
299///         vec
300///     }
301/// );
302/// ```
303#[macro_export]
304macro_rules! tuple_meta_type {
305    ( $($ty:ty),* ) => {
306        {
307            $crate::prelude::vec![
308                $(
309                    $crate::MetaType::new::<$ty>(),
310                )*
311            ]
312        }
313    }
314}
315
316/// Construct a vector of `TypeParameter`s from pairs of the name and the concrete type.
317///
318/// # Example
319///
320/// ```
321/// # use scale_info::{named_type_params, MetaType, TypeParameter};
322/// assert_eq!(
323///     named_type_params![(T, u8), (U, u32)],
324///     vec! [
325///         TypeParameter::new("T", Some(MetaType::new::<u8>())),
326///         TypeParameter::new("U", Some(MetaType::new::<u32>())),
327///     ]
328/// );
329/// ```
330#[macro_export]
331macro_rules! named_type_params {
332    ( $(($tp:ty, $ty:ty)),* ) => {
333        {
334            $crate::prelude::vec![
335                $(
336                    $crate::TypeParameter::<$crate::form::MetaForm>::new(
337                        ::core::stringify!($tp),
338                        Some($crate::MetaType::new::<$ty>())
339                    ),
340                )*
341            ]
342        }
343    }
344}
345
346/// Construct a vector of [`TypeParameter`] instances with the name of the type parameter,
347/// together with its concrete [`MetaType`].
348#[macro_export]
349macro_rules! type_params {
350    ( $($ty:ty),* ) => {
351        $crate::named_type_params!{ $( ($ty, $ty) ),* }
352    }
353}
354
355pub mod prelude;
356
357pub mod build;
358pub mod form;
359mod impls;
360pub mod interner;
361mod meta_type;
362mod portable;
363mod registry;
364mod ty;
365mod utils;
366
367#[doc(hidden)]
368pub use scale;
369
370pub use self::{
371    meta_type::MetaType,
372    portable::{PortableRegistry, PortableRegistryBuilder, PortableType},
373    registry::{IntoPortable, Registry},
374    ty::*,
375};
376
377#[cfg(feature = "derive")]
378pub use scale_info_derive::TypeInfo;
379
380/// Implementors return their meta type information.
381pub trait TypeInfo {
382    /// The type identifying for which type info is provided.
383    ///
384    /// # Note
385    ///
386    /// This is used to uniquely identify a type via [`core::any::TypeId::of`]. In most cases it
387    /// will just be `Self`, but can be used to unify different types which have the same encoded
388    /// representation e.g. reference types `Box<T>`, `&T` and `&mut T`.
389    type Identity: ?Sized + 'static;
390
391    /// Returns the static type identifier for `Self`.
392    fn type_info() -> Type;
393}
394
395/// Convenience trait for implementors, combining `TypeInfo` and `'static` bounds.
396///
397/// # Note
398///
399/// Currently because of the `'static` constraint on [`std::any::TypeId::of`] (see [`MetaType`]),
400/// `TypeInfo` constraints must also be accompanied by a `'static` bound. This trait is useful to
401/// implementors so only a single constraint is required.
402pub trait StaticTypeInfo: TypeInfo + 'static {}
403
404impl<T> StaticTypeInfo for T where T: TypeInfo + 'static {}
405
406/// Returns the runtime bridge to the types compile-time type information.
407pub fn meta_type<T>() -> MetaType
408where
409    T: ?Sized + TypeInfo + 'static,
410{
411    MetaType::new::<T>()
412}
413
414#[cfg(test)]
415mod tests;