How to initialize an UnorderedSet that is inside a LookupMap? - rust

I´m writing a smart contract with rust in near protocol. I have the following struct for the main contract:
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize, PanicOnDefault)]
pub struct Contract {
pub total_transactions: u64,
pub owner_id: AccountId,
pub transactions_per_account: LookupMap<AccountId, UnorderedSet<TransactionId>>,
pub transaction_by_id: LookupMap<TransactionId, Transaction>,
pub transaction_metadata_by_id: UnorderedMap<TransactionId, TransactionMetadata>,
}
I have already written a function to initialize the contract as the following:
#[derive(BorshSerialize)]
pub enum StorageKey {
TransactionsPerAccount,
TransactionById,
TransactionMetadataById,
}
#[near_bindgen]
impl Contract {
#[init]
pub fn new(owner_id: AccountId) -> Self {
let this = Self {
total_transactions: 0,
owner_id,
transactions_per_account: LookupMap::new(StorageKey::TransactionsPerAccount.try_to_vec().unwrap()),
transaction_by_id: LookupMap::new(StorageKey::TransactionById.try_to_vec().unwrap()),
transaction_metadata_by_id: UnorderedMap::new(
StorageKey::TransactionMetadataById.try_to_vec().unwrap(),
),
};
//return the Contract object
this
}
}
But there the UnorderedSet that is inside the LookupMap transactions_per_account is not initialize because it is supposed that there will be an UnorderedSet that corresponds to each user, so it should be created when a user log in for first time and creates an account:
I tried to write that function as the following:
#[payable]
pub fn create_transaction( //implement storage management for transactions
&mut self,
seller_id: AccountId,
buyer_id: AccountId,
price: Price,
nft_id: TokenId,
nft_contract_id: AccountId,
) -> Transaction {
let sender = env::predecessor_account_id();
let transaction = Transaction {
transaction_id: self.total_transactions,
creator_id: sender.clone(),
seller_id: seller_id.clone(),
buyer_id: buyer_id.clone(),
price: price,
nft_id: nft_id.clone(),
nft_contract_id: nft_contract_id.clone(),
amount_in_escrow: false,
token_in_escrow: false,
transaction_status: TransactionStatus::Pending,
};
//let account_as_key = transaction.creator_id.try_to_vec().unwrap();
// update number of transactions
self.total_transactions += 1;
let unordered_set = self.transactions_per_account.get(&transaction.creator_id);
match unordered_set {
Some(mut set) => {
set.insert(&transaction.transaction_id);
},
None => {
let mut set = UnorderedSet::new(&*transaction.creator_id.try_to_vec().unwrap());
set.insert(&transaction.transaction_id);
self.transactions_per_account.insert(&transaction.creator_id, &set);
},
}
self.transaction_by_id.insert(&transaction.transaction_id, &transaction);
transaction
}
Cargo check let it pass with no error but when trying to compile I got the following error:
error[E0277]: the trait bound `UnorderedSet<u64>: Serialize` is not satisfied
--> src/lib.rs:133:1
|
133 | #[near_bindgen]
| ^^^^^^^^^^^^^^^ the trait `Serialize` is not implemented for `UnorderedSet<u64>`
|
note: required by a bound in `to_vec`
--> /home/walquer/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.78/src/ser.rs:2193:17
|
2193 | T: ?Sized + Serialize,
| ^^^^^^^^^ required by this bound in `to_vec`
= note: this error originates in the attribute macro `near_bindgen` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0277`.
I believe the error is caused by a erroneous initialization of the UnorderedSet collection that was defined inside the struct that do have the serialize trait.
Can someone tell me what im missing?

Related

ExecutionError:Smart contract panicked:panicked at Cannot deserialize the contract state.:Custom kind:InvalidInput,error:"Unexpected length of input"

#[derive(BorshSerialize, BorshDeserialize)]
pub struct NotesDs {
pub own: Vec<String>,
pub shared: UnorderedMap<AccountId,Vec<String>>,
}
impl NotesDs{
pub fn new() -> Self {
assert!(env::state_read::<Self>().is_none(), "Already initialized");
Self {
own: Vec:: new(),
shared: UnorderedMap::new(b"w".to_vec()),
}
}
}
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Note {
pub note_list : UnorderedMap<AccountId,NotesDs>,
}
impl Default for Note {
fn default() -> Self {
// Check incase the contract is not initialized
env::panic(b"The contract is not initialized.")
}
}
#[near_bindgen]
impl Note {
/// Init attribute used for instantiation.
#[init]
pub fn new() -> Self {
assert!(env::state_read::<Self>().is_none(), "Already initialized");
Self {
note_list: UnorderedMap::new(b"h".to_vec()),
}
}
pub fn add_notes2(&mut self, status: String){
if self.note_list.get(&env::predecessor_account_id()).is_none() {
let mut temp = NotesDs:: new();
let mut vec = Vec:: new();
let mut vec2 = Vec:: new();
vec.push(status.clone());
temp.own = vec;
temp.shared = vec2;
self.note_list.insert(&env::predecessor_account_id(), &temp);
}
else {
let mut temp1 = self.note_list.get(&env::predecessor_account_id()).unwrap();
let mut vec1 = temp1.own;
vec1.push(status.clone());
temp1.own = vec1;
self.note_list.insert(&env::predecessor_account_id(), &temp1);
}
}
}
I am getting the following error
Failure [share.meghaha.testnet]: Error: {"index":0,"kind":{"ExecutionError":"Smart contract panicked: panicked at 'Cannot deserialize the contract state.: Custom { kind: InvalidInput, error: \"Unexpected length of input\" }', /home/meghaa105/.cargo/registry/src/github.com-1ecc6299db9ec823/near-sdk-3.1.0/src/environment/env.rs:786:46"}}
ServerTransactionError: {"index":0,"kind":{"ExecutionError":"Smart contract panicked: panicked at 'Cannot deserialize the contract state.: Custom { kind: InvalidInput, error: \"Unexpected length of input\" }', /home/meghaa105/.cargo/registry/src/github.com-1ecc6299db9ec823/near-sdk-3.1.0/src/environment/env.rs:786:46"}}
at Object.parseResultError (/usr/lib/node_modules/near-cli/node_modules/near-api-js/lib/utils/rpc_errors.js:31:29)
at Account.signAndSendTransactionV2 (/usr/lib/node_modules/near-cli/node_modules/near-api-js/lib/account.js:160:36)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async scheduleFunctionCall (/usr/lib/node_modules/near-cli/commands/call.js:57:38)
at async Object.handler (/usr/lib/node_modules/near-cli/utils/exit-on-error.js:52:9) {
type: 'FunctionCallError',
context: undefined,
index: 0,
kind: {
ExecutionError: `Smart contract panicked: panicked at 'Cannot deserialize the contract state.: Custom { kind: InvalidInput, error: "Unexpected length of input" }', /home/meghaa105/.cargo/registry/src/github.com-1ecc6299db9ec823/near-sdk-3.1.0/src/environment/env.rs:786:46`
},
transaction_outcome: {
block_hash: 'EesG3NjqXdbYZqEYE22nC12AYpU3gkC9uaC7rSjToGSA',
id: '89g7HhiXgZFZRLntMzFCPk82TQ5m8diwW2nh6jVnEgKz',
outcome: {
executor_id: 'share.meghaha.testnet',
gas_burnt: 2428050684172,
logs: [],
metadata: [Object],
receipt_ids: [Array],
status: [Object],
tokens_burnt: '242805068417200000000'
},
proof: [ [Object], [Object] ]
}
}
This error comes for the query
near calladd_notes2 '{"status" : "Trying out writing a smart contract" }'
I have even tried deleting and creating a new account with same or different names. I even tried redeploying the smart contract. Further, I also have added the serialize and deserialize dependencies. I don't know what is going wrong.
Edit: The original answer (which is marked correct) said that the standard Rust Vec can't be used in a NEAR contract. It can along with all the Rust types in https://docs.rs/borsh/0.2.9/borsh/ser/trait.BorshSerialize.html. The NEAR collections https://docs.rs/near-sdk/2.0.1/near_sdk/collections/index.html are recommended for bigger collections as they are more storage efficient, but have few features and are less familiar than Rust built ins.
Something else must have fixed the issue. Usually "can't deserialize the contract state" in NEAR happens when new contract code is deployed on an existing contract and is not compatible with the data that has been previously stored by the contract.
Original Answer
The following code may help to resolve the error. NEAR has it's own datatypes that persist the state of the contract.
near_sdk::collections::Vector is used in place of Vec.
The code below replaces Vec with the persistent NEAR Vector:
/// New imports...
use near_sdk::collections::{ UnorderedMap, Vector };
use near_sdk::{ BorshStorageKey };
#[derive(BorshSerialize, BorshStorageKey)]
enum StorageKeyNotes {
MapKey,
OwnKey,
SharedKey
}
#[derive(BorshSerialize, BorshDeserialize)]
pub struct NotesDs {
pub own: Vector<String>,
pub shared: UnorderedMap<AccountId, Vector<String>>,
}
impl NotesDs{
pub fn new() -> Self {
assert!(env::state_read::<Self>().is_none(), "Already initialized");
let mut notesDs = Self {
own: Vector::new(StorageKeyNotes::OwnKey),
shared: UnorderedMap::<AccountId, Vector<String>>::new(StorageKeyNotes::MapKey)
};
notesDs
}
}
#[near_bindgen]
#[derive(BorshDeserialize, BorshSerialize)]
pub struct Note {
pub note_list : UnorderedMap<AccountId,NotesDs>,
}
impl Default for Note {
fn default() -> Self {
// Check incase the contract is not initialized
env::panic(b"The contract is not initialized.")
}
}
#[near_bindgen]
impl Note {
/// Init attribute used for instantiation.
#[init]
pub fn new() -> Self {
assert!(env::state_read::<Self>().is_none(), "Already initialized");
Self {
note_list: UnorderedMap::new(b"h".to_vec()),
}
}
pub fn add_notes2(&mut self, status: String){
if self.note_list.get(&env::predecessor_account_id()).is_none() {
let mut temp = NotesDs:: new();
let mut vec = Vector::new(StorageKeyNotes::OwnKey);
let mut vec2 = Vector::new(StorageKeyNotes::SharedKey);
vec.push(&status.clone());
temp.own = vec;
temp.shared.insert(&String::from("Max Power"), &vec2);
self.note_list.insert(&env::predecessor_account_id(), &temp);
}
else {
let mut temp1 = self.note_list.get(&env::predecessor_account_id()).unwrap();
let mut vec1 = temp1.own;
vec1.push(&status.clone());
temp1.own = vec1;
self.note_list.insert(&env::predecessor_account_id(), &temp1);
}
}
}
The code hasn't been tested on chain but could help with solving the error.
For anybody searching for the similar error:
Smart contract panicked: panicked at 'Cannot deserialize the contract
state.: Custom { kind: InvalidData, error: "Not all bytes read" }
It usually means that a new contract has been deployed that does not work with the data that a previous contract stored.
See Not All Bytes Read Common Solutions

How can I chain functions that take the previous result and that fulfill a strict order?

Example:
let response = add_customer(InputCustomer)
.validate()?
.generate_code()
.create(DB::create(pool_conextion))?;
I tried using various structures, but I don't know if it is the best way to do it:
struct InputCustomer {}
fn add_customer(i: InputCustomer) -> Validate {
Validate {
result: InputCustomer {},
}
}
struct Validate {
result: InputCustomer,
}
impl Validate {
fn do_validate() -> GenCode {
// valdiate struct customer
GenCode {
result: InputCustomer {},
}
}
}
struct GenCode {
result: InputCustomer,
}
impl GenCode {
fn generate_code() -> Create {
// generate customer code
Create { result: true }
}
}
struct Create {
result: bool,
}
You can implement all the functions on a single struct using phantom type parameters. The Customer struct holds some state:
pub struct Customer<State> {
state: PhantomData<State>,
}
We can create the possible states that a Customer can be in:
pub struct CustomerStateNew;
pub struct CustomerStateValidated;
pub struct CustomerStateWithCode;
When you create a Customer, it's state is CustomerStateNew:
pub fn add_customer() -> Customer<CustomerStateNew> {
Customer { state: PhantomData }
}
To validate a Customer it must be in the CustomerStateNew state:
impl Customer<CustomerStateNew> {
pub fn validate(&self) -> Customer<CustomerStateValidated> {
Customer { state: PhantomData }
}
}
The Customer must be validated (CustomerStateValidated) to generate a code:
impl Customer<CustomerStateValidated> {
pub fn generate_code(&self) -> Customer<CustomerStateWithCode> {
Customer { state: PhantomData }
}
}
And it must have a generated code (CustomerStateWithCode) to be created. create consumes self, so the customer cannot be used after it is created (you might not want this behavior, but I included it here for completeness):
impl Customer<CustomerStateWithCode> {
pub fn create(self) -> Result<(), ()> {
Ok(())
}
}
Now we can chain together the methods to create the user:
let result = add_customer().validate().generate_code().create()?;
However, it we try to create the Customer before it is validated, the code will not compile:
let result = add_customer().create();
// error[E0599]: no method named `create` found for struct `Customer<CustomerStateNew>`
// --> src/main.rs:36:20
// 36 | add_customer().create();
// | ^^^^^^ method not found in `Customer<CustomerStateNew>`
Also, no one else can create a Customer with an arbitrary state, because the state field is private:
mod somewhere_else {
fn bla() {
let customer: Customer<CustomerStateWithCode> = Customer { state: PhantomData };
customer.create();
}
}
// error[E0451]: field `state` of struct `Customer` is private
// --> src/main.rs:41:64
// |
// 41 | let customer: Customer<CustomerStateWithCode> = Customer { state: PhantomData };
// |
If you want to store data specific to each state, you can store that actual State inside the Customer instead of PhantomData. Now however, the state is more than just compile time safety and will be stored at runtime:
pub struct CustomerStateWithCode(pub usize);
pub struct Customer<State> {
state: State,
}
impl Customer<CustomerStateValidated> {
pub fn generate_code(&self) -> Customer<CustomerStateWithCode> {
Customer { state: CustomerStateWithCode(1234) }
}
}
We have created a simple state machine using phantom types. This is also knows as the type state pattern. Note that the states will be compiled away to nothing, so there is no runtime cost, only compile time safety!
Playground link

Resolve elided static lifetime when borrowing from an object pool

This is a simplified version of the issue I am currently facing.
trait SuperObject {
fn object_name(&self) -> String;
}
trait Inspect {
fn inspect(&self);
}
impl Inspect for SuperObject {
fn inspect(&self) {
println!("I am a Superobject.");
}
}
struct Object {
name: String
}
impl SuperObject for Box<Object> {
fn object_name(&self) -> String {
format!("I am {}.", self.name.clone())
}
}
struct ObjectPool {
object1: Box<Object>,
object2: Box<Object>,
object3: Box<Object>
}
impl ObjectPool {
pub fn new() -> ObjectPool {
ObjectPool {
object1: Box::new(Object { name: String::from("Object 1") }),
object2: Box::new(Object { name: String::from("Object 2") }),
object3: Box::new(Object { name: String::from("Object 3") })
}
}
fn all_objects(&self) -> Vec<&SuperObject> {
let mut ret: Vec<&SuperObject> = Vec::new();
ret.push(&self.object1);
ret.push(&self.object2);
ret.push(&self.object3);
ret
}
}
fn main() {
let objectpool: ObjectPool = ObjectPool::new();
let allobjects: Vec<&SuperObject> = objectpool.all_objects();
for i in &allobjects {
println!("{}", i.object_name());
// Comment the following line in order to drop error E0597
i.inspect(); // FIXME: borrowed value must be valid for the static lifetime
}
}
The error when attempting to compile this snippet is as follows:
error[E0597]: `objectpool` does not live long enough
--> src/main.rs:50:41
|
50 | let allobjects: Vec<&SuperObject> = objectpool.all_objects();
| ^^^^^^^^^^ does not live long enough
...
56 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error
After numerous searches, from what I understand, the objects being instantiated have a default static lifetime, as referred in https://doc.rust-lang.org/book/second-edition/ch19-02-advanced-lifetimes.html
I believe the output of ObjectPool's all_objects method is elided by the compiler as static as is evidenced by one of the errors evoked when I attempted to debug the snippet:
error[E0308]: mismatched types
--> src/main.rs:42:18
|
42 | ret.push(&self.object2);
| ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found reference
|
= note: expected type `std::boxed::Box<SuperObject>`
found type `&std::boxed::Box<SuperObject + 'static>`
What would be the best course of action this doesn't involve scrapping the object pool altogether? Or is there a more elegant abstraction befitting for rust implementations?
The issue is your impl Inspect for SuperObject. Implementing a trait for another trait does not do what you expect from it. Basically the rule is: never do it. Essentially it means that only when you have a &(SuperObject + 'static), you'll be able to treat it as an Inspect. What you want is
impl<T: SuperObject + ?Sized> Inspect for T {
fn inspect(&self) {
println!("I am a Superobject.");
}
}

Avoiding closure - encapsulating thread variables in a struct

I am writing a simple websocket server named BoltServer based on Rust websocket crate(Code is incomplete, I just started). I am using the example program as the base. However the example programs are not modular (having very long methods). So I am trying to break them up into structs and methods. I want to spawn two threads for each client. One sends messages and the other one receives messages. So here, I want to capture all variables used by the thread in a struct and then call the run method in the impl.
extern crate websocket;
extern crate time;
extern crate rustc_serialize;
pub mod ws {
use std::thread;
use std::sync::{Arc, Mutex};
use std::sync::mpsc;
use std::net::ToSocketAddrs;
use websocket;
use websocket::{Server, Message, Sender, Receiver};
use websocket::server::Connection;
use websocket::stream::WebSocketStream;
use std::str::from_utf8;
struct BoltUser {
user_id: u32,
my_tx: mpsc::Sender<String>,
}
struct Broadcaster {
my_rx: mpsc::Receiver<String>,
}
impl Broadcaster {
fn new(receiver: mpsc::Receiver<String>) -> Broadcaster {
Broadcaster { my_rx: receiver }
}
fn run(self) {
while let Ok(msg) = self.my_rx.recv() {
println!("Broadcaster got message: {}", msg);
}
}
}
struct SocketReader {}
impl SocketReader {
fn run(self) {}
}
struct SocketWriter {
my_rx: mpsc::Receiver<String>,
sender: Sender,
}
impl SocketWriter {
fn run(self) {
while let Ok(message) = self.my_rx.recv() {
}
}
}
pub struct BoltServer {
address: String,
connected_users: Arc<Mutex<Vec<BoltUser>>>,
}
impl BoltServer {
pub fn new(address: &str) -> BoltServer {
BoltServer {
address: address.to_string(),
connected_users: Arc::new(Mutex::new(vec![])),
}
}
fn handshake(&mut self,
connection: Connection<WebSocketStream, WebSocketStream>)
-> (SocketWriter, SocketReader) {
let request = connection.read_request().unwrap();
// println!("thread-> Accepting request...");
let response = request.accept();
let (mut sender, mut receiver) = response.send().unwrap().split();
let (user_tx, user_rx) = mpsc::channel::<String>();//Create a channel for writer
let socket_writer = SocketWriter {
my_rx: user_rx,
sender: sender,
};
let socket_reader = SocketReader {};
(socket_writer, socket_reader)
}
pub fn start(&mut self) {
println!("Starting");
let (broadcaster_tx, broadcaster_rx) = mpsc::channel::<String>();
let broadcaster = Broadcaster::new(broadcaster_rx);
let handle = thread::Builder::new()
.name("Broadcaster".to_string())
.spawn(move || broadcaster.run());
let server = Server::bind(&*self.address).unwrap();
let mut user_id: u32 = 0;
// Block and process connection request from a new client
for connection in server {
user_id = user_id + 1;//Create a new user id
let (socket_writer, socket_reader) = self.handshake(connection);
thread::Builder::new()
.name("Socket writer".to_string())
.spawn(move || socket_writer.run());
thread::Builder::new()
.name("Socket reader".to_string())
.spawn(move || socket_reader.run());
}
handle.unwrap().join();
println!("Finished");
}
}
}
The following code gives an idea of what I want to achieve.
// Block and process connection request from a new client
for connection in server {
user_id = user_id + 1;//Create a new user id
let (socket_writer, socket_reader) = self.handshake(connection);
thread::Builder::new().name("Socket writer".to_string()).spawn(move || {
socket_writer.run()
});
thread::Builder::new().name("Socket reader".to_string()).spawn(move || {
socket_reader.run()
});
}
Here I am stuck in the handshake method. I am not able to initialize the SocketWriter struct with the sender that I am getting by calling the split method in the library. I am getting the following compilation error:
error[E0038]: the trait `websocket::Sender` cannot be made into an object
--> src/lib.rs:46:9
|
46 | sender:Sender,
| ^^^^^^^^^^^^^ the trait `websocket::Sender` cannot be made into an object
|
= note: method `send_dataframe` has generic type parameters
= note: method `send_message` has generic type parameters
The error is telling you the immediate problem:
46 | sender:Sender,
| ^^^^^^^^^^^^^ the trait `websocket::Sender` cannot be made into an object
First of all, a variable/field can't have a plain trait type (but &Trait can be possible), but also the websocket::Sender trait is not object safe; it has generic methods which can't work dynamically (ie vtable methods have to have a fixed type).
Instead, you have to have a concrete type (you could also make it a generic struct).
It's not obvious what the right type is, so I like to get the compiler to tell me. So first try the simplest possible:
sender: (),
The compiler replies with some information:
| ^^^^^^ expected (), found struct `websocket::client::Sender`
Ok, let's plug that in:
sender: websocket::client::Sender,
That gives:
46 | sender: websocket::client::Sender,
| ^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 type arguments, found 0
Ok, that's a generic type. Next try:
sender: websocket::client::Sender<()>,
Finally it gives us the real type:
74 | sender:sender,
| ^^^^^^ expected (), found enum `websocket::WebSocketStream`
So finally we can finish SocketWriter:
struct SocketWriter {
my_rx: mpsc::Receiver<String>,
sender: websocket::client::Sender<websocket::WebSocketStream>,
}
There's a following compile error since the connection you get is a Result<> so you need to check for errors (it compiles if I change to self.handshake(connection.unwrap()), but that's obviously not the best practice.

Recent Changes in Rust Lifetimes

I've been building a websocket server library with Rust for about 4-6 weeks now. Today, I grabbed the latest rustc using the rustup.sh script, and build is breaking from new lifetime requirements. I'm not sure where to look for these changes to figure out what I need to specify in order to meet the requirements? This Week in Rust doesn't have a listing for the recent changes, and the Lifetimes Guide only goes so far with various examples.
Various Struct Definitions
pub struct Server<'a> {
pub sockets: Vec<Socket<'a>>,
pub events: Vec<Event<'a>>,
pub to_event_loop: Sender<Action<'a>>,
pub socket_id: String
}
impl<'a> Clone for Server<'a> {
fn clone(&self) -> Server<'a> {
Server {
sockets: self.sockets.clone(),
events: self.events.clone(),
to_event_loop: self.to_event_loop.clone(),
socket_id: self.socket_id.clone()
}
}
}
pub struct Action<'a> {
pub event: String,
pub socket: Socket<'a>,
pub message: Message
}
pub struct Event<'a> {
pub name: String,
pub execute: fn(data: json::Json, server: super::Server)
}
pub struct Socket<'a> {
pub id: String,
pub stream: TcpStream
}
Function Producing Error
pub fn start(server: Server, ip: &str, port: u16) {
/*
* Communication channel
* - From HTTP Server to Event Loop (Action Passed)
*/
let (to_event_loop, from_conn_pool): (Sender<Action>, Receiver<Action>) = channel();
// Start up event loop
let server_clone = server.clone();
let to_event_loop_clone = to_event_loop.clone();
spawn(proc() {
event_loop(server_clone, from_conn_pool, to_event_loop_clone)
});
// Start TCP server
let listener = TcpListener::bind(ip, port);
let mut acceptor = listener.listen();
for stream in acceptor.incoming() {
match stream {
Ok(stream) => {
let event_loop_msgr = to_event_loop.clone();
spawn(proc() {
process_new_connection(stream, event_loop_msgr)
})
}
Err(e) => {
println!("Error accepting connection: {}", e)
}
}
}
drop(acceptor);
}
Compiler Output
src/rustic_io.rs:47:24: 47:30 error: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
src/rustic_io.rs:47 let server_clone = server.clone();
^~~~~~
src/rustic_io.rs:50:9: 50:70 note: first, the lifetime cannot outlive the call at 50:8...
src/rustic_io.rs:50 event_loop(server_clone, from_conn_pool, to_event_loop_clone)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/rustic_io.rs:50:20: 50:32 note: ...so that argument is valid for the call
src/rustic_io.rs:50 event_loop(server_clone, from_conn_pool, to_event_loop_clone)
^~~~~~~~~~~~
src/rustic_io.rs:38:51: 70:2 note: but, the lifetime must be valid for the anonymous lifetime #1 defined on the block at 38:50...
src/rustic_io.rs:38 pub fn start(server: Server, ip: &str, port: u16) {
src/rustic_io.rs:39
src/rustic_io.rs:40 /*
src/rustic_io.rs:41 * Communication channel
src/rustic_io.rs:42 * - From HTTP Server to Event Loop (Action Passed)
src/rustic_io.rs:43 */
...
src/rustic_io.rs:47:24: 47:30 note: ...so that types are compatible (expected `&server::Server<'_>`, found `&server::Server<'_>`)
src/rustic_io.rs:47 let server_clone = server.clone();
^~~~~~
The compiler is very specific on what the problem is, I just have no idea what syntax it is expecting so that I can satisfy the requirements?

Resources