Rust conflict with error-chain and websocket crates - rust

I'm trying to use error-chain with the websocket crate, but running into an issue that I'm not sure how to resolve. WsUpgrade::accept has the following signature:
fn accept(self) -> Result<Client<S>, (S, IoError)>
Note that the Err variant is a tuple. I want to configure error-chain to handle calls to this method, so I tried to do so as follows in the relevant consuming module:
mod errors {
error_chain! {
foreign_links {
WebSock((::std::net::TcpStream, ::std::io::Error));
}
}
}
This results in the following error, seemingly related to the presence of the tuple.
error: expected identifier, found `(`
--> src/lib/websock.rs:23:21
|
23 | WebSock((::std::net::TcpStream, ::std::io::Error));
| ^
How can I resolve this? Hopefully I've missed something simple.

A simple solution would be to introduce a type alias:
mod errors {
type WebSocketError = (::std::net::TcpStream, ::std::io::Error);
error_chain! {
foreign_links {
WebSock(WebSocketError);
}
}
}
However, this type does not implement traits required by error-chain (such as Error and Display), so it can't be used there.
I think the simplest solution is to convert the error manually using Result::map_err before passing the value to error-chain. For example, the following construction will produce Result<Client<S>, IoError>:
x.accept().map_err(|e| e.1)

Related

Error handling for applications: how to return a public message error instead of all the chain of errors and tracing it at the same time?

PROLOGUE
I'm using async-graphql and I have hundreds of resolvers and for each resolver I would like to trace all the possible errors.
In each method of my app I'm using anyhow::{Error}.
Right now I have code similar to this for each resolver:
#[Object]
impl MutationRoot {
async fn player_create(&self, ctx: &Context<'_>, input: PlayerInput) -> Result<Player> {
let services = ctx.data_unchecked::<Services>();
let player = services
.player_create(input)
.await?;
Ok(player)
}
}
So I thought about using the below code (note the added line with .map_err()):
#[Object]
impl MutationRoot {
async fn player_create(&self, ctx: &Context<'_>, input: PlayerInput) -> Result<Player> {
let services = ctx.data_unchecked::<Services>();
let player = services
.player_create(input)
.await
.map_err(errorify)?;
Ok(player)
}
}
fn errorify(err: anyhow::Error) -> async_graphql::Error {
tracing::error!("{:?}", err);
err.into()
}
Now the error is traced along with all the error chain:
ERROR example::main:10: I'm the error number 4
Caused by:
0: I'm the error number 3
1: I'm the error number 2
2: I'm the error number 1
in example::async_graphql
QUESTION 1
Is there a way to avoid the .map_err() on each resolver?
I would like to use the ? alone.
Should I use a custom error?
Can we have a global "hook"/callback/fn to call on each error?
QUESTION 2
As you can see above the chain of the error is the inverse.
In my graphql response I'm getting as message the "I'm the error number 4" but I need to get the "I'm the error number 2" instead.
The error chain is created using anyhow like this:
main.rs: returns error with .with_context(|| "I'm the error number 4")?
call fn player_create() in graphql.rs: returns with .with_context(|| "I'm the error number 3")?
call fn new_player() in domain.rs: returns with .with_context(|| "I'm the error number 2")?
call fn save_player() in database.rs: returns with .with_context(|| "I'm the error number 1")?
How can I accomplish this?
I'm really new to Rust. I come from Golang where I was using a struct like:
type Error struct {
error error
public_message string
}
chaining it easily with:
return fmt.Errorf("this function is called but the error was: %w", previousError)
How to do it in Rust?
Do I necessarily have to use anyhow?
Can you point me to a good handling error tutorial/book for applications?
Thank you very much.
I would suggest you define your own error for your library and handle them properly by using thiserror crate.
It's like Go defining var ErrNotFound = errors.New(...) and use fmt.Errorf(..., err) to add context.
With the powerful tool enum in Rust, so you can handle every error properly by match arms. It also provides really convenient derive macro like #[from] or #[error(transparent)] to make error conversion/forwarding easy.
Edit 1:
If you want to separate public message and tracing log, you may consider defining you custom error struct like this:
#[derive(Error, Debug)]
pub struct MyError {
msg: String,
#[source] // optional if field name is `source`
source: anyhow::Error,
}
and implement Display trait for formatting its inner msg field.
Finally, you could use macro in tracing-attributes crate:
#[instrument(err(Debug))]
fn my_function(arg: usize) -> Result<(), std::io::Error> {
Ok(())
}
Is there a way to avoid the .map_err() on each resolver?
Yes, you should be able to remove it unless you really need to convert to async_graphql::Error.
Do I necessarily have to use anyhow?
No, but it makes this easier when using ? on different error types.
I'm really new to Rust. I come from Golang where I was using a struct like:
Take a look at thiserror which lets you build you own enum of error variants.

