I have the following two structs for which I derive serde traits.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Item<'a> {
pub id: &'a str,
pub name: &'a str
}
#[derive(Serialize, Deserialize)]
struct Set<'a> {
items: Vec<Item<'a>>
}
When I try to compile this, I am getting am getting the following error message to ensure that lifetime parameter 'de from Deserialize needs to outlife lifetime parameter 'a:
15 | #[derive(Serialize, Deserialize)]
| ----------- lifetime `'de` defined here
16 | struct Set<'a> {
| -- lifetime `'a` defined here
17 | sets: Vec<Item<'a>>
| ^^^^ requires that `'de` must outlive `'a`
|
= help: consider adding the following bound: `'de: 'a`
But when I add the required bound as follows, I am getting an error message that 'de is not used.
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
pub struct Item<'a> {
pub id: &'a str,
pub name: &'a str
}
#[derive(Serialize, Deserialize)]
struct Set<'a, 'de: 'a> {
items: Vec<Item<'a>>
}
16 | struct Set<'a, 'de: 'a> {
| ^^^ unused parameter
|
= help: consider removing `'de`, referring to it in a field, or using a marker such as `PhantomData`
How can I fix this?
You need to add #[serde(borrow)] to the sets field:
#[derive(Serialize, Deserialize)]
struct Set<'a> {
#[serde(borrow)]
items: Vec<Item<'a>>,
}
This will bound the 'de lifetime in the generated code on 'a. Note that this happens implicitly for fields of type &str or &[u8], but for anything else you need to expicitly request the trait bound.
Related
This question already has answers here:
How do I implement Copy and Clone for a type that contains a String (or any type that doesn't implement Copy)?
(2 answers)
Closed 8 months ago.
When I added copy in the rust struct like this:
fn main() {
}
#[derive(Debug, Default, Copy)]
pub struct BillRecord {
pub id: Option<i64>,
pub remark: Option<String>
}
shows error info when compile:
➜ rust-learn git:(group-by) ✗ cargo build
Compiling rust-learn v0.1.0 (/Users/xiaoqiangjiang/source/reddwarf/backend/rust-learn)
error[E0204]: the trait `Copy` may not be implemented for this type
--> src/main.rs:7:26
|
7 | #[derive(Debug, Default, Copy)]
| ^^^^
...
10 | pub remark: Option<String>
| -------------------------- this field does not implement `Copy`
|
note: the `Copy` impl for `std::option::Option<std::string::String>` requires that `std::string::String: Copy`
--> src/main.rs:10:5
|
10 | pub remark: Option<String>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0204`.
error: could not compile `rust-learn` due to previous error
what should I do to implement the Copy? I just want to implement the Copy trait, did not want to implement the Clone trait. this code block need to implement the Copy trait:
fn main() {
let source = &BillRecord{ id: None, remark: None };
let a = BillRecordResponse{ id: source.id, remark: source.remark };
}
#[derive(Debug, Serialize, Default, Clone)]
pub struct BillRecord {
pub id: Option<i64>,
pub remark: Option<String>
}
use serde::Serialize;
#[derive(Debug, Serialize, Default)]
pub struct BillRecordResponse {
pub id: Option<i64>,
pub remark: Option<String>
}
when I compile this code block, shows error:
error[E0507]: cannot move out of `source.remark` which is behind a shared reference
--> src/main.rs:5:56
|
5 | let a = BillRecordResponse{ id: source.id, remark: source.remark };
| ^^^^^^^^^^^^^ move occurs because `source.remark` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
|
help: consider borrowing the `Option`'s content
|
5 | let a = BillRecordResponse{ id: source.id, remark: source.remark.as_ref() };
| +++++++++
For more information about this error, try `rustc --explain E0507`.
warning: `rust-learn` (bin "rust-learn") generated 1 warning
error: could not compile `rust-learn` due to previous error; 1 warning emitted
The error message is saying that String does not implement Copy (so Option<String> does not either), so therefore Copy cannot be derived for your struct (which contains an Option<String>).
As Copy signifies cheap copyability, and a String may contain a lot of characters (making it not cheaply copyable), String should not implement Copy. Therefore you should not try to implement Copy, but instead implement Clone and use clone() where necessary:
fn main() {
let source = &BillRecord{ id: None, remark: None };
let a = BillRecordResponse{ id: source.id, remark: source.remark.clone() };
}
#[derive(Debug, Serialize, Default, Clone)]
pub struct BillRecord {
pub id: Option<i64>,
pub remark: Option<String>
}
use serde::Serialize;
#[derive(Debug, Serialize, Default, Clone)]
pub struct BillRecordResponse {
pub id: Option<i64>,
pub remark: Option<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.
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..
}
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,
}
My type A, which can contain anything that implements trait Trait, is serialisable, although the type implementing the trait Trait might not be. In my case, it cannot be - it's a private asymmetric key:
extern crate serde;
#[macro_use]
extern crate serde_derive;
use serde::de::DeserializeOwned;
use serde::Serialize;
trait Trait {
type SerialisableType: Clone + Serialize + DeserializeOwned;
fn inner(&self) -> &Self::SerialisableType;
}
#[derive(Serialize, Deserialize)]
enum A<T: Trait> {
Variant0(B<T>), // *** NOTE: Compiles if this is commented ***
Variant1(T::SerialisableType),
}
#[derive(Serialize, Deserialize)]
struct B<T: Trait> {
inner: T::SerialisableType,
}
// ==============================================
struct NonSerialisable {
serialisable: Serialisable,
}
impl Trait for NonSerialisable {
type SerialisableType = Serialisable;
fn inner(&self) -> &Self::SerialisableType {
&self.serialisable
}
}
#[derive(Clone, Serialize, Deserialize)]
struct Serialisable(Vec<u8>);
#[derive(Serialize, Deserialize)]
enum E {
Variant0(A<NonSerialisable>),
Variant1(B<NonSerialisable>),
}
fn main() {}
playground
This errors out with:
error[E0277]: the trait bound `NonSerialisable: serde::Serialize` is not satisfied
--> src/main.rs:43:10
|
43 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^ the trait `serde::Serialize` is not implemented for `NonSerialisable`
|
= note: required because of the requirements on the impl of `serde::Serialize` for `A<NonSerialisable>`
= note: required by `serde::Serializer::serialize_newtype_variant`
error[E0277]: the trait bound `NonSerialisable: serde::Deserialize<'_>` is not satisfied
--> src/main.rs:43:21
|
43 | #[derive(Serialize, Deserialize)]
| ^^^^^^^^^^^ the trait `serde::Deserialize<'_>` is not implemented for `NonSerialisable`
|
= note: required because of the requirements on the impl of `serde::Deserialize<'_>` for `A<NonSerialisable>`
= note: required by `serde::de::VariantAccess::newtype_variant`
If I comment out A::Variant0, as mentioned in the inline comment in the code, then it compiles fine. This makes me think that the compiler is unable to deduce that B<T> is serialisable, but then it actually is able to deduce that because it can figure out E is serialisable which would require B to be serialisable as well.
Where is the problem?
During macro expansion the compiler has not yet determined which B is being referred to inside Variant0 or how that B may use its type parameters. As such, macro expansion infers trait bounds that would work for the most common cases of what B might be, like if B were Box or Vec. In those cases serializing B<T> would require T: Serialize and deserializing B<T> would require T: Deserialize<'de>.
You can provide handwritten generic type bounds to replace the inferred bounds.
#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
enum A<T: Trait> {
Variant0(B<T>),
Variant1(T::SerialisableType),
}