GenesisConfig { | missing `template_module` - substrate

I Need to create a pallet in substrate and i changed genesis build in substrate in my pallet.
when i run this command it show me this error :
GenesisConfig { ^^^^^^^^^^^^^ missing template_module
I dont know whats the problem , please guide me to solve this problem .
these code are my genesis build in my pallet :
#[cfg(feature = "std")]
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> GenesisConfig<T> {
GenesisConfig { default_price: T::DefaultMembershipPrice::get().saturated_into() }
}
}
#[pallet::genesis_build]
impl<T: Config> GenesisBuild<T> for GenesisConfig<T> {
fn build(&self) {
let n = T::DefaultNumMembership::get();
for i in 0u64..n {
let val = DaoMembership {
dna: None,
owner: None,
price: Some(self.default_price.clone()),
name: None,
};
<MembershipsPooled<T>>::insert(i, val);
log::info!("[info!!] generated membership and pooled: [{:?}]", i);
}
<CountForPooled<T>>::put(n);
<CountForOwned<T>>::put(0);
}
}
and this is configuratoin in chain_spec :
use node_template_runtime::{
AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,
SystemConfig, WASM_BINARY,
};
use sc_service::ChainType;
use sp_consensus_aura::sr25519::AuthorityId as AuraId;
use sp_core::{sr25519, Pair, Public};
use sp_finality_grandpa::AuthorityId as GrandpaId;
use sp_runtime::traits::{IdentifyAccount, Verify};
// The URL for the telemetry server.
// const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.
pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;
/// Generate a crypto pair from seed.
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
type AccountPublic = <Signature as Verify>::Signer;
/// Generate an account ID from seed.
pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId
where
AccountPublic: From<<TPublic::Pair as Pair>::Public>,
{
AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()
}
/// Generate an Aura authority key.
pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {
(get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))
}
pub fn development_config() -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;
Ok(ChainSpec::from_genesis(
// Name
"Development",
// ID
"dev",
ChainType::Development,
move || {
testnet_genesis(
wasm_binary,
// Initial PoA authorities
vec![authority_keys_from_seed("Alice")],
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
],
true,
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
None,
// Properties
None,
// Extensions
None,
))
}
pub fn local_testnet_config() -> Result<ChainSpec, String> {
let wasm_binary = WASM_BINARY.ok_or_else(|| "Development wasm not available".to_string())?;
Ok(ChainSpec::from_genesis(
// Name
"Local Testnet",
// ID
"local_testnet",
ChainType::Local,
move || {
testnet_genesis(
wasm_binary,
// Initial PoA authorities
vec![authority_keys_from_seed("Alice"), authority_keys_from_seed("Bob")],
// Sudo account
get_account_id_from_seed::<sr25519::Public>("Alice"),
// Pre-funded accounts
vec![
get_account_id_from_seed::<sr25519::Public>("Alice"),
get_account_id_from_seed::<sr25519::Public>("Bob"),
get_account_id_from_seed::<sr25519::Public>("Charlie"),
get_account_id_from_seed::<sr25519::Public>("Dave"),
get_account_id_from_seed::<sr25519::Public>("Eve"),
get_account_id_from_seed::<sr25519::Public>("Ferdie"),
get_account_id_from_seed::<sr25519::Public>("Alice//stash"),
get_account_id_from_seed::<sr25519::Public>("Bob//stash"),
get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),
get_account_id_from_seed::<sr25519::Public>("Dave//stash"),
get_account_id_from_seed::<sr25519::Public>("Eve//stash"),
get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),
],
true,
)
},
// Bootnodes
vec![],
// Telemetry
None,
// Protocol ID
None,
// Properties
None,
None,
// Extensions
None,
))
}
/// Configure initial storage state for FRAME modules.
fn testnet_genesis(
wasm_binary: &[u8],
initial_authorities: Vec<(AuraId, GrandpaId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool,
) -> GenesisConfig {
GenesisConfig {
system: SystemConfig {
// Add Wasm runtime to storage.
code: wasm_binary.to_vec(),
},
balances: BalancesConfig {
// Configure endowed accounts with initial balance of 1 << 60.
balances: endowed_accounts.iter().cloned().map(|k| (k, 1 << 60)).collect(),
},
aura: AuraConfig {
authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),
},
grandpa: GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.1.clone(), 1)).collect(),
},
sudo: SudoConfig {
// Assign network admin rights.
key: Some(root_key),
},
transaction_payment: Default::default(),
}
}

