use std::marker::PhantomData;
use std::any::Any;
use bit_set::BitSet;
use iron::Handler;
use iron::middleware::Chain;
use iron::{Request, Response, IronResult};
use iron::method::Method;
use router::Router;
use self::ResourceMethod::*;
use internals::{Parsers, OptionHandler};
use types::*;
const BASE_PATH: &'static str = "/";
const ID_PATH: &'static str = "/:resource_id";
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u8)]
pub enum ResourceMethod {
Create,
List,
Get,
Replace,
Delete,
HttpHead,
HttpHeadList,
CustomHttpOptions,
CustomHttpOptionsList
}
impl ResourceMethod {
fn bitset_id(&self) -> u16 {
*self as u16
}
fn info(&self) -> (Method, &'static str, &'static str) {
match *self {
Create => (Method::Post, BASE_PATH, "create"),
List => (Method::Get, BASE_PATH, "list"),
ResourceMethod::Get => (Method::Get, ID_PATH, "get"),
Replace => (Method::Put, ID_PATH, "put"),
Delete => (Method::Delete, ID_PATH, "delete"),
HttpHead => (Method::Head, ID_PATH, "head"),
HttpHeadList => (Method::Head, BASE_PATH, "list"),
CustomHttpOptions => (Method::Options, ID_PATH, "options"),
CustomHttpOptionsList => (Method::Options, BASE_PATH, "list_options")
}
}
}
pub struct ResourceEndpoint(Router);
impl Handler for ResourceEndpoint {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
self.0.handle(req)
}
}
pub struct ResourceEndpointBuilder<I: Id+Any, OpP: ParserMiddleware, R: Resource, BoP: ParserMiddleware> {
_id_info: PhantomData<I>,
_resource: PhantomData<R>,
route_id_base: String,
parsers: Parsers<OpP, BoP>,
seted_values: BitSet,
router: Router
}
impl
<OpP: OptionParser, R: Resource, BoP: BodyParser<R>>
ResourceEndpointBuilder<R::RId, OpP, R, BoP>
where R::RId: Sync+Send+Any
{
pub fn new(route_id_base: String, option_parser: OpP, body_parser: BoP)
-> ResourceEndpointBuilder<R::RId, OpP, R, BoP>
{
ResourceEndpointBuilder {
_resource: PhantomData,
_id_info: PhantomData,
route_id_base: route_id_base,
parsers: Parsers::new::<R::RId>(option_parser, body_parser),
router: Router::new(),
seted_values: BitSet::new()
}
}
pub fn is_method_set(&self, method: ResourceMethod) -> bool {
self.seted_values.contains(method.bitset_id() as usize)
}
pub fn finalize(mut self) -> ResourceEndpoint {
if !self.is_method_set(CustomHttpOptions) {
let mut allowed_methods = vec![Method::Options];
if self.is_method_set(Delete) {
allowed_methods.push(Delete.info().0);
}
if self.is_method_set(Replace) {
allowed_methods.push(Replace.info().0);
}
if self.is_method_set(Get) {
allowed_methods.push(Get.info().0);
}
self = self.route(CustomHttpOptions, OptionHandler::new(allowed_methods));
}
if !self.is_method_set(CustomHttpOptionsList) {
let mut allowed_methods = vec![Method::Options];
if self.is_method_set(List) {
allowed_methods.push(List.info().0);
}
if self.is_method_set(Create) {
allowed_methods.push(Create.info().0);
}
self = self.route(CustomHttpOptionsList, OptionHandler::new(allowed_methods));
}
ResourceEndpoint(self.router)
}
pub fn route<H: Handler>(mut self, resource_method: ResourceMethod, handler: H) -> Self {
if !self.seted_values.insert(resource_method.bitset_id() as usize) {
panic!("ResourceMethod [{:?}] was already set", resource_method);
}
let (method, route, rout_id_postfix) = resource_method.info();
let chain = self.create_chain(resource_method, handler);
let mut rout_id = self.route_id_base.clone();
rout_id.push_str(rout_id_postfix);
self.router.route(method, route, chain, rout_id);
self
}
fn create_chain<H: Handler>(&self, meth: ResourceMethod, handler: H) -> Chain {
match meth {
Create => chain_with_body(&self.parsers, handler),
List => chain(&self.parsers, handler),
Get => chain_with_id(&self.parsers, handler),
Replace => chain_with_id_body(&self.parsers, handler),
Delete => chain_with_id(&self.parsers, handler),
HttpHead => chain_with_id(&self.parsers, handler),
HttpHeadList => chain(&self.parsers, handler),
CustomHttpOptions => chain_with_id(&self.parsers, handler),
CustomHttpOptionsList => chain(&self.parsers, handler)
}
}
#[inline]
pub fn create<H: Handler>(self, handler: H) -> Self {
self.route(Create, handler)
}
#[inline]
pub fn list<H: Handler>(self, handler: H) -> Self {
self.route(List, handler)
}
#[inline]
pub fn delete<H: Handler>(self, handler: H) -> Self {
self.route(Delete, handler)
}
#[inline]
pub fn replace<H: Handler>(self, handler: H) -> Self {
self.route(Replace, handler)
}
#[inline]
pub fn get<H: Handler>(self, handler: H) -> Self {
self.route(Get, handler)
}
}
fn chain<OpP, BoP, H>(parsers: &Parsers<OpP, BoP>, handler: H) -> Chain
where OpP: ParserMiddleware, BoP: ParserMiddleware, H: Handler
{
let mut chain = Chain::new(handler);
chain.link_before(parsers.option_parser.clone());
chain
}
fn chain_with_id<OpP, BoP, H>(parsers: &Parsers<OpP, BoP>, handler: H) -> Chain
where OpP: ParserMiddleware, BoP: ParserMiddleware, H: Handler
{
let mut chain = Chain::new(handler);
chain.link_before(parsers.option_parser.clone());
chain.link_before(parsers.id_parser.clone());
chain
}
fn chain_with_body<OpP, BoP, H>(parsers: &Parsers<OpP, BoP>, handler: H) -> Chain
where OpP: ParserMiddleware, BoP: ParserMiddleware, H: Handler
{
let mut chain = Chain::new(handler);
chain.link_before(parsers.option_parser.clone());
chain.link_before(parsers.body_parser.clone());
chain
}
fn chain_with_id_body<OpP, BoP, H>(parsers: &Parsers<OpP, BoP>, handler: H) -> Chain
where OpP: ParserMiddleware, BoP: ParserMiddleware, H: Handler
{
let mut chain = Chain::new(handler);
chain.link_before(parsers.option_parser.clone());
chain.link_before(parsers.id_parser.clone());
chain.link_before(parsers.body_parser.clone());
chain
}