Skip to content

Commit

Permalink
add documentation to everything.
Browse files Browse the repository at this point in the history
  • Loading branch information
tadeohepperle committed Nov 27, 2023
1 parent fcfb267 commit ffa5ea3
Show file tree
Hide file tree
Showing 19 changed files with 147 additions and 11 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ frame-metadata = { version = "16.0.0", default-features = false, features = ["cu
bitvec = { version = "1", default-features = false }
pretty_assertions = "1.4.0"
anyhow = "1.0.75"
# crates
peekmore = "1.3.0"
scale-value = { version = "0.13.0" }
rand_chacha = { version = "0.3.1" }
rand = { version = "0.8.5" }
14 changes: 7 additions & 7 deletions description/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,18 @@ type-example = ["dep:scale-value", "dep:proc-macro2", "dep:rand_chacha", "dep:ra

[dependencies]
anyhow = { workspace = true }
peekmore = "1.3.0"
peekmore = { workspace = true }
smallvec = { workspace = true }
scale-info = { workspace = true }

scale-value = { version = "0.13.0", optional = true }
proc-macro2 = { version = "1.0.69", optional = true }
rand_chacha = { version = "0.3.1", optional = true }
rand = { version = "0.8.5", optional = true }

scale-typegen = { workspace = true }
quote = { workspace = true }

#dependencies for "type-example" feature:
scale-value = { workspace = true, optional = true }
proc-macro2 = { workspace = true, optional = true }
rand_chacha = { workspace = true, optional = true }
rand = { workspace = true, optional = true }

[dev-dependencies]
indoc = "2"
pretty_assertions = { workspace = true }
1 change: 1 addition & 0 deletions description/src/formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::str::Chars;
use peekmore::{PeekMore, PeekMoreIterator};
use smallvec::SmallVec;

/// Formats a type description string to have nice indents.
pub fn format_type_description(input: &str) -> String {
/// Big scope means we want to spread out items over multiple lines.
/// Small scope means, we want to keep it compact (on one line).
Expand Down
8 changes: 8 additions & 0 deletions description/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! A crate for turning a type from a [`scale_info::PortableRegistry`] into some other, fully resolved, tree-like representation.
//! Currently we can generate these representations for a type:
//! - A human readable description of the type via [`crate::type_description`].
//! - An exemplary rust value of the type via [`crate::rust_value`].
//! - An exemplary scale value of the type via [`crate::scale_value`].
#![deny(unused_crate_dependencies)]
#![deny(missing_docs)]

mod description;
mod formatting;
mod transformer;

/// Create type examples for a type registry.
#[cfg(feature = "type-example")]
pub mod type_example;

Expand Down
2 changes: 2 additions & 0 deletions description/src/type_example/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
/// Generate an exemplary rust value of some type
pub mod rust_value;
/// Generate an exemplary scale value of some type
pub mod scale_value;

#[cfg(test)]
Expand Down
5 changes: 5 additions & 0 deletions description/src/type_example/rust_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ impl<'a> CodeTransformer<'a> {
}
}

/// Generates a random rust value for a type from the registry. The result should be a valid rust expression.
pub fn example(
type_id: u32,
types: &PortableRegistry,
Expand All @@ -108,6 +109,10 @@ pub fn example(
example_from_seed(type_id, types, settings_for_path_resolver, 42, None, None)
}

/// Generates a random rust value for a type from the registry. The result should be a valid rust expression. You can specify a seed to get reproducable results.
/// The `ty_middleware` can be used, to return a different type when a certain type is encountered.
/// The `ty_path_middleware` can be used, to convert an type path encountered into a different type path.
/// E.g. turning `::std::vec::Vec<T>` into just `Vec<T>`.
pub fn example_from_seed(
type_id: u32,
types: &PortableRegistry,
Expand Down
2 changes: 2 additions & 0 deletions description/src/type_example/scale_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ use crate::transformer::Transformer;

type ValueTransformer<'a> = Transformer<'a, Value, RefCell<rand_chacha::ChaCha8Rng>>;

/// Generates a random scale value for a type from the registry.
pub fn example(id: u32, types: &PortableRegistry) -> anyhow::Result<Value> {
const MAGIC_SEED: u64 = 42;
example_from_seed(id, types, MAGIC_SEED)
}

/// Generates a random scale value for a type from the registry. You can specify the seed to get reproducable results.
pub fn example_from_seed(id: u32, types: &PortableRegistry, seed: u64) -> anyhow::Result<Value> {
fn error_on_recurse(
_type_id: u32,
Expand Down
5 changes: 5 additions & 0 deletions typegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! A library based on [scale-info](https://github.com/paritytech/scale-info) to transpile portable registries of types into rust type definitions.
#![deny(unused_crate_dependencies)]
#![deny(missing_docs)]

// The #![deny(unused_crate_dependencies)] requires us to do these for the example to work:
#[cfg(test)]
use frame_metadata as _;
#[cfg(test)]
use prettyplease as _;
#[cfg(test)]
use scale_bits as _;

/// Type Generation Settings and Logic
pub mod typegen;
/// Utilities for handling Type Registries
pub mod utils;

pub use typegen::{
Expand Down
11 changes: 11 additions & 0 deletions typegen/src/typegen/error.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
use proc_macro2::Span;

/// Error for when something went wrong during type generation.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TypegenError {
/// Could not parse into a syn type.
#[error("Could not parse into a syn type: {0}")]
SynParseError(#[from] syn::Error),
/// Fields should either be all named or all unnamed, make sure you are providing a valid metadata.
#[error("Fields should either be all named or all unnamed, make sure you are providing a valid metadata: {0}")]
InvalidFields(String),
/// A type in the metadata was invalid
#[error("A type in the metadata was invalid: {0}")]
InvalidType(String),
/// Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.
#[error("Could not generate a type that contains a compact type, because the Compact type path is not set in the settings.")]
CompactPathNone,
/// Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.
#[error("Could not generate a type that contains a bit sequence, because the DecodedBits type path is not set in the settings.")]
DecodedBitsPathNone,
/// Could not find type with ID in the type registry.
#[error("Could not find type with ID {0} in the type registry.")]
TypeNotFound(u32),
/// Type substitution error.
#[error("Type substitution error: {0}")]
InvalidSubstitute(#[from] TypeSubstitutionError),
}

/// Error attempting to do type substitution.
#[derive(Debug, thiserror::Error)]
pub struct TypeSubstitutionError {
/// Where in the code the error occured.
pub span: Span,
/// Kind of TypeSubstitutionError that happended.
pub kind: TypeSubstitutionErrorKind,
}

Expand All @@ -35,6 +45,7 @@ impl std::fmt::Display for TypeSubstitutionError {
}
}

/// Error attempting to do type substitution.
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum TypeSubstitutionErrorKind {
Expand Down
2 changes: 2 additions & 0 deletions typegen/src/typegen/ir/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
/// Intermediate Representation of a rust module.
pub mod module_ir;
/// Intermediate Representation of a rust type.
pub mod type_ir;
6 changes: 6 additions & 0 deletions typegen/src/typegen/ir/module_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ use scale_info::form::PortableForm;
/// Represents a Rust `mod`, containing generated types and child `mod`s.
#[derive(Debug, Clone)]
pub struct ModuleIR {
/// Name of this module.
pub name: Ident,
/// Root module identifier.
pub root_mod: Ident,
/// Submodules of this module.
pub children: BTreeMap<Ident, ModuleIR>,
/// Types in this module.
pub types: BTreeMap<scale_info::Path<PortableForm>, TypeIR>,
}

Expand Down Expand Up @@ -65,6 +69,8 @@ impl ModuleIR {
&self.root_mod
}

/// Recursively creates submodules for the given namespace and returns a mutable reference to the innermost module created this way.
/// Returns itself, if the namespace is empty.
pub fn get_or_insert_submodule(&mut self, namespace: &[String]) -> &mut ModuleIR {
if namespace.is_empty() {
return self;
Expand Down
30 changes: 29 additions & 1 deletion typegen/src/typegen/ir/type_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,26 @@ use crate::typegen::{
settings::derives::Derives, type_params::TypeParameters, type_path::TypePath,
};

/// Intermediate Representation of a Rust type.
#[derive(Debug, Clone)]
pub struct TypeIR {
/// Generic type parameters.
pub type_params: TypeParameters,
/// Derived traits for his type.
pub derives: Derives,
/// whether or not `#[codec(...)]` attributes should be inserted.
/// Only makes sense if the derives include `Encode`/`Decode`.
pub insert_codec_attributes: bool,
/// Is this type an enum or struct.
pub kind: TypeIRKind,
}

/// An enum or struct.
#[derive(Debug, Clone)]
pub enum TypeIRKind {
/// A struct.
Struct(CompositeIR),
/// An enum.
Enum(EnumIR),
}

Expand All @@ -35,34 +44,46 @@ impl TypeIR {
}
}

/// A composite. Could be a struct or a variant of an enum.
#[derive(Debug, Clone)]
pub struct CompositeIR {
/// Struct name or enum variant name.
pub name: Ident,
/// Named, Unnamed or NoFields.
pub kind: CompositeIRKind,
/// Docs for the composite.
pub docs: TokenStream,
}

impl CompositeIR {
/// Creates a new `CompositeIR`.
pub fn new(name: Ident, kind: CompositeIRKind, docs: TokenStream) -> Self {
Self { name, kind, docs }
}
}

/// A rust enum.
#[derive(Debug, Clone)]
pub struct EnumIR {
/// Docs for the enum.
pub(crate) docs: TokenStream,
pub(crate) name: Ident,
pub(crate) variants: Vec<(u8, CompositeIR)>,
}

/// Named, Unnamed or NoFields.
#[derive(Debug, Clone)]
pub enum CompositeIRKind {
/// A zero-sized, empty composite.
NoFields,
/// Composite with named fields, e.g. a struct.
Named(Vec<(Ident, CompositeFieldIR)>),
/// Composite with unnamed fields, e.g. a tuple.
Unnamed(Vec<CompositeFieldIR>),
}

impl CompositeIRKind {
/// Returns true if this composite be compact encoded. This is only true if the composite has exactly one field which could be compact encoded.
pub fn could_derive_as_compact(&self) -> bool {
// has to have only a single field:
let single_field = match self {
Expand All @@ -84,14 +105,20 @@ impl CompositeIRKind {
}
}

/// A field of a composite.
#[derive(Debug, Clone)]
pub struct CompositeFieldIR {
/// type path of the field.
pub type_path: TypePath,
/// Is this field compact encoded?
/// Having this as `true` may insert a `#[codec(compact)]` attribute during code generation.
pub is_compact: bool,
/// Is this field actually boxed? e.g. `Box<type_path>` instead of just `type_path`.
pub is_boxed: bool,
}

impl CompositeFieldIR {
/// Creates a new [`CompositeFieldIR`].
pub fn new(type_path: TypePath, is_compact: bool, is_boxed: bool) -> Self {
CompositeFieldIR {
type_path,
Expand All @@ -100,7 +127,8 @@ impl CompositeFieldIR {
}
}

pub fn compact_attr(&self) -> Option<TokenStream> {
/// Returns a `#[codec(compact)]` attribute if the field should be compact encoded.
fn compact_attr(&self) -> Option<TokenStream> {
self.is_compact.then(|| quote!( #[codec(compact)] ))
}
}
Expand Down
13 changes: 13 additions & 0 deletions typegen/src/typegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ use quote::quote;
use scale_info::{form::PortableForm, PortableRegistry, Type, TypeDef};
use syn::parse_quote;

/// Custom error types.
pub mod error;
/// Intermediate representation of types and modules.
pub mod ir;
/// Utility extension functions on the `TypeGenerator` struct to resolve type paths.
pub mod resolve_type_paths;
/// Settings passed into the `TypeGenerator`.
pub mod settings;
/// Logic for dealing with used and unused generic type parameters.
pub mod type_params;
/// Type path definition and conversion into tokens.
pub mod type_path;

/// An interface for generating a types module.
Expand All @@ -35,10 +41,12 @@ impl<'a> TypeGenerator<'a> {
}
}

/// The name of the generated module which will contain the generated types.
pub fn types_mod_ident(&self) -> &Ident {
&self.settings.types_mod_ident
}

/// The settings used by this type generator.
pub fn settings(&self) -> &TypeGeneratorSettings {
self.settings
}
Expand Down Expand Up @@ -81,6 +89,7 @@ impl<'a> TypeGenerator<'a> {
Ok(root_mod)
}

/// Creates an intermediate representation of a type that can later be converted into rust tokens.
pub fn create_type_ir(
&self,
ty: &Type<PortableForm>,
Expand Down Expand Up @@ -156,6 +165,7 @@ impl<'a> TypeGenerator<'a> {
.unwrap_or_default()
}

/// Creates an intermediate representation of a composite.
pub fn create_composite_ir_kind(
&self,
fields: &[scale_info::Field<PortableForm>],
Expand Down Expand Up @@ -229,6 +239,8 @@ impl<'a> TypeGenerator<'a> {
}
}

/// Creates the intermediate representation of a type from just a composite definition.
/// This uses just the default derives and type params are left empty.
pub fn upcast_composite(&self, composite: &CompositeIR) -> TypeIR {
// just use Default Derives + AsCompact. No access to type specific derives here. (Mainly used in subxt to create structs from enum variants...)
let mut derives = self.settings.derives.default_derives().clone();
Expand All @@ -243,6 +255,7 @@ impl<'a> TypeGenerator<'a> {
}
}

/// The default derives set in the type generator's settings.
pub fn default_derives(&self) -> &Derives {
self.settings.derives.default_derives()
}
Expand Down
2 changes: 2 additions & 0 deletions typegen/src/typegen/resolve_type_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ impl<'a> TypeGenerator<'a> {
Ok(TypePath::from_type(ty))
}

/// Converts a [`scale_info::Path`] into a [`TypePathType`], replacing all types that should be substituted.
pub fn type_path_maybe_with_substitutes(
&self,
path: &scale_info::Path<PortableForm>,
Expand All @@ -189,6 +190,7 @@ impl<'a> TypeGenerator<'a> {
}
}

/// Resolves a type, given some type id.
pub fn resolve_type(&self, id: u32) -> Result<&Type<PortableForm>, TypegenError> {
let ty = self
.type_registry
Expand Down
Loading

0 comments on commit ffa5ea3

Please sign in to comment.