Related

Solana anchor Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account

I am struggling to make a simple solana anchor code example to work. All I am trying to do is to initialize a piece of data with only my wallet being allowed to do it.
Here is my Solana anchor code:
impl<'info> Validate<'info> for InitData<'info> {
fn validate(&self) -> Result<()> {
assert_keys_eq!(self.manager, Pubkey::from_str("2jEfqL1wFEHFjtbKEDoRottSBsij3v1j19aZueqrnj7v").unwrap());
Ok(())
}
}
#[program]
mod coinflip_bet {
use super::*;
#[access_control(ctx.accounts.validate())]
pub fn init_data(ctx: Context<InitData>) -> Result<()> {
Ok(())
}
}
#[derive(Accounts)]
pub struct InitData<'info> {
#[account(
init,
payer = manager,
space = 8 + 1,
seeds = [b"data-account", manager.key().as_ref()],
bump
)]
pub data_account: Account<'info, DummyData>,
#[account(mut)]
pub manager: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[account]
pub struct DummyData {
pub dummy: u8,
}
Here is my client code:
require('dotenv').config();
const PROGRAM_ID = process.env.PROGRAM_ID ?? '';
async function run() {
const connection = new Connection('http://127.0.0.1:8899');
const wallet = NodeWallet.local();
const programId = new PublicKey(PROGRAM_ID);
const [dataAccount,] = await PublicKey.findProgramAddress(
[Buffer.from("data-account"), wallet.publicKey.toBuffer()],
SystemProgram.programId
);
const provider = new anchor.AnchorProvider(
connection,
wallet,
anchor.AnchorProvider.defaultOptions()
);
//doesn't compile without this type checker skip
//#ts-ignore
const program = new anchor.Program(IDL, programId, provider);
await program.methods.initData()
.accounts(
{
dataAccount: dataAccount,
manager: wallet.publicKey,
systemProgram: SystemProgram.programId,
}
)
.signers(
[wallet.payer]
)
.rpc();
}
run().then(
() => process.exit(),
err => {
console.error(err);
process.exit(-1);
},
);
I'm on localhost:8899, launching this with 'solana-test-validator', 'anchor build', 'anchor deploy', 'ts-node src/init-data-account.ts'
I get this error:
SendTransactionError: failed to send transaction: Transaction simulation failed: Error processing Instruction 0: Cross-program invocation with unauthorized signer or writable account
logs: [
'Program 6YQukxVDKejG79RNSddyeEy6YQRVNkXSi4f5HuEyVMd6 invoke [1]',
'Program log: Instruction: InitData',
"7g32AFUNrTqyyuj1zbve6ui1aUzqzEvzpBc2tdNmqBjo's signer privilege escalated",
'Program 6YQukxVDKejG79RNSddyeEy6YQRVNkXSi4f5HuEyVMd6 consumed 6670 of 200000 compute units',
'Program 6YQukxVDKejG79RNSddyeEy6YQRVNkXSi4f5HuEyVMd6 failed: Cross-program invocation with unauthorized signer or writable account'
],
Can you please help me get rid off this error?
Update:
I updated my accounts struct:
#[derive(Accounts)]
pub struct InitData<'info> {
#[account(
init,
payer = manager,
space = 8 + 1,
seeds = [b"data-account", handler.key().as_ref()],
bump
)]
pub data_account: Account<'info, Escrow>,
/// CHECK:
#[account(mut)]
pub handler: AccountInfo<'info>,
#[account(mut)]
pub manager: Signer<'info>,
pub system_program: Program<'info, System>,
}
And I still have this error:
Cross-program invocation with unauthorized signer or writable account
Going by the accepted answer here, you need to use some variable aside from the 'manager' as seed e.g.
#[account(
init,
payer = manager,
space = 8 + 1,
seeds = [b"data-account", system_program.key().as_ref()],
bump
)]
pub data_account: Account<'info, DummyData>,
Don't forget to update your test to use the new key in findProgramAddress
The problem is this code:
const [dataAccount,] = await PublicKey.findProgramAddress(
[Buffer.from("data-account"), wallet.publicKey.toBuffer()],
SystemProgram.programId
);
It should be the id of the program instead of system program

