Rust mistyping for csv reading - rust

use walkdir::WalkDir;
use std::ffi::OsStr;
use rusqlite::{params, Connection, Result};
use std::error::Error;
use std::io;
use std::process;
use std::path::Path;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Trade {
id: usize,
price: f64,
quantity: f64,
quoted_quantity: f64,
time: i64,
is_buyer_maker: bool,
is_best_match: bool,
}
fn process_csv(file: &Path, db: &Connection) -> Result<(), Box<dyn Error>> {
let mut rdr = csv::Reader::from_path(file)?;
for result in rdr.records() {
match result.deserialize::<Trade>() {
Ok(s) => {
db.execute("INSERT INTO trades (id, price, quantity, quoted_quantity, time, is_buyer_maker, is_best_match) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
params![s.id, s.price, s.quantity, s.quoted_quantity, s.time, s.is_buyer_maker, s.is_best_match])?;
},
Err(e) => println!("Failed to deserialize: {}", e),
}
}
}
fn main () -> Result<(), Box<dyn Error>> {
let conn = Connection::open("bot.db")?;
conn.execute(
"CREATE TABLE trades (
id INTEGER PRIMARY KEY,
price REAL NOT NULL,
quanity REAL NOT NULL,
quoted_quatity REAL NOT NULL,
time INTEGER NOT NULL,
is_buyer_maker INTEGER NOT NULL,
is_best_match INTEGER NOT NULL,
)",
[],
)?;
for entry in WalkDir::new("E:/binance-public-data/python/data/spot/monthly/trades/").into_iter().filter_map(|e| e.ok()) {
println!("Processing: {}", entry.path().display());
if let Err(e) = process_csv(entry.path(), &conn) {
println!("Processing failed: {}", e);
}
}
Ok(())
}
error[E0599]: no method named `deserialize` found for enum `Result` in the current scope
--> src/lib.rs:24:22
|
24 | match result.deserialize::<Trade>() {
| ^^^^^^^^^^^ this is an associated function, not a method
|
= note: found the following associated functions; to be used as methods, functions must have a `self` parameter
note: the candidate is defined in the trait `_::_serde::Deserialize`
--> /playground/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.127/src/de/mod.rs:537:5
|
537 | / fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
538 | | where
539 | | D: Deserializer<'de>;
| |_____________________________^
help: use associated function syntax instead
|
24 | match Result::<StringRecord, csv::Error>::deserialize::<Trade>() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: disambiguate the associated function for the candidate
|
24 | match _::_serde::Deserialize::deserialize(result) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> src/lib.rs:23:5
|
21 | fn process_csv(file: &Path, db: &Connection) -> Result<(), Box<dyn Error>> {
| -------------------------- expected `Result<(), Box<(dyn StdError + 'static)>>` because of return type
22 | let mut rdr = csv::Reader::from_path(file)?;
23 | / for result in rdr.records() {
24 | | match result.deserialize::<Trade>() {
25 | | Ok(s) => {
26 | |
... |
31 | | }
32 | | }
| |_____^ expected enum `Result`, found `()`
|
= note: expected enum `Result<(), Box<(dyn StdError + 'static)>>`
found unit type `()`
help: try using a variant of the expected enum
|
23 | Ok(for result in rdr.records() {
24 | match result.deserialize::<Trade>() {
25 | Ok(s) => {
26 |
27 | db.execute("INSERT INTO trades (id, price, quantity, quoted_quantity, time, is_buyer_maker, is_best_match) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
28 | params![s.id, s.price, s.quantity, s.quoted_quantity, s.time, s.is_buyer_maker, s.is_best_match])?;
...
I want to put my data into a sqlite database. I have a bunch of csvs I need to go through and read their data. I do not know how to work around these errors. I've tried reading on the csv documentation but I still get errors with the return types. Also not sure how to deal deserialize.

Your first error is because you're calling csv's .deserialize() on the wrong variable, it should be called on the reader. Change:
for result in rdr.records() {
match result.deserialize::<Trade>() {
to:
for result in rdr.deserialize::<Trade>() {
match result {
Your second error is from simply not returning a success at the end of your process_csv function:
fn process_csv(file: &Path, db: &Connection) -> Result<(), Box<dyn Error>> {
// ...snip...
Ok(()) // <--------
}
Playground

Related

Iterator next method lifetime mismatch

I'm trying to create an Iterator interface using the csv crate such that I can return a HashMap of col-name: value and am running into a lifetime error I cannot figure out.
For the code below:
use csv::{
Reader,
StringRecord,
StringRecordsIter,
};
use std::collections::HashMap;
use std::fs::File;
pub struct Handler {
pub reader: Reader<File>
}
impl Handler {
pub fn new(file: File) -> Handler {
Handler { reader: Reader::from_reader(file) }
}
}
// type Row = HashMap<String, String>;
pub struct Row<'r> {
number: usize,
fields: HashMap<&'r str, &'r str>,
}
pub struct CSVIterator<'f> {
current_row: usize,
headers: StringRecord,
records: StringRecordsIter<'f, File>,
}
impl<'f> CSVIterator<'f> {
pub fn new(handler: &'f mut Handler) -> CSVIterator<'f> {
CSVIterator {
current_row: 0,
headers: handler.reader.headers().unwrap().clone(),
records: handler.reader.records(),
}
}
}
impl<'f> Iterator for CSVIterator<'f> {
type Item = Row<'f>;
fn next(&mut self) -> Option<Self::Item> {
let next_record = self.records.next();
if next_record.is_none() {
return None;
}
let record = next_record.unwrap().unwrap();
let fields = make_fields(&record, &self.headers);
let row = Row {
number: self.current_row,
fields: fields,
};
return Some(row)
}
}
fn make_fields<'r>(
record: &'r StringRecord, header: &'r StringRecord
) -> HashMap<&'r str, &'r str> {
let mut row: HashMap<&str, &str> = HashMap::new();
for (colname, value) in header.iter().zip(record) {
row.insert(colname, value);
}
row
}
I'm getting the following error:
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> src/csvio.rs:55:43
|
55 | let fields = make_fields(&record, &self.headers);
| ^^^^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime defined here...
--> src/csvio.rs:47:13
|
47 | fn next(&mut self) -> Option<Self::Item> {
| ^^^^^^^^^
note: ...so that reference does not outlive borrowed content
--> src/csvio.rs:55:43
|
55 | let fields = make_fields(&record, &self.headers);
| ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'f` as defined here...
--> src/csvio.rs:44:6
|
44 | impl<'f> Iterator for CSVIterator<'f> {
| ^^
note: ...so that the types are compatible
--> src/csvio.rs:47:46
|
47 | fn next(&mut self) -> Option<Self::Item> {
| ______________________________________________^
48 | | let next_record = self.records.next();
49 | |
50 | | if next_record.is_none() {
... |
61 | | return Some(row)
62 | | }
| |_____^
= note: expected `<CSVIterator<'f> as Iterator>`
found `<CSVIterator<'_> as Iterator>`
For more information about this error, try `rustc --explain E0495`.
I may not intuitively understand the lifetime requirements for the next method here, can someone point me in the right direction?
Thanks!

How to use Diesel connection and Gtk-rs events?

I am trying to do a get a object from a database with Diesel when the Enter key is pressed in a gtk Entry. My idea is to create a Diesel SQLite connection in main function and then borrow it every time that I need it.
To do that, I am trying to use a very simple MVC. The idea is to pass the connection to all the controllers and reuse it. I know that lifetime is necessary here.
pub struct Controller<'a> {
pub connection: &'a SQLiteConnection,
pub search_entry: SearchEntry,
....
}
impl<'a> Controller<'a> {
pub fn new(conn: &'a SQLiteConnection) -> Self {
Self {
search_entry: SearchEntry::new(),
connection: conn,
....
}
}
pub fn init(&self) {
self.search_entry.connect_activate(|x| {
let need_it = diesel_table
.filter(column_id.eq(&x.get_text().unwrap()))
.first(self.connection)
.unwrap();
});
}
}
When compile I get this:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/lib.rs:44:44
|
44 | self.search_entry.connect_activate(|x| {
| ____________________________________________^
45 | | let need_it = diesel_table
46 | | .filter(column_id.eq(&x.get_text().unwrap()))
47 | | .first(self.connection)
48 | | .unwrap();
49 | | });
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 43:5...
--> src/lib.rs:43:5
|
43 | / pub fn init(&self) {
44 | | let need_it = diesel_table
46 | | .filter(column_id.eq(&x.get_text().unwrap()))
47 | | .first(self.connection)
48 | | .unwrap();
49 | | });
50 | | }
| |_____^
note: ...so that the types are compatible
--> src/lib.rs:44:44
|
44 | self.search_entry.connect_activate(|x| {
| ____________________________________________^
45 | | let need_it = diesel_table
46 | | .filter(column_id.eq(&x.get_text().unwrap()))
47 | | .first(self.connection)
48 | | .unwrap();
49 | | });
| |_________^
= note: expected `&&Controller<'_>`
found `&&Controller<'a>`
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#src/lib.rs:44:44: 49:10 self:&&Controller<'_>]` will meet its required lifetime bounds
--> src/lib.rs:44:27
|
44 | self.search_entry.connect_activate(|x| {
| ^^^^^^^^^^^^^^^^
This error is because the function connect_activate has a static parameter: fn connect_activate<F: Fn(&Self) + 'static>.
I would not like to initialize the connection every time that the user press the Intro key by using a function that returns a connection. Instead I would like to borrow that connection.
What would be the most efficient way to do that?
Thanks you very much. I hope you understand everything.
I think you need a Rc<SQLiteConnection>
The question contains various other code issues beside the one mentioned by the OP, so I will include a full working example based on the information provided above. For future questions: Please make sure that your example is self contained and do not contain other compilation errors as that one mentioned in the question. That will make it easier for other people to reproduce your problem and answer the question.
#[macro_use] extern crate diesel;
use diesel::prelude::*;
table! {
diesel_table(id) {
id -> Integer,
column_id -> Text,
}
}
pub struct Controller<'a> {
pub connection: &'a SqliteConnection,
pub search_entry: SearchEntry,
}
pub struct SearchEntry;
impl SearchEntry {
fn new() -> Self {
SearchEntry
}
fn connect_activate<'a, F: Fn(&Self) + 'a>(&self, f: F) {
f(self)
}
fn get_text(&self) -> Option<&'static str> {
Some("foo")
}
}
impl<'a> Controller<'a> {
pub fn new(conn: &'a SqliteConnection) -> Self {
Self {
search_entry: SearchEntry::new(),
connection: conn,
}
}
pub fn init(&self) {
self.search_entry.connect_activate(|x| {
use self::diesel_table::dsl::*;
let need_it: (i32, String) = diesel_table
.filter(column_id.eq(&x.get_text().unwrap()))
.first(self.connection)
.unwrap();
});
}
}
The only relevant change for solving the error described in the OP is the following change to connect_activate:
- fn connect_activate<F: Fn(&Self) + 'static>(&self, f: F) {
+ fn connect_activate<'a, F: Fn(&Self) + 'a>(&self, f: F) {

Returning a value from a function that spawns threads

I'm trying to return a String using pop() in a thread:
use crossbeam_utils::thread; // 0.7.2
use std::sync::{Arc, Mutex};
pub struct MyText {
my_text: Mutex<Vec<String>>,
}
pub trait MyTextOptions {
fn get(&self) -> String;
}
impl MyTextOptions for MyText {
fn get(&self) -> String {
let mut int_text = Arc::new(self);
thread::scope(|scope| {
scope.spawn(|_| {
let mut text_feed = int_text.my_text.lock().unwrap();
text_feed.pop().unwrap()
});
})
.unwrap()
}
}
When I try to run it I get:
error[E0308]: mismatched types
--> src/lib.rs:15:9
|
13 | fn get(&self) -> String {
| ------ expected `std::string::String` because of return type
14 | let mut int_text = Arc::new(self);
15 | / thread::scope(|scope| {
16 | | scope.spawn(|_| {
17 | | let mut text_feed = int_text.my_text.lock().unwrap();
18 | | text_feed.pop().unwrap()
19 | | });
20 | | })
21 | | .unwrap()
| |_________________^ expected struct `std::string::String`, found `()`
I don't understand why it is not returning the popped String value in text_feed.pop().unwrap().
The first problem is the following line:
text_feed.pop().unwrap()
You want an expression in order to return something, so you should remove the ;.
Once you do so, you hit the second problem: the return value of thread::scope will be of type crossbeam_utils::thread::ScopedJoinHandle but you want a String. The docs states that it has a join().
Putting it all together we get:
use crossbeam_utils::thread; // 0.7.2
use std::sync::{Arc, Mutex};
pub struct MyText {
my_text: Mutex<Vec<String>>,
}
pub trait MyTextOptions {
fn get(&self) -> String;
}
impl MyTextOptions for MyText {
fn get(&self) -> String {
let int_text = Arc::new(self);
thread::scope(|scope| {
scope
.spawn(|_| {
let mut text_feed = int_text.my_text.lock().unwrap();
text_feed.pop().unwrap()
})
.join()
.unwrap()
})
.unwrap()
}
}

Trouble with closure lifetimes

I am really struggling with closure lifetimes. I'm making a simple hangman game where all connections play one game. I'm attempting to pass a closure to a channel that will update the game and then broadcast JSON, but I am running into lifetime issues.
extern crate names;
extern crate ws;
#[macro_use]
extern crate json;
use names::{Generator, Name};
use std::collections::HashSet;
use std::sync::mpsc;
use std::thread;
use ws::{listen, CloseCode, Handler, Message, Result, Sender};
type Job = Box<FnMut(&mut Game) + Send>;
#[derive(Debug)]
struct Game {
word: Vec<String>,
guesses: HashSet<String>,
misses: u32,
progress: Vec<String>,
}
impl Game {
fn increment_miss(&mut self) {
self.misses += 1;
}
fn update_progress(&mut self, guess: &String) {
for (i, letter) in self.word.iter().enumerate() {
if letter == guess {
self.progress[i] = letter.clone();
}
}
}
fn status(&self) -> &str {
if self.misses > 10 {
"lose"
} else if self.progress == self.word {
"win"
} else {
"active"
}
}
}
struct Server {
out: Sender,
tx: std::sync::mpsc::Sender<Job>,
}
impl Handler for Server {
fn on_message(&mut self, msg: Message) -> Result<()> {
let string_msg = msg.to_string();
self.tx
.send(Box::new(move |mut game: &mut Game| {
if game.guesses.insert(string_msg.clone()) {
check_letter(&mut game, &string_msg);
};
let status = game.status();
let progress = game.progress.clone();
let guesses = game.guesses.clone().into_iter().collect::<Vec<String>>();
println!(
"guesses: {:?}, progress: {:?}, misses: {}, status: {}",
guesses, progress, game.misses, status
);
self.out.broadcast(json::stringify(object!{
"status" => "status",
"progress" => "progress",
"guesses" => "guesses",
"misses" => "misses",
}));
}))
.unwrap();
Ok(())
}
fn on_close(&mut self, code: CloseCode, reason: &str) {
match code {
CloseCode::Normal => println!("The client is done with the connection."),
CloseCode::Away => println!("The client is leaving the site."),
_ => println!("The client encountered an error: {}", reason),
}
}
}
fn check_letter(game: &mut Game, guess: &String) {
if game.word.contains(guess) {
game.update_progress(guess);
} else {
game.increment_miss();
}
}
fn generate_word() -> Vec<String> {
let mut generator = Generator::with_naming(Name::Plain);
generator
.next()
.unwrap()
.split("")
.map(|c| c.to_string())
.filter(|s| s != "")
.collect::<Vec<String>>()
}
fn start_game() -> Game {
let word = generate_word();
Game {
progress: vec!["".to_string(); word.len()],
word: word,
guesses: HashSet::new(),
misses: 0,
}
}
fn main() {
let (tx, rx) = mpsc::channel::<Job>();
thread::spawn(move || {
let mut game = start_game();
for mut received in rx {
received(&mut game)
}
});
listen("127.0.0.1:3000", |out| Server {
out: out,
tx: mpsc::Sender::clone(&tx),
}).unwrap();
}
I am getting the following error:
Compiling hang_man v0.1.0 (file:///Users/smykowski/workspace/rust/hang_man)
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/main.rs:54:5
|
54 | / fn on_message(&mut self, msg: Message) -> Result<()> {
55 | | let string_msg = msg.to_string();
56 | |
57 | | self.tx.send(Box::new(move |mut game: &mut Game| {
... |
78 | | Ok(())
79 | | }
| |_____^
note: ...so that the type `[closure#src/main.rs:57:31: 76:10 string_msg:std::string::String, self:&mut Server]` will meet its required lifetime bounds
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<for<'r> std::ops::FnMut(&'r mut Game) + std::marker::Send + 'static>, found std::boxed::Box<for<'r> std::ops::FnMut(&'r mut Game) + std::marker::Send>)
--> src/main.rs:57:22
|
57 | self.tx.send(Box::new(move |mut game: &mut Game| {
| ______________________^
58 | | if game.guesses.insert(string_msg.clone()) {
59 | | check_letter(&mut game, &string_msg);
60 | | };
... |
75 | | }));
76 | | })).unwrap();
| |__________^
There is some confusion here because Rust is not very explicit about some features of lifetimes. In this example,
A closure's lifetime is limited by the lifetime of all the params moved into it. In your case, the closure is limited by self because of the line self.out.broadcast. Note that self is actually a reference in this case coming from the &self argument in fn on_message. Essentially you create something like
Box<FnMut(&mut Game) + Send + 'a>
Where 'a is a lifetime of &self.
When you create a boxed trait object, the default lifetime is 'static. That means that
type Job = Box<FnMut(&mut Game) + Send> = Box<FnMut(&mut Game) + Send + 'static>
To avoid this, you can make self cloneable and move self.clone() inside this closure.

Create a struct pointing to another

How can I create the Item instance pointing to the database received as parameter?
struct Something {}
struct Database<'a> {
something: &'a Something,
}
struct Item<'a> {
database: &'a mut Database<'a>,
}
impl<'a> Item<'a> {
fn new(database: &'a mut Database) -> Self {
let mut obj = Self { database };
obj
}
}
This produces the error:
error[E0308]: mismatched types
--> src/main.rs:16:13
|
16 | database
| ^^^^^^^^ lifetime mismatch
|
= note: expected type `&'a mut Database<'a>`
found type `&'a mut Database<'_>`
note: the lifetime 'a as defined on the impl at 13:1...
--> src/main.rs:13:1
|
13 | / impl<'a> Item<'a> {
14 | | fn new(database: &'a mut Database) -> Self {
15 | | let mut obj = Self {
16 | | database
... |
20 | | }
21 | | }
| |_^
note: ...does not necessarily outlive the anonymous lifetime #1 defined on the method body at 14:5
--> src/main.rs:14:5
|
14 | / fn new(database: &'a mut Database) -> Self {
15 | | let mut obj = Self {
16 | | database
17 | | };
18 | |
19 | | obj
20 | | }
| |_____^
I do not understand if the error is in the return type (Self) or another thing.
You defined Database to require a lifetime parameter. That means you also have to give it one. The error message is really helpful here and your problem is fixed by simply doing what it says:
expected type `&'a mut Database<'a>`
found type `&'a mut Database<'_>`
It suffices to simply add <'a> to Database in the signature of new.
N.B.: Always read error messages from top to bottom. Usually by resolving the first error all the successive ones disappear.
struct Something {}
struct Database<'a> {
something: &'a Something
}
struct Item<'a> {
database: &'a mut Database<'a>
}
impl<'a> Item<'a> {
fn new(database: &'a mut Database<'a>) -> Self {
let mut obj = Self {
database
};
obj
}
}
fn main() {
let something = &Something {};
let mut database = Database { something };
let item = Item::new(&mut database);
}
Playground

Resources