Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
37c0a57
Parameterize CompactForm String for optional SCALE impl
ascjones Dec 7, 2020
643f09d
Merge remote-tracking branch 'origin/master' into aj-compact-string
dvdplm Dec 14, 2020
9a7ccbf
Fix no-std compilation
dvdplm Dec 14, 2020
254fee1
Obey the fmt
dvdplm Dec 14, 2020
e74e4f9
Introduce String trait for Form
ascjones Dec 16, 2020
7860c79
Rename "Compact" to "Frozen" (and associated fallout)
dvdplm Dec 16, 2020
579f958
Docs cleanup and more renames
dvdplm Dec 17, 2020
8333e5a
Cleanup
dvdplm Dec 17, 2020
2818f7b
More cleanup
dvdplm Dec 17, 2020
7706a38
Merge branch 'aj-compact-string' into dp-rename-compact-to-frozen
dvdplm Dec 17, 2020
e03a2cd
obey the fmt
dvdplm Dec 17, 2020
3a95663
Add a `compact` flag to `Field` to indicate that this type is to be e…
dvdplm Dec 17, 2020
004e107
Clippy warnings
dvdplm Dec 17, 2020
93a9aeb
Acommodate older clippy
dvdplm Dec 17, 2020
6569e50
Derive (scale) compact fields
dvdplm Dec 28, 2020
f098101
Merge branch 'master' into dp-flag-types-as-compact
dvdplm Jan 4, 2021
eda2769
Merge remote-tracking branch 'origin/master' into dp-flag-types-as-co…
dvdplm Jan 5, 2021
09c1241
WIP
dvdplm Jan 8, 2021
55f1413
Sort out the TypeInfo impl for Compact<T> (ty @ascjones!)
dvdplm Jan 8, 2021
e2397bf
Clean up conditionals a bit
dvdplm Jan 11, 2021
d15bf25
Add Compact to prelude
dvdplm Jan 11, 2021
1f4f8d3
Cleanup
dvdplm Jan 11, 2021
02ed1a3
fmt
dvdplm Jan 11, 2021
80a8b27
Merge branch 'master' into dp-add-TypeDef-to-handle-Compact-types
dvdplm Jan 18, 2021
7389297
fmt
dvdplm Jan 18, 2021
d8506dc
Sort out TODOs
dvdplm Jan 18, 2021
ab56118
Remove unused top-level way of adding a Compact
dvdplm Jan 19, 2021
5436755
Merge remote-tracking branch 'origin/master' into dp-add-TypeDef-to-h…
dvdplm Jan 27, 2021
c70f31c
Merge remote-tracking branch 'origin/master' into dp-add-TypeDef-to-h…
dvdplm Jan 29, 2021
e656489
Merge remote-tracking branch 'origin/master' into dp-add-TypeDef-to-h…
dvdplm Jan 29, 2021
1c0c05d
Remove unneeded bound
dvdplm Jan 29, 2021
693b23a
Remove `Compact` from the prelude
dvdplm Jan 29, 2021
c2a38f5
Resolve TODO
dvdplm Jan 29, 2021
5649a66
fmt
dvdplm Jan 29, 2021
aad3277
Use <T as HasCompact>::Type rather than Compact<T> (ty @thiolliere!)
dvdplm Jan 29, 2021
4b18500
Split long comment
dvdplm Jan 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use syn::{
punctuated::Punctuated,
token::Comma,
visit_mut::VisitMut,
AttrStyle,
Data,
DataEnum,
DataStruct,
Expand All @@ -49,6 +50,9 @@ use syn::{
Fields,
Lifetime,
Lit,
Meta,
MetaList,
NestedMeta,
Variant,
};

Expand Down Expand Up @@ -100,7 +104,6 @@ fn generate_type(input: TokenStream2) -> Result<TokenStream2> {
.path(::scale_info::Path::new(stringify!(#ident), module_path!()))
.type_params(::scale_info::prelude::vec![ #( #generic_type_ids ),* ])
.#build_type
.into()
}
}
};
Expand All @@ -127,20 +130,37 @@ fn generate_fields(fields: &FieldsList) -> Vec<TokenStream2> {
StaticLifetimesReplace.visit_type_mut(&mut ty);

let type_name = clean_type_string(&quote!(#ty).to_string());

if let Some(i) = ident {
quote! {
.field_of::<#ty>(stringify!(#i), #type_name)
}
let method_call = if is_compact(f) {
quote!(.compact_of::<#ty>)
} else {
quote! {
.field_of::<#ty>(#type_name)
}
quote!(.field_of::<#ty>)
};
if let Some(ident) = ident {
quote!(#method_call(stringify!(#ident), #type_name))
} else {
quote!(#method_call(#type_name))
}
})
.collect()
}

/// Look for a `#[codec(compact)]` outer attribute.
fn is_compact(f: &Field) -> bool {
f.attrs.iter().any(|attr| {
let mut is_compact = false;
if attr.style == AttrStyle::Outer && attr.path.is_ident("codec") {
if let Ok(Meta::List(MetaList { nested, .. })) = attr.parse_meta() {
if let Some(NestedMeta::Meta(Meta::Path(path))) = nested.iter().next() {
if path.is_ident("compact") {
is_compact = true;
}
}
}
}
is_compact
})
}

fn clean_type_string(input: &str) -> String {
input
.replace(" ::", "::")
Expand Down
29 changes: 20 additions & 9 deletions derive/src/trait_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,21 @@ pub fn make_where_clause<'a>(

let types = collect_types_to_bind(input_ident, data, &ty_params_ids)?;

types.into_iter().for_each(|ty| {
where_clause
.predicates
.push(parse_quote!(#ty : ::scale_info::TypeInfo + 'static))
types.into_iter().for_each(|(ty, is_compact)| {
// Compact types need extra bounds, T: HasCompact and <T as
// HasCompact>::Type: TypeInfo + 'static
if is_compact {
where_clause
.predicates
.push(parse_quote!(#ty : ::scale::HasCompact));
where_clause
.predicates
.push(parse_quote!(<#ty as ::scale::HasCompact>::Type : ::scale_info::TypeInfo + 'static));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think our use of ::scale is becoming a problem. ink! imports parity-scale-codec crate as scale but from what I remember Substrate imports it as codec. We need a solution that works for both. Probably Basti's https://crates.io/crates/proc-macro-crate could help here. For now I am fine and we can fix this later.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also seem to break primitive-types: paritytech/parity-common#519

} else {
where_clause
.predicates
.push(parse_quote!(#ty : ::scale_info::TypeInfo + 'static));
}
});

generics.type_params().into_iter().for_each(|type_param| {
Expand Down Expand Up @@ -94,14 +105,14 @@ fn type_contains_idents(ty: &Type, idents: &[Ident]) -> bool {
visitor.result
}

/// Returns all types that must be added to the where clause with the respective
/// trait bound.
/// Returns all types that must be added to the where clause with a boolean
/// indicating if the field is [`scale::Compact`] or not.
fn collect_types_to_bind(
input_ident: &Ident,
data: &syn::Data,
ty_params: &[Ident],
) -> Result<Vec<Type>> {
let types_from_fields = |fields: &Punctuated<syn::Field, _>| -> Vec<syn::Type> {
) -> Result<Vec<(Type, bool)>> {
let types_from_fields = |fields: &Punctuated<syn::Field, _>| -> Vec<(Type, bool)> {
fields
.iter()
.filter(|field| {
Expand All @@ -112,7 +123,7 @@ fn collect_types_to_bind(
// to not have them in the where clause.
!type_contains_idents(&field.ty, &[input_ident.clone()])
})
.map(|f| f.ty.clone())
.map(|f| (f.ty.clone(), super::is_compact(f)))
.collect()
};

Expand Down
21 changes: 21 additions & 0 deletions src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,17 @@ impl FieldsBuilder<NamedFields> {
self.fields.push(Field::named_of::<T>(name, type_name));
self
}

/// Add a named, [`Compact`] field of type `T`.
pub fn compact_of<T>(mut self, name: &'static str, type_name: &'static str) -> Self
where
T: scale::HasCompact,
<T as scale::HasCompact>::Type: TypeInfo + 'static,
{
self.fields
.push(Field::compact_of::<T>(Some(name), type_name));
self
}
}

impl FieldsBuilder<UnnamedFields> {
Expand All @@ -270,6 +281,16 @@ impl FieldsBuilder<UnnamedFields> {
self.fields.push(Field::unnamed_of::<T>(type_name));
self
}

/// Add an unnamed, [`Compact`] field of type `T`.
pub fn compact_of<T>(mut self, type_name: &'static str) -> Self
where
T: scale::HasCompact,
<T as scale::HasCompact>::Type: TypeInfo + 'static,
{
self.fields.push(Field::compact_of::<T>(None, type_name));
self
}
}

/// Build a type with no variants.
Expand Down
11 changes: 11 additions & 0 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
Path,
Type,
TypeDefArray,
TypeDefCompact,
TypeDefPhantom,
TypeDefPrimitive,
TypeDefSequence,
Expand Down Expand Up @@ -251,3 +252,13 @@ where
TypeDefPhantom::new(MetaType::new::<T>()).into()
}
}

impl<T> TypeInfo for scale::Compact<T>
where
T: TypeInfo + 'static,
{
type Identity = Self;
fn type_info() -> Type {
TypeDefCompact::new(MetaType::new::<T>()).into()
}
}
1 change: 0 additions & 1 deletion src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,6 @@ mod tests {
"&mut RecursiveRefs",
),
)
.into()
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::{
*,
};
use core::marker::PhantomData;
use scale::Compact;

#[cfg(not(feature = "std"))]
use alloc::{
Expand Down Expand Up @@ -77,6 +78,11 @@ fn prelude_items() {
assert_type!(PhantomData<i32>, TypeDefPhantom::new(meta_type::<i32>()));
}

#[test]
fn scale_compact_types() {
assert_type!(Compact<i32>, TypeDefCompact::new(meta_type::<i32>()))
}

#[test]
fn tuple_primitives() {
// unit
Expand Down Expand Up @@ -128,7 +134,6 @@ fn struct_with_generics() {
.path(Path::new("MyStruct", module_path!()))
.type_params(tuple_meta_type!(T))
.composite(Fields::named().field_of::<T>("data", "T"))
.into()
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/ty/fields.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
use scale::{
Decode,
Encode,
HasCompact,
};
#[cfg(feature = "serde")]
use serde::{
Expand Down Expand Up @@ -129,6 +130,15 @@ impl Field {
{
Self::new(None, MetaType::new::<T>(), type_name)
}

/// Creates a new [`Compact`] field.
pub fn compact_of<T>(name: Option<&'static str>, type_name: &'static str) -> Field
where
T: HasCompact,
<T as HasCompact>::Type: TypeInfo + 'static,
{
Self::new(name, MetaType::new::<<T as HasCompact>::Type>(), type_name)
}
}

impl<T> Field<T>
Expand Down
81 changes: 54 additions & 27 deletions src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,35 +94,24 @@ impl IntoPortable for Type {
}
}

impl From<TypeDefPrimitive> for Type {
fn from(primitive: TypeDefPrimitive) -> Self {
Self::new(Path::voldemort(), Vec::new(), primitive)
}
}

impl From<TypeDefArray> for Type {
fn from(array: TypeDefArray) -> Self {
Self::new(Path::voldemort(), Vec::new(), array)
}
}

impl From<TypeDefSequence> for Type {
fn from(sequence: TypeDefSequence) -> Self {
Self::new(Path::voldemort(), Vec::new(), sequence)
}
}

impl From<TypeDefTuple> for Type {
fn from(tuple: TypeDefTuple) -> Self {
Self::new(Path::voldemort(), Vec::new(), tuple)
}
macro_rules! impl_from_type_def_for_type {
( $( $t:ty ), + $(,)?) => { $(
impl From<$t> for Type {
fn from(item: $t) -> Self {
Self::new(Path::voldemort(), Vec::new(), item)
}
}
)* }
}

impl From<TypeDefPhantom> for Type {
fn from(phantom: TypeDefPhantom) -> Self {
Self::new(Path::voldemort(), Vec::new(), phantom)
}
}
impl_from_type_def_for_type!(
TypeDefPrimitive,
TypeDefArray,
TypeDefSequence,
TypeDefTuple,
TypeDefCompact,
TypeDefPhantom,
);

impl Type {
/// Create a [`TypeBuilder`](`crate::build::TypeBuilder`) the public API for constructing a [`Type`]
Expand Down Expand Up @@ -187,6 +176,8 @@ pub enum TypeDef<T: Form = MetaForm> {
Tuple(TypeDefTuple<T>),
/// A Rust primitive type.
Primitive(TypeDefPrimitive),
/// A type using the [`Compact`] encoding
Compact(TypeDefCompact<T>),
/// A PhantomData type.
Phantom(TypeDefPhantom<T>),
}
Expand All @@ -202,6 +193,7 @@ impl IntoPortable for TypeDef {
TypeDef::Array(array) => array.into_portable(registry).into(),
TypeDef::Tuple(tuple) => tuple.into_portable(registry).into(),
TypeDef::Primitive(primitive) => primitive.into(),
TypeDef::Compact(compact) => compact.into_portable(registry).into(),
TypeDef::Phantom(phantom) => phantom.into_portable(registry).into(),
}
}
Expand Down Expand Up @@ -391,6 +383,41 @@ where
}
}

/// A type wrapped in [`Compact`].
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Encode, Decode, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TypeDefCompact<T: Form = MetaForm> {
/// The type wrapped in [`Compact`], i.e. the `T` in `Compact<T>`.
#[cfg_attr(feature = "serde", serde(rename = "type"))]
type_param: T::Type,
}

impl IntoPortable for TypeDefCompact {
type Output = TypeDefCompact<PortableForm>;

fn into_portable(self, registry: &mut Registry) -> Self::Output {
TypeDefCompact {
type_param: registry.register_type(&self.type_param),
}
}
}

impl TypeDefCompact {
/// Creates a new type wrapped in [`Compact`].
pub fn new(type_param: MetaType) -> Self {
Self { type_param }
}
}
impl<T> TypeDefCompact<T>
where
T: Form,
{
/// Returns the [`Compact`] wrapped type, i.e. the `T` in `Compact<T>`.
pub fn type_param(&self) -> &T::Type {
&self.type_param
}
}

/// A type describing a `PhantomData<T>` type.
///
/// In the context of SCALE encoded types, including `PhantomData<T>` types in
Expand Down
Loading