Rust wasm-bindgen struct with string - rust

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.

Related

Returning structure in Substrate RPC

We're trying to return structure in RPC, but as far as I understand it should be serializable:
error[E0277]: the trait bound `pallet_spaces::Space<T>: serde::de::Deserialize<'_>` is not satisfied
--> pallets/spaces/rpc/src/lib.rs:15:1
|
15 | #[rpc]
| ^^^^^^ the trait `serde::de::Deserialize<'_>` is not implemented for `pallet_spaces::Space<T>`
|
= note: required because of the requirements on the impl of `for<'de> serde::de::Deserialize<'de>` for `std::vec::Vec<pallet_spaces::Space<T>>`
= note: required because of the requirements on the impl of `serde::de::DeserializeOwned` for `std::vec::Vec<pallet_spaces::Space<T>>`
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
The problem is that we use T::Moment from pallet_timestamp and it's not serializable, so we stuck at this point:
error[E0277]: the trait bound `<T as pallet_timestamp::Trait>::Moment: _::_serde::Serialize` is not satisfied
--> pallets/spaces/src/lib.rs:25:5
|
25 | pub created: WhoAndWhen<T>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `_::_serde::Serialize` is not implemented for `<T as pallet_timestamp::Trait>::Moment`
|
= note: required because of the requirements on the impl of `_::_serde::Serialize` for `pallet_utils::WhoAndWhen<T>`
= note: required by `_::_serde::ser::SerializeStruct::serialize_field`
What can you suggest to easily return a structure like this?
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Serialize, Deserialize)]
pub struct Space<T: Trait> {
pub id: SpaceId,
pub created: WhoAndWhen<T>,
pub updated: Option<WhoAndWhen<T>>,
pub owner: T::AccountId,
// Can be updated by the owner:
pub parent_id: Option<SpaceId>,
pub handle: Option<Vec<u8>>,
pub content: Content,
pub hidden: bool,
pub posts_count: u32,
pub hidden_posts_count: u32,
pub followers_count: u32,
pub score: i32,
/// Allows to override the default permissions for this space.
pub permissions: Option<SpacePermissions>,
}
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug, Serialize, Deserialize)]
pub struct WhoAndWhen<T: Trait> {
pub account: T::AccountId,
pub block: T::BlockNumber,
pub time: T::Moment,
}
Your main problem is that you are mixing std and no-std here. Substrate only depends on serde in std mode, as you can learn about in literally any Cargo.toml file in the project.
Start by fixing this: You only derive serde::* when you are in std mode.
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)]
pub struct Space<T: Trait> {
// snip..
}

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?

How do I declare a struct that contains any kind of Deserializable/Serializable struct?

I am trying to declare a struct that contains another struct of any given type that can be Deserialize and Serialize.
#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T: Deserialize + Serialize> {
pub data: T,
}
Rust playground.
For that, I have tried to use trait bounds, using traits such as DeserializeOwned or Deserialize. Both have failed at compilation time with the following errors:
error[E0283]: type annotations required: cannot resolve `T: serde::Deserialize<'de>`
--> src/main.rs:9:28
|
9 | #[derive(Debug, Serialize, Deserialize)]
| ^^^^^^^^^^^
|
= note: required by `serde::Deserialize`
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> src/main.rs:10:19
|
10 | pub struct Foo<T: Deserialize + Serialize> {
| ^^^^^^^^^^^ explicit lifetime name needed here
I faced errors trying to add a lifetime since I am not using storing a reference but a value.
What is the most idiomatic way of declaring this type of struct?
Just don't place the bounds on the type:
use serde::{Deserialize, Serialize}; // 1.0.91
#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T> {
pub data: T,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Boo {
pub a: i64,
}
fn main() {
let data = Boo { a: 1 };
let wrap = Foo { data };
println!("{:?}", wrap);
}
Then, place the bounds on methods where you need that behavior:
fn use_it<T>(foo: Foo<T>)
where
Foo<T>: Serialize,
{
// ...
}
I found a solution thanks to a member of the Rust Discord who referred me to the following Github issue. The trick is not to use trait bounds but attribute bounds.
#[derive(Debug, Serialize, Deserialize)]
pub struct Foo<T> {
#[serde(bound(
serialize = "T: Serialize",
deserialize = "T: Deserialize<'de>",
))]
pub data: T,
}

How can I implement Borrow for a generic container in the case of the use of associated types?

