I feel like I've almost got a grip of lifetimes, however this has stumped me. Today I followed the Guessing Game tutorial, and then decided to make it web based. I grabbed the tiny_http
package and got to work. Everything was going well except that all of the code was living inside of the main
function. I needed to refactor.
Only now, I get this error:
src/main.rs:30:5: 30:9 error: `data` does not live long enough
src/main.rs:30 data.split('=').collect()
^~~~
src/main.rs:25:66: 31:2 note: reference must be valid for the anonymous lifetime #1 defined on the block at 25:65...
src/main.rs:25 fn parse_fields_from_request(request: &mut Request) -> Vec<&str> {
src/main.rs:26 let mut data = String::with_capacity(request.body_length().unwrap());
src/main.rs:27
src/main.rs:28 request.as_reader().read_to_string(&mut data).unwrap();
src/main.rs:29
src/main.rs:30 data.split('=').collect()
...
src/main.rs:26:74: 31:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 26:73
src/main.rs:26 let mut data = String::with_capacity(request.body_length().unwrap());
src/main.rs:27
src/main.rs:28 request.as_reader().read_to_string(&mut data).unwrap();
src/main.rs:29
src/main.rs:30 data.split('=').collect()
src/main.rs:31 }
I think that it's expecting data
to live as long as the request
, but I'm not sure what to do about it:
extern crate rand;
extern crate tiny_http;
use rand::Rng;
use std::io::Error as IoError;
use std::cmp::Ordering;
use tiny_http::{Server, Request, Response};
fn respond(request: Request, html: String) -> Result<(), IoError> {
let response = Response::from_string(html)
.with_header(tiny_http::Header {
field: "Content-Type".parse().unwrap(),
value: "text/html".parse().unwrap()
});
let result = request.respond(response);
result
}
fn parse_guess_from_form_request(fields: Vec<&str>) -> &str {
fields.last().unwrap()
}
fn parse_fields_from_request(request: &mut Request) -> Vec<&str> {
let mut data = String::with_capacity(request.body_length().unwrap());
request.as_reader().read_to_string(&mut data).unwrap();
data.split('=').collect()
}
fn main() {
let server = Server::http("0.0.0.0:9090").unwrap();
let mut secret_number = rand::thread_rng().gen_range(1, 101);
let form = String::from("<form method=\"post\"><input name=\"guess\" type=\"number\" /><button>Submit</button></form>");
println!("Listening on port 9090.");
for mut request in server.incoming_requests() {
let mut html = String::new();
let fields = parse_fields_from_request(&mut request);
let guess = match request.body_length() {
// Parse the guess from the form data:
Some(_) => parse_guess_from_form_request(fields),
// Show the initial entrance to the game:
None => {
html.push_str("Guess a number between 1 and 100:</p>");
html.push_str(form.as_str());
respond(request, html)
.expect("Failed to send the response.");
continue;
}
};
let guess: u32 = match guess.trim().parse() {
// Parse the guess into an unsigned integer:
Ok(num) => num,
// Show an error because it's not a number:
Err(_) => {
html.push_str("That isn't actually a number...</p>");
html.push_str(form.as_str());
respond(request, html)
.expect("Failed to send the response.");
continue;
}
};
html.push_str(format!("<p>You guessed {}", guess).as_str());
match guess.cmp(&secret_number) {
Ordering::Less => {
html.push_str(" which is too small...</p>");
html.push_str(form.as_str());
},
Ordering::Greater => {
html.push_str(" which is too big...</p>");
html.push_str(form.as_str());
},
Ordering::Equal => {
html.push_str(" correctly! Guess a new number between 1 and 100:</p>");
html.push_str(form.as_str());
// Create a new secret number:
secret_number = rand::thread_rng().gen_range(1, 101);
}
}
respond(request, html)
.expect("Failed to send the response.");
}
}
Please help this Rust noob understand what is going on, and feel free to point out anything else I'm doing wrong.