Created
April 24, 2018 00:16
-
-
Save evanw/06a672db1897482eadfbbf37ebf9b9ec to your computer and use it in GitHub Desktop.
Example crazy Rust compile error
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "multiplayer" | |
version = "0.0.1" | |
publish = false | |
[dependencies] | |
futures = "0.1.18" | |
hyper = "0.11.17" | |
tokio-core = "0.1.12" | |
tokio-signal = "0.1.4" | |
tokio-tungstenite = "0.5.1" | |
tungstenite = "0.5.3" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate futures; | |
extern crate hyper; | |
extern crate tokio_core; | |
extern crate tokio_tungstenite; | |
extern crate tungstenite; | |
use futures::{Future, Stream}; | |
fn main() { | |
let address = "127.0.0.1:8080".parse().unwrap(); | |
let mut core = tokio_core::reactor::Core::new().unwrap(); | |
let handle = core.handle(); | |
let server = tokio_core::net::TcpListener::bind(&address, &handle).unwrap(); | |
let socket_server = server.incoming().for_each(move |(stream, address)| { | |
let handle_clone = handle.clone(); | |
tokio_tungstenite::accept_async(stream).and_then(move |_stream| { | |
start_session(handle_clone).and_then(move |_session_data| { | |
println!("Connected to {}", address); | |
Ok(()) | |
}) | |
// This particular compile error happens when this line is missing | |
// .map_err(|e| tungstenite::Error::Io(e)) | |
}) | |
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) | |
}); | |
core.run(socket_server).unwrap(); | |
} | |
fn start_session(handle: tokio_core::reactor::Handle) | |
-> Box<Future<Item=Vec<u8>, Error=std::io::Error>> | |
{ | |
let client = hyper::Client::new(&handle); | |
let url = "https://www.example.com/api/session".parse().unwrap(); | |
Box::new(client.get(url).and_then(|res| { | |
res.body().concat2().and_then(move |body| Ok(body.to_vec())) | |
}) | |
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$ cargo build | |
Compiling multiplayer v0.0.1 | |
error[E0271]: type mismatch resolving `<futures::AndThen<std::boxed::Box<futures | |
::Future<Error=std::io::Error, Item=std::vec::Vec<u8>>>, std::result::Result<(), | |
std::io::Error>, [closure@src/main.rs:17:44: 20:8 address:_]> as futures::IntoF | |
uture>::Error == tungstenite::Error` | |
--> src/main.rs:16:45 | |
| | |
16 | tokio_tungstenite::accept_async(stream).and_then(move |_stream| { | |
| ^^^^^^^^ expected struct `std:: | |
io::Error`, found enum `tungstenite::Error` | |
| | |
= note: expected type `std::io::Error` | |
found type `tungstenite::Error` | |
error[E0599]: no method named `map_err` found for type `futures::AndThen<tokio_t | |
ungstenite::AcceptAsync<tokio_core::net::TcpStream, tungstenite::handshake::serv | |
er::NoCallback>, futures::AndThen<std::boxed::Box<futures::Future<Error=std::io: | |
:Error, Item=std::vec::Vec<u8>>>, std::result::Result<(), std::io::Error>, [clos | |
ure@src/main.rs:17:44: 20:8 address:_]>, [closure@src/main.rs:16:54: 22:6 handle | |
_clone:_, address:_]>` in the current scope | |
--> src/main.rs:23:6 | |
| | |
23 | .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e)) | |
| ^^^^^^^ | |
| | |
= note: the method `map_err` exists but the following trait bounds were not s | |
atisfied: | |
`futures::AndThen<tokio_tungstenite::AcceptAsync<tokio_core::net::Tcp | |
Stream, tungstenite::handshake::server::NoCallback>, futures::AndThen<std::boxed | |
::Box<futures::Future<Error=std::io::Error, Item=std::vec::Vec<u8>>>, std::resul | |
t::Result<(), std::io::Error>, [closure@src/main.rs:17:44: 20:8 address:_]>, [cl | |
osure@src/main.rs:16:54: 22:6 handle_clone:_, address:_]> : futures::Future` | |
`&mut futures::AndThen<tokio_tungstenite::AcceptAsync<tokio_core::net | |
::TcpStream, tungstenite::handshake::server::NoCallback>, futures::AndThen<std:: | |
boxed::Box<futures::Future<Error=std::io::Error, Item=std::vec::Vec<u8>>>, std:: | |
result::Result<(), std::io::Error>, [closure@src/main.rs:17:44: 20:8 address:_]> | |
, [closure@src/main.rs:16:54: 22:6 handle_clone:_, address:_]> : futures::Stream | |
` | |
`&mut futures::AndThen<tokio_tungstenite::AcceptAsync<tokio_core::net | |
::TcpStream, tungstenite::handshake::server::NoCallback>, futures::AndThen<std:: | |
boxed::Box<futures::Future<Error=std::io::Error, Item=std::vec::Vec<u8>>>, std:: | |
result::Result<(), std::io::Error>, [closure@src/main.rs:17:44: 20:8 address:_]> | |
, [closure@src/main.rs:16:54: 22:6 handle_clone:_, address:_]> : futures::Future | |
` | |
error: aborting due to 2 previous errors | |
error: Could not compile `multiplayer`. | |
To learn more, run the command again with --verbose. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Go wasn't ruled out exactly in that I didn't do a formal comparison between the two before building it. I was experimenting with Rust at the time and had a working Rust implementation, then the servers started falling over from load and we needed to use it.
That said, the multiplayer server does have some unique requirements that Rust is a good fit for. The multiplayer service is extremely memory-intensive and garbage-collected languages inherently add additional overhead because of uncollected garbage. I also wanted to have an individual process per document for robustness and Rust's smaller binary size and lack of a runtime meant this strategy was actually practical. The multiplayer server is basically a real-time graph database and generics were nice to have for working with graph data structures. The code for the multiplayer server is also pretty small so Rust's bad compile times are tolerable.