Add new member variable to struct [duplicate] - rust

This question already has answers here:
Is it possible for one struct to extend an existing struct, keeping all the fields?
(5 answers)
Closed 3 years ago.
I'm trying to add new member variables to a struct in an impl block.
I'm using protoc-rust to procedurally generate Rust code from protocol buffers. In particular, it generates structs and methods for the messages defined in the protos. I need to add new members to these structs to initialize some WebAssembly::Instances off of a bytes object in the struct
The struct:
pub struct Module {
// message fields
pub module_name: ::std::string::String,
pub init_script: ::std::string::String,
pub JS_boiler_plate: ::std::string::String,
pub functions: ::protobuf::RepeatedField<Function>,
pub meta_data: ::std::string::String,
pub packager: ::std::string::String,
pub pure_wasm: bool,
pub wasm_binary: ::std::vec::Vec<u8>,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
What I want to do:
impl RPC_Module::Module {
self.wasm_instance: WebAssembly::Instance;
pub fn init(&mut self) -> Result<(), &'static str> {
// Init the instance based off of wasm_binary
let self.wasm_instance = WebAssembly::Instance::new()
}
}
What I get:
Compiling wRPC v0.1.0 (/Users/swarfield/Code/wRPC-Core/w-rpc-core)
error: expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `let`
--> src/protos/mod.rs:12:5
|
11 | impl RPC_Module::Module {
| - expected one of 11 possible tokens here
12 | let self.wasm_instance: WebAssembly::Instance;
| ^^^ unexpected token

I'm trying to add new member variables to a struct in an impl block.
Rust does not allow that.
What you can do is define another struct:
struct ModuleInstance {
wasm_instance: WebAssembly::Instance,
module: RPC_Module::Module
}
.. and return it from your init function.

Related

How to ignore generic argument for `#[derive(Debug)]`?

Here's a minimal example representing the type of problem I'm running into.
use core::fmt::Debug;
pub trait Config {
type A: Debug;
}
#[derive(Debug)]
pub struct Info<T: Config> {
pub field: T::A,
}
pub struct Conf;
impl Config for Conf {
type A = i128;
}
fn main() {
let s = Info::<Conf> {
field: 123
};
dbg!(s);
}
The framework that I'm using (Substrate) uses this concept of a Config trait that aggregates all generic types for a module (pallet).
The problem is that trying to #[derive(Debug)] for a struct that only uses the associated types of the object T implementing Config still requires that T implements Debug itself.
error[E0277]: `Conf` doesn't implement `Debug`
--> src/main.rs:22:5
|
22 | dbg!(s);
| ^^^^^^^ `Conf` cannot be formatted using `{:?}`
|
= help: the trait `Debug` is not implemented for `Conf`
= note: add `#[derive(Debug)]` to `Conf` or manually `impl Debug for Conf`
Moreover, I don't have control of the implementation of the Conf object. Regardless, I'm not trying to print anything about the Conf object itself.
Is there a way to make #[derive(Debug)] for Info ignore T?
Unfortunately, not as of today. You have to impl Debug manually:
impl<T: Config> fmt::Debug for Info<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Info").field("field", &self.field).finish()
}
}
There is an intent to make it possible to create what is called "perfect derive": derive bounds based on what needed and not the generic parameters. See for example this lang team design meeting proposal. But for now there is nothing.

Rust wasm-bindgen struct with string