I would like to implement Borrow for UserFriendlyDataStructure to provide access to the internal_data field within a function that should be agnostic with respect to the data provider. The type of the internal_data field is determined by the type associated to trait TraitA. Note that the Sealed trait ensures that none of these traits here can be implemented by other crates; this is functionality that strictly I provide. Furthermore, the type TraitA::Data is restricted by the empty trait DataTrait to prevent UserFriendlyDataStructure from being used as that type.
The following example explains best:
use std::borrow::Borrow;
use std::marker::PhantomData;
mod private {
pub trait Sealed {}
}
pub trait DataTrait: private::Sealed {}
pub trait TraitA: private::Sealed {
type Data: DataTrait;
}
pub struct UserFriendlyDataStructure<A: TraitA> {
internal_data: A::Data,
_a: PhantomData<A>,
}
impl<A: TraitA> Borrow<A::Data> for UserFriendlyDataStructure<A> {
fn borrow(&self) -> &A::Data {
&self.internal_data
}
}
pub fn important_function<A: TraitA, T: Borrow<A::Data>>(data: &T) {
let _internal_data = data.borrow();
// Do lots of work.
}
#[cfg(test)]
mod tests {
use super::*;
pub struct TestData(u32);
impl super::private::Sealed for TestData {}
impl DataTrait for TestData {}
pub struct TestProvider;
impl super::private::Sealed for TestProvider {}
impl TraitA for TestProvider {
type Data = TestData;
}
#[test]
fn basic_test() {
let ufds: UserFriendlyDataStructure<TestProvider> = UserFriendlyDataStructure {
internal_data: TestData(100),
_a: PhantomData::default(),
};
important_function::<TestProvider, _>(&ufds);
}
}
Unfortunately, the compiler complains:
error[E0119]: conflicting implementations of trait `std::borrow::Borrow<UserFriendlyDataStructure<_>>` for type `UserFriendlyDataStructure<_>`:
--> src/lib.rs:19:1
|
19 | impl<A: TraitA> Borrow<A::Data> for UserFriendlyDataStructure<A> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T> std::borrow::Borrow<T> for T
where T: ?Sized;
Is there a way to achieve what I am trying to do?
The compiler can be cajoled into accepting the code by introducing a redundant second type parameter that is constrained to be identical to A::Data:
impl<A, D> Borrow<D> for UserFriendlyDataStructure<A>
where
A: TraitA<Data = D>,
D: DataTrait,
{
fn borrow(&self) -> &A::Data {
&self.internal_data
}
}
I don't know why this works, and simply constraining A::Data: DataTrait doesn't. I think the compiler should accept both versions.
(Full code on the playground)
Edit: The fact that we need the redundant type D in the above code appears to be a shortcoming of the current compiler implementation, and is hopefully resolved once the experimental type inference engine chalk gets integrated in the compiler.

How to implement Eq and Hash for my own structs to use them as a HashMap key?

I have two structs, A and B, and I want to use a HashMap<A, B>. I have a piece of code like this:
use std::collections::HashMap;
pub struct A {
x: i32,
y: i32,
title: String,
}
pub struct B {
a: u32,
b: u32,
}
fn main() {
let map = HashMap::new();
map.insert(
A {
x: 10,
y: 20,
title: "test".to_string(),
},
B { a: 1, b: 2 },
);
}
But the compiler gives me these errors:
error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`
error[E0277]: the trait bound `A: std::hash::Hash` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::hash::Hash` is not implemented for `A`
I know that I must implement these traits, but after hours of searching the web, I have found nothing about implementing them.
My actual code is more complicated, and my structs contain other structs (I've edited the code).
I've implemented the Hash trait:
impl std::hash::Hash for A {
fn hash<H>(&self, state: &mut H)
where
H: std::hash::Hasher,
{
state.write_i32(self.x);
state.finish();
}
}
I made an implementation for PartialEq also:
impl PartialEq for A {
fn eq(&self, other: &A) -> bool {
self.x == other.x
}
}
But the compiler continues to complain, this time about Eq:
error[E0277]: the trait bound `A: std::cmp::Eq` is not satisfied
--> src/main.rs:16:9
|
16 | map.insert(
| ^^^^^^ the trait `std::cmp::Eq` is not implemented for `A`
How can I implement Eq? Why is there no implementation in the docs?
Eq is what we call a marker trait: it has no method on its own, it is just a way for the programmer to express that the struct verifies a certain property. You can implement it like this:
impl Eq for Application {}
Or alternatively, use #[derive(Eq)] on top of the Application declaration
Eq is a trait bound by PartialEq. This means that you can implement it only on structs that also implement PartialEq (which is the case here). By implementing Eq, you make the promise that your implementation of PartialEq is reflexive (see the docs for what it means).
You can have the compiler derive these instances for you by inserting the following before your struct declaration:
#[derive(PartialEq, Eq, Hash)]
pub struct A {
// ...
}
You could also implement them manually instead. If you want to do that, you should read the documentation on traits, Eq and Hash.
This is how the Rust documentation says you write your own implementation of Hash:
use std::hash::{Hash, Hasher};
struct Person {
id: u32,
name: String,
phone: u64,
}
impl Hash for Person {
fn hash<H: Hasher>(&self, state: &mut H) {
self.id.hash(state);
self.phone.hash(state);
}
}
Source: https://doc.rust-lang.org/std/hash/trait.Hash.html

Resources