use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr};
use std::str::FromStr;
use error::Error;
use http::uri::URI;
pub trait FromFormValue<'v>: Sized {
type Error;
fn from_form_value(form_value: &'v str) -> Result<Self, Self::Error>;
fn default() -> Option<Self> {
None
}
}
impl<'v> FromFormValue<'v> for &'v str {
type Error = Error;
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
Ok(v)
}
}
impl<'v> FromFormValue<'v> for String {
type Error = &'v str;
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
let replaced = v.replace("+", " ");
match URI::percent_decode(replaced.as_bytes()) {
Err(_) => Err(v),
Ok(string) => Ok(string.into_owned())
}
}
}
impl<'v> FromFormValue<'v> for bool {
type Error = &'v str;
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
match v {
"on" | "true" => Ok(true),
"off" | "false" => Ok(false),
_ => Err(v),
}
}
}
macro_rules! impl_with_fromstr {
($($T:ident),+) => ($(
impl<'v> FromFormValue<'v> for $T {
type Error = &'v str;
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
$T::from_str(v).map_err(|_| v)
}
}
)+)
}
impl_with_fromstr!(f32, f64, isize, i8, i16, i32, i64, usize, u8, u16, u32, u64,
IpAddr, Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6, SocketAddr);
impl<'v, T: FromFormValue<'v>> FromFormValue<'v> for Option<T> {
type Error = Error;
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
match T::from_form_value(v) {
Ok(v) => Ok(Some(v)),
Err(_) => Ok(None),
}
}
fn default() -> Option<Option<T>> {
Some(None)
}
}
impl<'v, T: FromFormValue<'v>> FromFormValue<'v> for Result<T, T::Error> {
type Error = Error;
fn from_form_value(v: &'v str) -> Result<Self, Self::Error> {
match T::from_form_value(v) {
ok@Ok(_) => Ok(ok),
e@Err(_) => Ok(e),
}
}
}