How could I configure the reward for a substrate Aura validator?

Now that the PoA is running with multiple Aura validators in my substrate-node-template. How could I configure that reward amount or value for my Aura validators?
I got it working, PoA will reward the validator who created the block using the tip as the sample value for the fees, here are the steps:
Install the pallet_authorship
pallet-authorship = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.23" }
Configure the pallet to get the current author of the block
pub struct AuraAccountAdapter;
impl frame_support::traits::FindAuthor<AccountId> for AuraAccountAdapter {
fn find_author<'a, I>(digests: I) -> Option<AccountId>
where I: 'a + IntoIterator<Item=(frame_support::ConsensusEngineId, &'a [u8])>
{
pallet_aura::AuraAuthorId::<Runtime>::find_author(digests).and_then(|k| {
AccountId::try_from(k.as_ref()).ok()
})
}
}
impl pallet_authorship::Config for Runtime {
type FindAuthor = AuraAccountAdapter;
type UncleGenerations = ();
type FilterUncle = ();
type EventHandler = ();
}
Create OnUnbalanced implementation of Author and DealWithFees
use crate::{Authorship, Balances};
use frame_support::traits::{Imbalance, OnUnbalanced};
use crate::sp_api_hidden_includes_construct_runtime::hidden_include::traits::Currency;
use crate::AccountId;
type NegativeImbalance = <Balances as Currency<AccountId>>::NegativeImbalance;
pub struct Author;
impl OnUnbalanced<NegativeImbalance> for Author {
fn on_nonzero_unbalanced(amount: NegativeImbalance) {
if let Some(author) = Authorship::author() {
Balances::resolve_creating(&author, amount);
}
}
}
pub struct DealWithFees;
impl OnUnbalanced<NegativeImbalance> for DealWithFees {
fn on_unbalanceds<B>(mut fees_then_tips: impl Iterator<Item = NegativeImbalance>) {
if let Some(fees) = fees_then_tips.next() {
let mut split = fees.ration(80, 20);
if let Some(tips) = fees_then_tips.next() {
// for tips, if any, 80% to treasury, 20% to block author (though this can be anything)
tips.ration_merge_into(80, 20, &mut split);
}
//Treasury::on_unbalanced(split.0);
Author::on_unbalanced(split.1);
}
}
}
Call the implementation in the pallet_transaction_payment tuple OnChargeTransaction
impl pallet_transaction_payment::Config for Runtime {
type OnChargeTransaction = CurrencyAdapter<Balances, crate::impls::DealWithFees>;
type OperationalFeeMultiplier = ConstU8<5>;
type WeightToFee = IdentityFee<Balance>;
type LengthToFee = IdentityFee<Balance>;
type FeeMultiplierUpdate = ();
}
Also added in my blog: https://hgminerva.wordpress.com/2022/06/21/how-to-pay-the-block-author-validator-on-a-proof-of-authority-poa-consensus-in-substrate/

egui combobox vector for selected