I'm trying to export the following struct:
#[wasm_bindgen]
#[derive(Eq, PartialEq, Debug, Clone)]
pub enum TokenType {
KeywordLiteral,
NumberLiteral,
Operator,
Separator,
StringLiteral,
}
#[wasm_bindgen]
#[derive(Eq, PartialEq, Debug, Clone)]
pub struct Token {
pub typ: TokenType,
pub val: String,
}
but I'm getting:
error[E0277]: the trait bound `token::TokenType: std::marker::Copy` is not satisfied
--> src\tokenizer\token.rs:17:14
|
14 | #[wasm_bindgen]
| --------------- required by this bound in `__wbg_get_token_typ::assert_copy`
...
17 | pub typ: TokenType,
| ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `token::TokenType`
as well as:
error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
--> src\tokenizer\token.rs:18:14
|
14 | #[wasm_bindgen]
| --------------- required by this bound in `__wbg_get_token_val::assert_copy`
...
18 | pub val: String,
I can add #[derive(Copy)] to TokenType but not to String.
I'm new to rust so help is really appreciated.
According to wasm-bindgen#1985, public fields of structs are required to be Copy in order for the automatically generated accessors to function.
You can either make the fields private, or annotate them with #[wasm_bindgen(skip)], and then implement a getter and setter directly.
There is an example provided in wasm-bindgen's docs describing how to write these:
#[wasm_bindgen]
pub struct Baz {
field: i32,
}
#[wasm_bindgen]
impl Baz {
#[wasm_bindgen(constructor)]
pub fn new(field: i32) -> Baz {
Baz { field }
}
#[wasm_bindgen(getter)]
pub fn field(&self) -> i32 {
self.field
}
#[wasm_bindgen(setter)]
pub fn set_field(&mut self, field: i32) {
self.field = field;
}
}
When objects are shared between wasm and js, the js object only contains the pointer to the struct inside the wasm runtime's memory. When you access fields from JS, it goes through a defined property which makes a function call to the wasm code asking it for the property value (you can think of the wasm memory as a bit UInt8Array).
Requiring the objects to be Copy is probably done to avoid surprises when auto-generating these getters and setters. If you implement them manually, you can have the same behaviour in JS and be able to control what's being set on the rust side.

Complex nested trait struct

I am trying to decode APER messages and have issue creating nested structs with traits. I am using the asn1 library, but I have provided an example to illustrate the issue.
I need a model that can take a value that can be any struct (more or less).
Using boxes does not work since the serial trait is Sized. I cannot seem to get generics to work either since the decode function does not return the type.
How can I get past this?
use std::fmt::Error;
pub trait serial: Sized {
fn decode(&self) -> Result<Self, Error>;
}
pub struct Middle {
pub bottomCode: i32,
pub value: Box<dyn Bottom>,
}
impl serial for Middle {
fn decode(&self) -> Result<Self, Error> {
let code = 1;
if code == 1 {
Ok(Middle {
bottomCode: code,
value: Box::new(BottomA { a: 1 }),
})
} else {
Ok(Middle {
bottomCode: code,
value: Box::new(BottomB { b: 1 }),
})
}
}
}
pub trait Bottom: serial {}
pub struct BottomA {
pub a: i32,
}
impl Bottom for BottomA {}
pub struct BottomB {
pub b: i32,
}
impl Bottom for BottomB {}
error[E0038]: the trait `Bottom` cannot be made into an object
--> src/lib.rs:9:5
|
9 | pub value: Box<dyn Bottom>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Bottom` cannot be made into an object
|
= note: the trait cannot require that `Self : Sized`
error[E0277]: the trait bound `BottomA: serial` is not satisfied
--> src/lib.rs:32:6
|
32 | impl Bottom for BottomA {}
| ^^^^^^ the trait `serial` is not implemented for `BottomA`
error[E0277]: the trait bound `BottomB: serial` is not satisfied
--> src/lib.rs:37:6
|
37 | impl Bottom for BottomB {}
| ^^^^^^ the trait `serial` is not implemented for `BottomB`
The serial trait represents the APerElement trait I'm trying to use from the ASN1 library, thus the return type and signature.
I want to be able to call Middle.decode() which will result in all children being decoded alongside it, and any children of those etc. For that reason, it made sense to implement serial for it as well.
How would someone achieve such behavior? Is it possible?

Cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements [duplicate]

This question already has an answer here:
Why can Serde not derive Deserialize for a struct containing only a &Path?
(1 answer)
Closed 2 years ago.
Take the following code snippet (has to be run in cargo, so you can add the serde feature to num-bigint):
use num_bigint::BigInt;
use serde_derive::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize)]
pub struct Trade<'a> {
pub id: &'a str,
pub price: BigInt,
pub quantity: BigInt,
}
#[derive(Debug, Deserialize)]
pub struct TradeTable<'a> {
pub trades: Vec<Trade<'a>>,
}
fn main() {
let mut ether_trades: Vec<Trade> = Vec::new();
ether_trades.push(Trade {
id: "#1",
price: BigInt::from(100),
quantity: BigInt::from(2)
});
let mut trades: HashMap<&str, Vec<Trade>> = HashMap::new();
trades.insert("ETH", ether_trades);
println!("trades: {}", trades);
}
It yields this error when compiling:
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'de` due to conflicting requirements
And this note:
note: first, the lifetime cannot outlive the lifetime `'de` as defined on the impl at 34:17...
Now, I understand that I need to make 'a live shorter than 'de, but how can I do that? I don't know where the 'de lifetime is defined. I tried to use a colon like this:
'de: 'a
But that didn't work.
Please check that one
TL;DR
#[derive(Debug, Deserialize)]
pub struct TradeTable<'a> {
#[serde(borrow)]
pub trades: Vec<Trade<'a>>,
}

