81 lines
1.8 KiB
Rust
81 lines
1.8 KiB
Rust
use std::fmt;
|
|
|
|
use rocket::{request::FromParam, TypedError, catcher::TypedError};
|
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub struct DotJson<T>(T);
|
|
|
|
impl<T> std::ops::Deref for DotJson<T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, TypedError)]
|
|
pub enum FormatError<T> {
|
|
MissingFormat(&'static [&'static str]),
|
|
Parse(T),
|
|
}
|
|
|
|
impl<'a, T: FromParam<'a>> FromParam<'a> for DotJson<T>
|
|
where
|
|
T::Error: TypedError<'a> + fmt::Debug + 'static,
|
|
{
|
|
type Error = FormatError<T::Error>;
|
|
|
|
fn from_param(param: &'a str) -> Result<Self, Self::Error> {
|
|
param
|
|
.strip_suffix(".json")
|
|
.ok_or(FormatError::MissingFormat(&["json"]))
|
|
.and_then(|s| T::from_param(s).map_err(FormatError::Parse))
|
|
.map(Self)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum FormatType {
|
|
Json,
|
|
Opml,
|
|
Jsonp,
|
|
Text,
|
|
Xml,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub struct Format<T>(T, FormatType);
|
|
|
|
impl<T> Format<T> {
|
|
pub fn format(&self) -> FormatType {
|
|
self.1
|
|
}
|
|
}
|
|
|
|
impl<T> std::ops::Deref for Format<T> {
|
|
type Target = T;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl<'a, T: FromParam<'a>> FromParam<'a> for Format<T>
|
|
where
|
|
T::Error: TypedError<'a> + fmt::Debug + 'static,
|
|
{
|
|
type Error = FormatError<T::Error>;
|
|
|
|
fn from_param(param: &'a str) -> Result<Self, Self::Error> {
|
|
// TODO: Support other formats
|
|
if let Some(s) = param
|
|
.strip_suffix(".json") {
|
|
T::from_param(s).map_err(FormatError::Parse)
|
|
.map(|v| Self(v, FormatType::Json))
|
|
} else {
|
|
Err(FormatError::MissingFormat(&["json"]))
|
|
}
|
|
}
|
|
}
|