I am trying to use a vector instead of the enum specified in the docs but I have no clue how to implement the selected part. My current code is
egui::ComboBox::from_label("Take your pick")
.selected_text(format!("{}", self.radio[0]))
.show_ui(ui, |ui| {
for i in 0..self.radio.len() {
ui.selectable_value(&mut &self.radio, &self.radio, &self.radio[i]);
}
});
can anyone give me an idea. I do not mind using enum but I do not know how many things will be in it.
I stumbled on the same problem, and I have found a solution. The solution is to add a new Variable to the self. Here is a basic example on the Enum select and the Vector select. Hope this helps out anyone who has run into the same problem.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use eframe::egui;
fn main() {
let options = eframe::NativeOptions::default();
eframe::run_native(
"Test Select with Enum and Vector",
options,
Box::new(|_cc| Box::new(MyApp::default())),
);
}
#[derive(PartialEq)]
#[derive(Debug)]
enum OS_Select {
First,
Second,
Third,
}
struct MyApp {
selected: usize,
radio: OS_Select,
selector_vec: Vec<String>,
}
impl Default for MyApp {
fn default() -> Self {
Self {
selected: 0,
radio: OS_Select::First,
selector_vec: get_vec(),
}
}
}
fn get_vec() -> Vec<String> {
let vecs = [
"1".to_string(),
"2".to_string(),
"3".to_string(),
].to_vec();
return vecs;
}
impl eframe::App for MyApp {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| {
ui.heading("Select with enum");
ui.horizontal(|ui| {
ui.radio_value(&mut self.radio, OS_Select::First, "First");
ui.radio_value(&mut self.radio, OS_Select::Second, "Second");
ui.radio_value(&mut self.radio, OS_Select::Third, "Third");
});
ui.end_row();
ui.heading("Select with Vectors");
egui::ComboBox::from_label("Take your pick")
.selected_text(format!("{}", &self.selector_vec[self.selected]))
.show_ui(ui, |ui| {
for i in 0..self.selector_vec.len() {
let value = ui.selectable_value(&mut &self.selector_vec[i], &self.selector_vec[self.selected], &self.selector_vec[i]);
if (value.clicked()) {
self.selected = i;
}
}
});
ui.end_row();
});
}
fn save(&mut self, _storage: &mut dyn eframe::Storage) {}
fn on_close_event(&mut self) -> bool {
true
}
fn on_exit(&mut self, _gl: Option<&eframe::glow::Context>) {}
fn auto_save_interval(&self) -> std::time::Duration {
std::time::Duration::from_secs(30)
}
fn max_size_points(&self) -> egui::Vec2 {
egui::Vec2::INFINITY
}
fn clear_color(&self, _visuals: &egui::Visuals) -> egui::Rgba {
// NOTE: a bright gray makes the shadows of the windows look weird.
// We use a bit of transparency so that if the user switches on the
// `transparent()` option they get immediate results.
egui::Color32::from_rgba_unmultiplied(12, 12, 12, 180).into()
// _visuals.window_fill() would also be a natural choice
}
fn persist_native_window(&self) -> bool {
true
}
fn persist_egui_memory(&self) -> bool {
true
}
fn warm_up_enabled(&self) -> bool {
false
}
fn post_rendering(&mut self, _window_size_px: [u32; 2], _frame: &eframe::Frame) {}
}

How do you pass and handle arguments to a `ChainExtension`?