Why can't I import `std::assert` via `use` while it works for other macros from std?

With Rust 2018, this code works (Playground):
use std::panic;
use std::format;
use std::assert_eq;
But this:
use std::assert;
Results in this error:
error[E0432]: unresolved import `std::assert`
--> src/lib.rs:4:5
|
4 | use std::assert;
| ^^^^^^^^^^^ no `assert` in the root
I read the edition guide about this topic and it says that use should work with macro_rules! macros and procedural macros. Thus, I'm confused.
use should work with macro_rules! macros and procedural macros
Except assert is neither of those:
/// Built-in macros to the compiler itself.
///
/// These macros do not have any corresponding definition with a `macro_rules!`
/// macro, but are documented here. Their implementations can be found hardcoded
/// into libsyntax itself.
It is a compiler built-in:
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_doc_only_macro]
macro_rules! assert {
($cond:expr) => ({ /* compiler built-in */ });
($cond:expr,) => ({ /* compiler built-in */ });
($cond:expr, $($arg:tt)+) => ({ /* compiler built-in */ });
}
Other faux-macros include:
compile_error
format_args
env
option_env
concat_idents
concat
line
column
file
stringify
include_str
include_bytes
module_path
cfg
include
The actual definition of assert is buried much lower in libsyntax_ext/assert.rs
Stabilize uniform paths on Rust 2018 (#56417) does mention these in passing:
Built-in macros, for example use env.
Currently an error due to some (fixable) implementation details of built-in macros.
No known issues to resolve before stabilization (after the error is removed).

Invalid operand for inline asm constraint 'i' when writing inline x86_64 assembly

The code below used to build just fine back in April (Rust version ~1.6), but it doesn't anymore.
#![feature(asm)]
enum MyEnum { One = 1 }
fn main() {
unsafe {
asm!("nop" : : "i" (MyEnum::One as isize) : : ); // broken
}
}
The error message does not point to any obvious changes that might be causing this.
The value for the "i" constraint must be a compile-time constant and you are supplying it something that isn't. If you move the addition into Rust, you could use a register as well as a constant using the constraints "ri".
Whether something is a constant for the purpose of inline assembler can be affected by optimization options.

"associated types may not be referenced here"

Can someone explain why this code fails to compile?
#![feature(associated_types)]
trait Wub {
type Zoop;
}
trait Flim: Wub {
}
I get the error:
qqq.rs:7:13: 7:16 error: associated types may not be referenced here
qqq.rs:7 trait Flim: Wub {
Looks like a bug, I filed #18996. Associated items are very raw at the moment, issue #17307 summarises how much there is to go.

Declaring a map in a separate file and reading its contents

I'm trying to declare a map in a separate file, and then access it from my main function.
I want Rust's equivalent (or whatever comes closest) to this C++ map:
static const std::map<std::string, std::vector<std::string>> table = {
{ "a", { "foo" } },
{ "e", { "bar", "baz" } }
};
This is my attempt in Rust.
table.rs
use std::container::Map;
pub static table: &'static Map<~str, ~[~str]> = (~[
(~"a", ~[~"foo"]),
(~"e", ~[~"bar", ~"baz"])
]).move_iter().collect();
main.rs
mod table;
fn main() {
println(fmt!("%?", table::table));
}
The above gives two compiler errors in table.rs, saying "constant contains unimplemented expression type".
I also have the feeling that the map declaration is less than optimal for the purpose.
Finally, I'm using Rust 0.8.
As Chris Morgan noted, rust doesn't allow you to run user code in order to initialize global variables before main is entered, unlike C++. So you are mostly limited to primitive types that you can initialize with literal expressions. This is, afaik, part of the design and unlikely to change, even though the particular error message is probably not final.
Depending on your use case, you might want to change your code so you're manually passing your map as an argument to all the functions that will want to use it (ugh!), use task-local storage to initialize a tls slot with your map early on and then refer to it later in the same task (ugh?), or use unsafe code and a static mut variable to do much the same with your map wrapped in an Option maybe so it can start its life as None (ugh!).

Resources