Initial implementation

This commit is contained in:
2025-09-27 00:29:57 -05:00
commit 957bf1b549
13 changed files with 4671 additions and 0 deletions

80
src/format.rs Normal file
View File

@@ -0,0 +1,80 @@
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"]))
}
}
}