I have an ink! contract which calls a extension method fetch_random().
// runtime/src/lib.rs
pub struct FetchRandomExtension;
impl ChainExtension<Runtime> for FetchRandomExtension {
fn call<E: Ext>(
func_id: u32,
env: Environment<E, InitState>,
) -> Result<RetVal, DispatchError>
where
<E::T as SysConfig>::AccountId:
UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,
{
match func_id {
1101 => {
let mut env = env.buf_in_buf_out();
let random_seed = crate::RandomnessCollectiveFlip::random_seed().0;
let random_slice = random_seed.encode();
env.write(&random_slice, false, None).map_err(|_| {
DispatchError::Other("ChainExtension failed to call random")
})?;
}
_ => {
return Err(DispatchError::Other("Unimplemented func_id"))
}
}
Ok(RetVal::Converging(0))
}
fn enabled() -> bool {
true
}
}
// contract/lib.rs
let new_random = self.env().extension().fetch_random()?;
How can can I write the extension handler to receive arguments such as let new_random = self.env().extension().fetch_random(1, "hello", true)?;?
You can have a complete example on GitHub here.
Here's the working code:
#![cfg_attr(not(feature = "std"), no_std)]
use ink_env::Environment;
use ink_lang as ink;
/// This is an example of how ink! contract should
/// call substrate runtime `RandomnessCollectiveFlip::random_seed`.
/// Define the operations to interact with the substrate runtime
#[ink::chain_extension]
pub trait FetchRandom {
type ErrorCode = RandomReadErr;
/// Note: this gives the operation a corresponding `func_id` (1101 in this
case),
/// and the chain-side chain extension will get the `func_id` to do further operations.
#[ink(extension = 1101, returns_result = false)]
fn fetch_random() -> [u8; 32];
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, scale::Encode, scale::Decode)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum RandomReadErr {
FailGetRandomSource,
}
impl ink_env::chain_extension::FromStatusCode for RandomReadErr {
fn from_status_code(status_code: u32) -> Result<(), Self> {
match status_code {
0 => Ok(()),
1 => Err(Self::FailGetRandomSource),
_ => panic!("encountered unknown status code"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "std", derive(scale_info::TypeInfo))]
pub enum CustomEnvironment {}
impl Environment for CustomEnvironment {
const MAX_EVENT_TOPICS: usize =
<ink_env::DefaultEnvironment as Environment>::MAX_EVENT_TOPICS;
type AccountId = <ink_env::DefaultEnvironment as Environment>::AccountId;
type Balance = <ink_env::DefaultEnvironment as Environment>::Balance;
type Hash = <ink_env::DefaultEnvironment as Environment>::Hash;
type BlockNumber = <ink_env::DefaultEnvironment as Environment>::BlockNumber;
type Timestamp = <ink_env::DefaultEnvironment as Environment>::Timestamp;
type RentFraction = <ink_env::DefaultEnvironment as Environment>::RentFraction;
type ChainExtension = FetchRandom;
}
#[ink::contract(env = crate::CustomEnvironment)]
mod rand_extension {
use super::RandomReadErr;
/// Defines the storage of your contract.
/// Here we store the random seed fetched from the chain
#[ink(storage)]
pub struct RandExtension {
/// Stores a single `bool` value on the storage.
value: [u8; 32],
}
#[ink(event)]
pub struct RandomUpdated {
#[ink(topic)]
new: [u8; 32],
}
impl RandExtension {
/// Constructor that initializes the `bool` value to the given `init_value`.
#[ink(constructor)]
pub fn new(init_value: [u8; 32]) -> Self {
Self { value: init_value }
}
/// Constructor that initializes the `bool` value to `false`.
///
/// Constructors can delegate to other constructors.
#[ink(constructor)]
pub fn default() -> Self {
Self::new(Default::default())
}
/// update the value from runtime random source
#[ink(message)]
pub fn update(&mut self) -> Result<(), RandomReadErr> {
// Get the on-chain random seed
let new_random = self.env().extension().fetch_random()?;
self.value = new_random;
// emit the RandomUpdated event when the random seed
// is successfully fetched.
self.env().emit_event(RandomUpdated { new: new_random });
Ok(())
}
/// Simply returns the current value.
#[ink(message)]
pub fn get(&self) -> [u8; 32] {
self.value
}
}
/// Unit tests in Rust are normally defined within such a `#[cfg(test)]`
#[cfg(test)]
mod tests {
/// Imports all the definitions from the outer scope so we can use them here.
use super::*;
use ink_lang as ink;
/// We test if the default constructor does its job.
#[ink::test]
fn default_works() {
let rand_extension = RandExtension::default();
assert_eq!(rand_extension.get(), [0; 32]);
}
}
}
You should be able to access the arguments through one of the functions on the <'a, 'b, E: Ext, S: state::BufIn> Environment<'a, 'b, E, S> implementation of Environment, e.g. read, read_as, read_as_unbounded. Please see the Environment struct for more information on this.
The rand-extension example you've cited here has also been updated to demonstrate passing an argument to the chain extension in the runtime. See that example here. You should be able to follow that example and implement the changes.

Is there a way to directly access a field value in an enum struct without pattern matching?

I wish that enums in Rust can be used like Haskell's productive type. I want to
access a field's value directly
assign a field's value directly or make a clone with the changing value.
Directly means that not using too long pattern matching code, but just could access like let a_size = a.size.
In Haskell:
data TypeAB = A {size::Int, name::String} | B {size::Int, switch::Bool} deriving Show
main = do
let a = A 1 "abc"
let b = B 1 True
print (size a) -- could access a field's value directly
print (name a) -- could access a field's value directly
print (switch b) -- could access a field's value directly
let aa = a{size=2} -- could make a clone directly with the changing value
print aa
I tried two styles of Rust enum definition like
Style A:
#[derive(Debug)]
enum EntryType {
A(TypeA),
B(TypeB),
}
#[derive(Debug)]
struct TypeA {
size: u32,
name: String,
}
#[derive(Debug)]
struct TypeB {
size: u32,
switch: bool,
}
fn main() {
let mut ta = TypeA {
size: 3,
name: "TAB".to_string(),
};
println!("{:?}", &ta);
ta.size = 2;
ta.name = "TCD".to_string();
println!("{:?}", &ta);
let mut ea = EntryType::A(TypeA {
size: 1,
name: "abc".to_string(),
});
let mut eb = EntryType::B(TypeB {
size: 1,
switch: true,
});
let vec_ab = vec![&ea, &eb];
println!("{:?}", &ea);
println!("{:?}", &eb);
println!("{:?}", &vec_ab);
// Want to do like `ta.size = 2` for ea
// Want to do like `ta.name = "bcd".to_string()` for ea
// Want to do like `tb.switch = false` for eb
// ????
println!("{:?}", &ea);
println!("{:?}", &eb);
println!("{:?}", &vec_ab);
}
Style B:
#[derive(Debug)]
enum TypeCD {
TypeC { size: u32, name: String },
TypeD { size: u32, switch: bool },
}
fn main() {
// NOTE: Rust requires representative struct name before each constructor
// TODO: Check constructor name can be duplicated
let mut c = TypeCD::TypeC {
size: 1,
name: "abc".to_string(),
};
let mut d = TypeCD::TypeD {
size: 1,
switch: true,
};
let vec_cd = vec![&c, &d];
println!("{:?}", &c);
println!("{:?}", &d);
println!("{:?}", &vec_cd);
// Can't access a field's value like
// let c_size = c.size
let c_size = c.size; // [ERROR]: No field `size` on `TypeCD`
let c_name = c.name; // [ERROR]: No field `name` on `TypeCD`
let d_switch = d.switch; // [ERROR]: No field `switch` on `TypeCD`
// Can't change a field's value like
// c.size = 2;
// c.name = "cde".to_string();
// d.switch = false;
println!("{:?}", &c);
println!("{:?}", &d);
println!("{:?}", &vec_cd);
}
I couldn't access/assign values directly in any style. Do I have to implement functions or a trait just to access a field's value? Is there some way of deriving things to help this situation?
What about style C:
#[derive(Debug)]
enum Color {
Green { name: String },
Blue { switch: bool },
}
#[derive(Debug)]
struct Something {
size: u32,
color: Color,
}
fn main() {
let c = Something {
size: 1,
color: Color::Green {
name: "green".to_string(),
},
};
let d = Something {
size: 2,
color: Color::Blue { switch: true },
};
let vec_cd = vec![&c, &d];
println!("{:?}", &c);
println!("{:?}", &d);
println!("{:?}", &vec_cd);
let _ = c.size;
}
If all variant have something in common, why separate them?
Of course, I need to access not common field too.
This would imply that Rust should define what to do when the actual type at runtime doesn't contain the field you required. So, I don't think Rust would add this one day.
You could do it yourself. It will require some lines of code, but that matches the behavior of your Haskell code. However, I don't think this is the best thing to do. Haskell is Haskell, I think you should code in Rust and not try to code Haskell by using Rust. That a general rule, some feature of Rust come directly from Haskell, but what you want here is very odd in my opinion for Rust code.
#[derive(Debug)]
enum Something {
A { size: u32, name: String },
B { size: u32, switch: bool },
}
impl Something {
fn size(&self) -> u32 {
match self {
Something::A { size, .. } => *size,
Something::B { size, .. } => *size,
}
}
fn name(&self) -> &String {
match self {
Something::A { name, .. } => name,
Something::B { .. } => panic!("Something::B doesn't have name field"),
}
}
fn switch(&self) -> bool {
match self {
Something::A { .. } => panic!("Something::A doesn't have switch field"),
Something::B { switch, .. } => *switch,
}
}
fn new_size(&self, size: u32) -> Something {
match self {
Something::A { name, .. } => Something::A {
size,
name: name.clone(),
},
Something::B { switch, .. } => Something::B {
size,
switch: *switch,
},
}
}
// etc...
}
fn main() {
let a = Something::A {
size: 1,
name: "Rust is not haskell".to_string(),
};
println!("{:?}", a.size());
println!("{:?}", a.name());
let b = Something::B {
size: 1,
switch: true,
};
println!("{:?}", b.switch());
let aa = a.new_size(2);
println!("{:?}", aa);
}
I think there is currently no built-in way of accessing size directly on the enum type. Until then, enum_dispatch or a macro-based solution may help you.

Resources