What is 'self: Box<Self>' on a method? [duplicate]

I wanted to create a method that only works where the self parameter was an Rc. I saw that I could use Box, so I thought I might try to mimic how that works:
use std::rc::Rc;
use std::sync::Arc;
struct Bar;
impl Bar {
fn consuming(self) {}
fn reference(&self) {}
fn mutable_reference(&mut self) {}
fn boxed(self: Box<Bar>) {}
fn ref_count(self: Rc<Bar>) {}
fn atomic_ref_count(self: Arc<Bar>) {}
}
fn main() {}
Yields these errors:
error[E0308]: mismatched method receiver
--> a.rs:11:18
|
11 | fn ref_count(self: Rc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::rc::Rc`
|
= note: expected type `Bar`
= note: found type `std::rc::Rc<Bar>`
error[E0308]: mismatched method receiver
--> a.rs:12:25
|
12 | fn atomic_ref_count(self: Arc<Bar>) {}
| ^^^^ expected struct `Bar`, found struct `std::sync::Arc`
|
= note: expected type `Bar`
= note: found type `std::sync::Arc<Bar>`
This is with Rust 1.15.1.
Before Rust 1.33, there are only four valid method receivers:
struct Foo;
impl Foo {
fn by_val(self: Foo) {} // a.k.a. by_val(self)
fn by_ref(self: &Foo) {} // a.k.a. by_ref(&self)
fn by_mut_ref(self: &mut Foo) {} // a.k.a. by_mut_ref(&mut self)
fn by_box(self: Box<Foo>) {} // no short form
}
fn main() {}
Originally, Rust didn't have this explicit self form, only self, &self, &mut self and ~self (the old name for Box). This changed so that only by-value and by-references have the short-hand built-in syntax, since they are the common cases, and have very key language properties, while all smart pointers (including Box) require the explicit form.
As of Rust 1.33, some additional selected types are available for use as self:
Rc
Arc
Pin
This means that the original example now works:
use std::{rc::Rc, sync::Arc};
struct Bar;
impl Bar {
fn consuming(self) { println!("self") }
fn reference(&self) { println!("&self") }
fn mut_reference(&mut self) { println!("&mut self") }
fn boxed(self: Box<Bar>) { println!("Box") }
fn ref_count(self: Rc<Bar>) { println!("Rc") }
fn atomic_ref_count(self: Arc<Bar>) { println!("Arc") }
}
fn main() {
Bar.consuming();
Bar.reference();
Bar.mut_reference();
Box::new(Bar).boxed();
Rc::new(Bar).ref_count();
Arc::new(Bar).atomic_ref_count();
}
However, the impl handling hasn't yet been fully generalised to match the syntax, so user-created types still don't work. Progress on this is being made under the feature flag arbitrary_self_types and discussion is taking place in the tracking issue 44874.
(Something to look forward to!)
It's now possible to use arbitrary types for self, including Arc<Self>, but the feature is considered unstable and thus requires adding this crate attribute:
#![feature(arbitrary_self_types)]
Using feature crate attributes requires using nightly Rust.

Resources