mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-09 08:18:04 +00:00
@@ -0,0 +1,98 @@
|
||||
// This file is part of Substrate.
|
||||
|
||||
// Copyright (C) 2021 Parity Technologies (UK) Ltd.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Derive Clone but do not bound any generic.
|
||||
pub fn derive_default_no_bound(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
let input: syn::DeriveInput = match syn::parse(input) {
|
||||
Ok(input) => input,
|
||||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
|
||||
let name = &input.ident;
|
||||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
|
||||
|
||||
let impl_ = match input.data {
|
||||
syn::Data::Struct(struct_) => match struct_.fields {
|
||||
syn::Fields::Named(named) => {
|
||||
let fields = named.named.iter()
|
||||
.map(|i| &i.ident)
|
||||
.map(|i| quote::quote_spanned!(i.span() =>
|
||||
#i: core::default::Default::default()
|
||||
));
|
||||
|
||||
quote::quote!( Self { #( #fields, )* } )
|
||||
},
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
let fields = unnamed.unnamed.iter().enumerate()
|
||||
.map(|(i, _)| syn::Index::from(i))
|
||||
.map(|i| quote::quote_spanned!(i.span() =>
|
||||
core::default::Default::default()
|
||||
));
|
||||
|
||||
quote::quote!( Self ( #( #fields, )* ) )
|
||||
},
|
||||
syn::Fields::Unit => {
|
||||
quote::quote!( Self )
|
||||
}
|
||||
},
|
||||
syn::Data::Enum(enum_) => {
|
||||
if let Some(first_variant) = enum_.variants.first() {
|
||||
let variant_ident = &first_variant.ident;
|
||||
match &first_variant.fields {
|
||||
syn::Fields::Named(named) => {
|
||||
let fields = named.named.iter()
|
||||
.map(|i| &i.ident)
|
||||
.map(|i| quote::quote_spanned!(i.span() =>
|
||||
#i: core::default::Default::default()
|
||||
));
|
||||
|
||||
quote::quote!( #name :: #ty_generics :: #variant_ident { #( #fields, )* } )
|
||||
},
|
||||
syn::Fields::Unnamed(unnamed) => {
|
||||
let fields = unnamed.unnamed.iter().enumerate()
|
||||
.map(|(i, _)| syn::Index::from(i))
|
||||
.map(|i| quote::quote_spanned!(i.span() =>
|
||||
core::default::Default::default()
|
||||
));
|
||||
|
||||
quote::quote!( #name :: #ty_generics :: #variant_ident ( #( #fields, )* ) )
|
||||
},
|
||||
syn::Fields::Unit => quote::quote!( #name :: #ty_generics :: #variant_ident ),
|
||||
}
|
||||
} else {
|
||||
quote::quote!( Self )
|
||||
}
|
||||
|
||||
},
|
||||
syn::Data::Union(_) => {
|
||||
let msg = "Union type not supported by `derive(CloneNoBound)`";
|
||||
return syn::Error::new(input.span(), msg).to_compile_error().into()
|
||||
},
|
||||
};
|
||||
|
||||
quote::quote!(
|
||||
const _: () = {
|
||||
impl #impl_generics core::default::Default for #name #ty_generics #where_clause {
|
||||
fn default() -> Self {
|
||||
#impl_
|
||||
}
|
||||
}
|
||||
};
|
||||
).into()
|
||||
}
|
||||
@@ -27,6 +27,7 @@ mod transactional;
|
||||
mod debug_no_bound;
|
||||
mod clone_no_bound;
|
||||
mod partial_eq_no_bound;
|
||||
mod default_no_bound;
|
||||
|
||||
pub(crate) use storage::INHERENT_INSTANCE_NAME;
|
||||
use proc_macro::TokenStream;
|
||||
@@ -412,6 +413,12 @@ pub fn derive_eq_no_bound(input: TokenStream) -> TokenStream {
|
||||
).into()
|
||||
}
|
||||
|
||||
/// derive `Default` but do no bound any generic. Docs are at `frame_support::DefaultNoBound`.
|
||||
#[proc_macro_derive(DefaultNoBound)]
|
||||
pub fn derive_default_no_bound(input: TokenStream) -> TokenStream {
|
||||
default_no_bound::derive_default_no_bound(input)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn require_transactional(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
transactional::require_transactional(attr, input).unwrap_or_else(|e| e.to_compile_error().into())
|
||||
|
||||
@@ -560,6 +560,25 @@ pub use frame_support_procedural::PartialEqNoBound;
|
||||
/// ```
|
||||
pub use frame_support_procedural::DebugNoBound;
|
||||
|
||||
/// Derive [`Default`] but do not bound any generic.
|
||||
///
|
||||
/// This is useful for type generic over runtime:
|
||||
/// ```
|
||||
/// # use frame_support::DefaultNoBound;
|
||||
/// # use core::default::Default;
|
||||
/// trait Config {
|
||||
/// type C: Default;
|
||||
/// }
|
||||
///
|
||||
/// // Foo implements [`Default`] because `C` bounds [`Default`].
|
||||
/// // Otherwise compilation will fail with an output telling `c` doesn't implement [`Default`].
|
||||
/// #[derive(DefaultNoBound)]
|
||||
/// struct Foo<T: Config> {
|
||||
/// c: T::C,
|
||||
/// }
|
||||
/// ```
|
||||
pub use frame_support_procedural::DefaultNoBound;
|
||||
|
||||
/// Assert the annotated function is executed within a storage transaction.
|
||||
///
|
||||
/// The assertion is enabled for native execution and when `debug_assertions` are enabled.
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Tests for DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, and RuntimeDebugNoBound
|
||||
//! Tests for DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound, and
|
||||
//! RuntimeDebugNoBound
|
||||
|
||||
use frame_support::{DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound};
|
||||
use frame_support::{
|
||||
DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, RuntimeDebugNoBound, DefaultNoBound,
|
||||
};
|
||||
|
||||
#[derive(RuntimeDebugNoBound)]
|
||||
struct Unnamed(u64);
|
||||
@@ -29,7 +32,7 @@ fn runtime_debug_no_bound_display_correctly() {
|
||||
}
|
||||
|
||||
trait Config {
|
||||
type C: std::fmt::Debug + Clone + Eq + PartialEq;
|
||||
type C: std::fmt::Debug + Clone + Eq + PartialEq + Default;
|
||||
}
|
||||
|
||||
struct Runtime;
|
||||
@@ -39,7 +42,7 @@ impl Config for Runtime {
|
||||
type C = u32;
|
||||
}
|
||||
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound)]
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)]
|
||||
struct StructNamed<T: Config, U, V> {
|
||||
a: u32,
|
||||
b: u64,
|
||||
@@ -56,6 +59,12 @@ fn test_struct_named() {
|
||||
phantom: Default::default(),
|
||||
};
|
||||
|
||||
let a_default: StructNamed::<Runtime, ImplNone, ImplNone> = Default::default();
|
||||
assert_eq!(a_default.a, 0);
|
||||
assert_eq!(a_default.b, 0);
|
||||
assert_eq!(a_default.c, 0);
|
||||
assert_eq!(a_default.phantom, Default::default());
|
||||
|
||||
let a_2 = a_1.clone();
|
||||
assert_eq!(a_2.a, 1);
|
||||
assert_eq!(a_2.b, 2);
|
||||
@@ -76,7 +85,7 @@ fn test_struct_named() {
|
||||
assert!(b != a_1);
|
||||
}
|
||||
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound)]
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)]
|
||||
struct StructUnnamed<T: Config, U, V>(u32, u64, T::C, core::marker::PhantomData<(U, V)>);
|
||||
|
||||
#[test]
|
||||
@@ -88,6 +97,12 @@ fn test_struct_unnamed() {
|
||||
Default::default(),
|
||||
);
|
||||
|
||||
let a_default: StructUnnamed::<Runtime, ImplNone, ImplNone> = Default::default();
|
||||
assert_eq!(a_default.0, 0);
|
||||
assert_eq!(a_default.1, 0);
|
||||
assert_eq!(a_default.2, 0);
|
||||
assert_eq!(a_default.3, Default::default());
|
||||
|
||||
let a_2 = a_1.clone();
|
||||
assert_eq!(a_2.0, 1);
|
||||
assert_eq!(a_2.1, 2);
|
||||
@@ -108,7 +123,7 @@ fn test_struct_unnamed() {
|
||||
assert!(b != a_1);
|
||||
}
|
||||
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound)]
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)]
|
||||
enum Enum<T: Config, U, V> {
|
||||
VariantUnnamed(u32, u64, T::C, core::marker::PhantomData<(U, V)>),
|
||||
VariantNamed {
|
||||
@@ -121,6 +136,32 @@ enum Enum<T: Config, U, V> {
|
||||
VariantUnit2,
|
||||
}
|
||||
|
||||
// enum that will have a named default.
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)]
|
||||
enum Enum2<T: Config> {
|
||||
VariantNamed {
|
||||
a: u32,
|
||||
b: u64,
|
||||
c: T::C,
|
||||
},
|
||||
VariantUnnamed(u32, u64, T::C),
|
||||
VariantUnit,
|
||||
VariantUnit2,
|
||||
}
|
||||
|
||||
// enum that will have a unit default.
|
||||
#[derive(DebugNoBound, CloneNoBound, EqNoBound, PartialEqNoBound, DefaultNoBound)]
|
||||
enum Enum3<T: Config> {
|
||||
VariantUnit,
|
||||
VariantNamed {
|
||||
a: u32,
|
||||
b: u64,
|
||||
c: T::C,
|
||||
},
|
||||
VariantUnnamed(u32, u64, T::C),
|
||||
VariantUnit2,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_enum() {
|
||||
type TestEnum = Enum::<Runtime, ImplNone, ImplNone>;
|
||||
@@ -131,6 +172,22 @@ fn test_enum() {
|
||||
let variant_2 = TestEnum::VariantUnit;
|
||||
let variant_3 = TestEnum::VariantUnit2;
|
||||
|
||||
let default: TestEnum = Default::default();
|
||||
assert_eq!(
|
||||
default,
|
||||
// first variant is default.
|
||||
TestEnum::VariantUnnamed(0, 0, 0, Default::default())
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Enum2::<Runtime>::default(),
|
||||
Enum2::<Runtime>::VariantNamed { a: 0, b: 0, c: 0},
|
||||
);
|
||||
assert_eq!(
|
||||
Enum3::<Runtime>::default(),
|
||||
Enum3::<Runtime>::VariantUnit,
|
||||
);
|
||||
|
||||
assert!(variant_0 != variant_0_bis);
|
||||
assert!(variant_1 != variant_1_bis);
|
||||
assert!(variant_0 != variant_1);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
trait Config {
|
||||
type C;
|
||||
}
|
||||
|
||||
#[derive(frame_support::DefaultNoBound)]
|
||||
struct Foo<T: Config> {
|
||||
c: T::C,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
@@ -0,0 +1,7 @@
|
||||
error[E0277]: the trait bound `<T as Config>::C: std::default::Default` is not satisfied
|
||||
--> $DIR/default.rs:7:2
|
||||
|
|
||||
7 | c: T::C,
|
||||
| ^ the trait `std::default::Default` is not implemented for `<T as Config>::C`
|
||||
|
|
||||
= note: required by `std::default::Default::default`
|
||||
Reference in New Issue
Block a user