use std::collections::HashMap;
#[derive(PartialEq, Eq, Hash, Debug, Copy, Clone)]
pub enum Method {
Get,
Put,
Post,
Delete,
NoImpl,
}
pub trait FromUri {
fn from_uri(data: &str) -> Self;
}
impl FromUri for String {
fn from_uri(data: &str) -> String {
String::from(data)
}
}
impl FromUri for i32 {
fn from_uri(data: &str) -> i32 {
match data.parse::<i32>() {
Ok(v) => v,
Err(e) => panic!("matched integer can't be parsed: {:?}", e),
}
}
}
impl FromUri for u32 {
fn from_uri(data: &str) -> u32 {
match data.parse::<u32>() {
Ok(v) => v,
Err(e) => panic!("matched integer can't be parsed: {:?}", e),
}
}
}
impl FromUri for f32 {
fn from_uri(data: &str) -> f32 {
match data.parse::<f32>() {
Ok(v) => v,
Err(e) => panic!("matched float can't be parsed: {:?}", e),
}
}
}
#[derive(Debug)]
pub struct Request {
pub method: Method,
pub path: String,
pub payload: Vec<u8>,
pub params: HashMap<String, String>,
headers: HashMap<String, String>,
}
impl Request {
pub fn new() -> Request {
Request {
method: Method::NoImpl,
path: String::new(),
headers: HashMap::new(),
params: HashMap::new(),
payload: Vec::with_capacity(2048),
}
}
pub fn from_str(rqstr: &str) -> Request {
let mut req = Request::new();
req.parse(rqstr);
req
}
pub fn get<T: FromUri>(&self, name: &str) -> T {
if !self.params.contains_key(name) {
panic!("invalid route parameter {:?}", name);
}
FromUri::from_uri(&self.params[name])
}
fn parse(&mut self, rqstr: &str) {
let mut buf: Vec<&str> = rqstr.splitn(2, "\r\n").collect();
let ask: Vec<&str> = buf[0].splitn(3, ' ').collect();
self.method = match ask[0] {
"GET" => Method::Get,
"PUT" | "PATCH" => Method::Put,
"POST" => Method::Post,
"DELETE" => Method::Delete,
_ => Method::NoImpl,
};
self.path = String::from(ask[1]);
loop {
buf = buf[1].splitn(2, "\r\n").collect();
if buf[0] == "" {
if buf.len() == 1 || buf[1] == "" {
break;
}
self.payload.extend(buf[1].as_bytes());
break;
}
let hdr: Vec<&str> = buf[0].splitn(2, ": ").collect();
if hdr.len() == 2 {
self.headers.insert(String::from(hdr[0]), String::from(hdr[1]));
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fromuri_trait_i32() {
let pos = String::from("1234");
assert_eq!(1234, FromUri::from_uri(&pos));
let neg = String::from("-4321");
assert_eq!(-4321, FromUri::from_uri(&neg));
}
#[test]
fn test_fromuri_trait_u32() {
let orig = String::from("1234");
assert_eq!(1234, FromUri::from_uri(&orig));
}
#[test]
fn test_fromuri_trait_string() {
let orig = String::from("foobar");
assert_eq!("foobar", <String as FromUri>::from_uri(&orig));
}
#[test]
fn test_fromuri_trait_float() {
let pos = String::from("123.45");
assert_eq!(123.45f32, FromUri::from_uri(&pos));
let neg = String::from("-54.321");
assert_eq!(-54.321f32, FromUri::from_uri(&neg));
}
}