This question already has an answer here:
- How do you define custom `Error` types in Rust? 3 answers
- How to get a reference to a concrete type from a trait object? 2 answers
- Rust proper error handling (auto convert from one error type to another with question mark) 3 answers
In my try to better handle errors and prevent repeating tio much code, I am implementing the ?
, operator returning Result<bool, Box<error::Error>>
so that I could just match
the error once instead of multiple times.
I changed the following code using multiple match
es:
fn example(pool: mysql::Pool) {
let now = match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
Ok(n) => n.as_secs(),
Err(_) => panic!("SystemTime before UNIX EPOCH!"),
};
// create table
match pool.prep_exec("CREATE TABLE IF NOT EXISTS dbpulse_rw (id INT NOT NULL, t INT(11) NOT NULL, PRIMARY KEY(id))", ()) {
Ok(_) => (),
Err(e) => {
eprintln!("{}", e);
return;
}
}
// write into table
let mut stmt = match pool
.prepare("INSERT INTO dbpulse_rw (id, t) VALUES (1, ?) ON DUPLICATE KEY UPDATE t=?")
{
Ok(stmt) => stmt,
Err(e) => {
eprintln!("{}", e);
return;
}
};
match stmt.execute((now, now)) {
Ok(_) => (),
Err(mysql::Error::IoError(e)) => {
eprintln!("IoError: {}", e);
// send alert
return;
}
Err(e) => {
eprintln!("{}", e);
return;
}
}
let items = match pool.prep_exec("SELECT t FROM dbpulse_rw WHERE id=1", ()) {
Ok(n) => n,
Err(mysql::Error::IoError(e)) => {
eprintln!("IoError: {}", e);
//send_alert
return;
}
Err(e) => {
eprintln!("{}", e);
return;
}
};
for row in items {
let pool = pool.clone();
let rs = mysql::from_row::<u64>(row.unwrap());
if now != rs {
// send alert
}
assert_eq!(now, rs);
}
}
To use the ?
operator:
fn example(pool: mysql::Pool) -> Result<bool, Box<error::Error>> {
let n = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH)?;
let now = n.as_secs();
// create table
pool.prep_exec("CREATE TABLE IF NOT EXISTS dbpulse_rw (id INT NOT NULL, t INT(11) NOT NULL, PRIMARY KEY(id))", ())?;
// write into table
let mut stmt = pool
.prepare("INSERT INTO dbpulse_rw (id, t) VALUES (1, ?) ON DUPLICATE KEY UPDATE t=?")?;
stmt.execute((now, now))?;
pool.prep_exec("SELECT t FROM dbpulse_rw WHERE id=1", ())
.map(|items| {
for row in items {
match row {
Ok(row) => {
let rs = mysql::from_row::<u64>(row);
if now != rs {
// send alert
}
}
Err(e) => println!("{}", e),
}
}
})?;
Ok(true)
}
What I would like to do now is to match
based on the error, either a timeout or a query error, or other error type. I am creating the MySQL pool like this:
let mut opts = mysql::OptsBuilder::from_opts(dsn);
opts.stmt_cache_size(0);
opts.read_timeout(Some(Duration::new(3, 0)));
opts.write_timeout(Some(Duration::new(3, 0)));
let pool = mysql::Pool::new_manual(1, 5, opts).expect("Could not connect to MySQL");
If a query takes more than 3 seconds it will return a mysql::Error::IoError
the one I would like to distinguish between other possible errors, so far I have tried:
fun run_example() {
match example() {
Ok(_) => (),
Err(mysql::Error::IoError(e)) => {
eprintln!("IoError: {}", e);
// send alert
return;
}
Err(e) => {
eprintln!("{}", e);
return;
}
}
}
But I am getting a mismatched types error:
expected struct `std::boxed::Box`, found enum `mysql::error::Error`
Any tips or better ideas about how to implement this?