I was exploring the "BorshDeserialize" option in Rust. and noticed the following issues when using trait bounds. Any help is appreciated
Sample code
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::pubkey::Pubkey;
use std::mem;
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
struct SampleData<'a> {
accounts: (&'a Pubkey, &'a Pubkey),
data: String,
timestamp: u64,
owner: &'a Pubkey,
}
fn main() {
println!(
"Size of SampleData is {} bytes",
mem::size_of::<SampleData>()
);
let _pub_key = Pubkey::default();
let _a = SampleData {
accounts: (&_pub_key, &_pub_key),
data: "ABCDE".to_string(),
timestamp: 1643116047,
owner: &_pub_key,
};
let _encoded_a = _a.try_to_vec().unwrap();
println!("{:?}", _encoded_a);
let _decoded_a = SampleData::try_from_slice(&_encoded_a).unwrap();
println!("decoded_a: {:?}", _decoded_a);
}
Error message
error[E0599]: the function or associated item try_from_slice exists
for struct SampleData<'_>, but its trait bounds were not satisfied
--> src/main.rs:27:34 | 6 | struct SampleData<'a> { | --------------------- | | | function or associated item try_from_slice not found for this | doesn't satisfy
SampleData<'_>: BorshDeserialize ... 27 | let _decoded_a =
SampleData::try_from_slice(&_encoded_a).unwrap(); |
^^^^^^^^^^^^^^ function or associated item cannot be called on
SampleData<'_> due to unsatisfied trait bounds | note: the
following trait bounds were not satisfied because of the requirements
of the implementation of BorshDeserialize for _:
(&Pubkey, &Pubkey): BorshDeserialize
&Pubkey: BorshDeserialize --> src/main.rs:5:26 | 5 | #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)] | ^^^^^^^^^^^^^^^^ 6 | struct SampleData<'a> { |
^^^^^^^^^^^^^^ = help: items from traits can only be used if the
trait is implemented and in scope = note: the following trait
defines an item try_from_slice, perhaps you need to implement it:
candidate #1: BorshDeserialize = note: this error originates in the derive macro BorshDeserialize (in Nightly builds,
run with -Z macro-backtrace for more info)
For more information about this error, try rustc --explain E0599.
error: could not compile seralize due to previous error
The problem is that SampleData contains references, which isn't supported in normal Borsh deserialization. Borsh creates a new instance of your type based on a slice, but it won't be able to create references.
If you want to stick with Borsh, you should change the type to:
#[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
struct SampleData {
accounts: (Pubkey, Pubkey),
data: String,
timestamp: u64,
owner: Pubkey,
}
Related
I am working with Solana smart contracts using the anchor library, I am trying to make a struct that will store an array of public keys of other Solana accounts, but it is giving errors around lifetimes and borrowing the array. Can someone explain to me what is wrong and how to fix it? I am still iffy on how stuff like borrowing and ownership works in rust.
// This is your program's public key and it will update
// automatically when you build the project.
declare_id!("********************************************");
#[program]
mod hello_anchor {
use super::*;
pub fn initialize(ctx: Context<Initialize>, entries: u64, keys: [&[u8]]) -> Result<()> {
ctx.accounts.new_account.entries = entries;
ctx.accounts.new_account.keys = keys;
msg!("Changed entry number to: {}!", entries); // Message will show up in the tx logs
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
// We must specify the space in order to initialize an account.
// First 8 bytes are default account discriminator,
// next 8 bytes come from NewAccount.data being type u64.
// (u64 = 64 bits unsigned integer = 8 bytes)
#[account(init, payer = signer, space = 8 + 8)]
pub new_account: Account<'info, NewAccount>,
#[account(mut)]
pub signer: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[account]
pub struct NewAccount {
pub entries: u64,
pub keys: [&[u8]],
}
#[account]
pub struct NewEntry {
pubkey: String,
day: u8,
month: u8,
year: u16,
}
error log
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> /src/lib.rs:7:1
|
7 | #[program]
| ^ explicit lifetime name needed here
|
= note: this error originates in the attribute macro `program` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0637]: `&` without an explicit lifetime name cannot be used here
--> /src/lib.rs:34:16
|
34 | pub keys: [&[u8]],
| ^ explicit lifetime name needed here
error[E0106]: missing lifetime specifier
--> /src/lib.rs:34:16
|
34 | pub keys: [&[u8]],
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
32 ~ pub struct NewAccount<'a> {
33 | pub entries: u64,
34 ~ pub keys: [&'a [u8]],
|
error[E0106]: missing lifetime specifier
--> /src/lib.rs:7:1
|
7 | #[program]
| ^ expected named lifetime parameter
|
= note: this error originates in the attribute macro `program` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider introducing a named lifetime parameter
|
7 ~ #<'a>[program]
8 | mod hello_anchor {
9 | use super::*;
10~ pub fn initialize<'a>(ctx: Context<Initialize>, entries: u64, keys: [&[u8]]) -> Result<()> {
|
Some errors have detailed explanations: E0106, E0637.
error: could not compile `solpg` due to 4 previous errors
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 endeavour to save my struct to user preferences. My code follows
use serde::{Serialize, Deserialize};
use preferences::AppInfo;
const APP_INFO: AppInfo = AppInfo{name: "some-name", author: "some-author"};
#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Foo {
bar: i32
}
fn main() {
let x = Foo{bar: 12};
// Attempt 1: cannot find a `save` function
// x.save(x, &APP_INFO, "foo/bar").unwrap();
// Attempt 2: Foo leaves Serialize & Deserialise unsatisfied
preferences::Preferences::save(&x, &APP_INFO, "foo/bar").unwrap();
}
Despite this line #[derive(Serialize, Deserialize, PartialEq, Debug)] the compiler grumbles ..
error[E0277]: the trait bound `Foo: serde::ser::Serialize` is not satisfied
--> src/main.rs:17:5
|
17 | preferences::Preferences::save(&x, &APP_INFO, "foo/bar").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `serde::ser::Serialize` is not implemented for `Foo`
|
::: /Users/martincowie/.cargo/registry/src/github.com-1ecc6299db9ec823/preferences-1.1.0/src/lib.rs:302:16
|
302 | fn save<S: AsRef<str>>(&self, app: &AppInfo, key: S) -> Result<(), PreferencesError>;
| ---------- required by this bound in `save`
|
= note: required because of the requirements on the impl of `Preferences` for `Foo`
The unsatisfied trait bound <S: AsRef<str>> relates to the parameter key, which is a string literal.
This is more or less inspired by the example at https://docs.rs/preferences/1.1.0/preferences/
What need I do to placate the compiler?
Check your cargo.lock. Most likely, your main application is pulling in a different version of serde than the preferences crate.
It appears that preferences depends on serde-0.9, but chances are you're pulling in serde-1.0. This means that your struct implements serde-1.0::Deserialize, but preferences wants serde-0.9::Deserialize.
The inability of the compiler to produce a nice message for this case is a long-standing bug.
I'm using the fltk-rs crate and running into the "multiple applicable items in scope" error.
fltk = "0.10.14"
use fltk::{table::*};
pub struct AssetViewer {
pub table: Table,
}
impl AssetViewer {
pub fn new(x: i32, y: i32, width: i32, height: i32) -> Self {
let mut av = AssetViewer {
table: Table::new(x,y,width-50,height,""),
};
av.table.set_rows(5);
av.table.set_cols(5);
av
}
pub fn load_file_images(&mut self, asset_paths: Vec<String>){
self.table.clear(); //<- throws multiple applicable items in scope
}
}
Gives error:
error[E0034]: multiple applicable items in scope
--> src\main.rs:18:20
|
18 | self.table.clear(); //<- throws multiple applicable items in scope
| ^^^^^ multiple `clear` found
|
= note: candidate #1 is defined in an impl of the trait `fltk::TableExt` for the type `fltk::table::Table`
= note: candidate #2 is defined in an impl of the trait `fltk::GroupExt` for the type `fltk::table::Table`
I would like to specify that I'm referencing the TableExt trait, not the GroupExt trait. How would I do this?
TLDR: Use fully qualified function name:
fltk::GroupExt::clear(&mut self.table)
Consider this simplified example:
struct Bar;
trait Foo1 {
fn foo(&self) {}
}
trait Foo2 {
fn foo(&self) {}
}
impl Foo1 for Bar {}
impl Foo2 for Bar {}
fn main() {
let a = Bar;
a.foo()
}
It will fail to compile with the following error message:
error[E0034]: multiple applicable items in scope
--> src/main.rs:16:7
|
16 | a.foo()
| ^^^ multiple `foo` found
|
Compiler will also suggest a solution:
help: disambiguate the associated function for candidate #1
|
16 | Foo1::foo(&a)
|
The compiler in this instance recommends the correct fix. The error message (as of 1.48.0) contains these help annotations:
help: disambiguate the associated function for candidate #1
|
18 | fltk::TableExt::clear(&mut self.table);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for candidate #2
|
18 | fltk::GroupExt::clear(&mut self.table);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The full error message actually shows 5 candidates and 5 help annotations.
As an aside, another syntax for disambiguating methods is:
<Table as fltk::TableExt>::clear(&mut self.table);
Though its more verbose than the recommended syntax and its only needed in situations where the method doesn't take self and therefore can't deduce Table.
I am trying to serialize a stuct with a generic member I get the error 'equired because of the requirements on the impl of sns_pub::_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize for sns_pub::Message<T>
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(bound(
serialize = "T: Serialize",
deserialize = "T: Deserialize<'de>",
))]
struct Message<T> {
topic: String,
message_id: String,
created_date: DateTime<Utc>,
message: T,
subject: String
}
let msg = String::from("TEST_MESSAGE");
let message = Message {
topic: self.topic.clone(),
message_id: id.to_string(),
created_date: now,
subject: self.subject.clone(),
message: msg
};
let filename = format!("{}/{}_{}", self.folder_path, prefix, id);
let mut file = File::create(filename.clone())?;
file.write_all(serde_yaml::to_string(&message)?.as_str())?;
error[E0277]: the trait bound `T: sns_pub::_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` is not satisfied
--> src/sns_pub.rs:57:46
|
43 | impl<T> SnsPub<T> for DiskSnsPub {
| - help: consider restricting this bound: `T: sns_pub::_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` ...
57 | file.write_all(serde_yaml::to_string(&message)?.as_str())?;
| ^^^^^^^^ the trait `sns_pub::_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` is not implemented for `T`
| ::: /home/moharaza/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_yaml-0.8.11/src/ser.rs:421:8
|
421 | T: ser::Serialize,
| -------------- required by this bound in `serde_yaml::ser::to_string`
|
= note: required because of the requirements on the impl of `sns_pub::_IMPL_DESERIALIZE_FOR_Message::_serde::Serialize` for `sns_pub::Message<T>`
error[E0308]: mismatched types
The provided code is missing a lot of information, and the error is actually caused by code that you didn't provide. This is why it's important to provide a [reprex].
However, I can guess some of the code is actually from a method of Message, since it uses self. What you have missed is to but bounds on T for the impl block that defines the method:
impl<T> Message<T>
where
T: Serialize + for<'de> Deserialize<'de>,
{
/// methods go here
{
I know this because the error message already tells you pretty much this exactly.