use errors::Result;
use std::default;
use std::rc::Rc;
use {Attributes, Diagnostics, Flavor, Loc, RpChannel, RpPathSpec, Translate, Translator};
#[derive(Debug, Clone, Serialize)]
pub enum RpHttpMethod {
Get,
Post,
Put,
Update,
Delete,
Patch,
Head,
}
impl RpHttpMethod {
pub fn as_str(&self) -> &str {
use self::RpHttpMethod::*;
match *self {
Get => "GET",
Post => "POST",
Put => "PUT",
Update => "UPDATE",
Delete => "DELETE",
Patch => "PATCH",
Head => "HEAD",
}
}
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub enum RpAccept {
#[serde(rename = "json")]
Json,
#[serde(rename = "text")]
Text,
}
impl default::Default for RpAccept {
fn default() -> Self {
RpAccept::Json
}
}
#[derive(Debug, Clone, Serialize, Default)]
#[serde(bound = "F: ::serde::Serialize, F::Type: ::serde::Serialize")]
pub struct RpEndpointHttp<F: 'static>
where
F: Flavor,
{
#[serde(skip_serializing_if = "Option::is_none")]
pub path: Option<RpPathSpec<F>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub body: Option<RpEndpointArgument<F>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub method: Option<RpHttpMethod>,
pub accept: RpAccept,
}
impl<F: 'static, T> Translate<T> for RpEndpointHttp<F>
where
F: Flavor,
T: Translator<Source = F>,
{
type Source = F;
type Out = RpEndpointHttp<T::Target>;
fn translate(
self,
diag: &mut Diagnostics,
translator: &T,
) -> Result<RpEndpointHttp<T::Target>> {
Ok(RpEndpointHttp {
path: self.path.translate(diag, translator)?,
body: self.body.translate(diag, translator)?,
method: self.method,
accept: self.accept,
})
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
#[serde(bound = "F::Type: ::serde::Serialize")]
pub struct RpEndpointArgument<F: 'static>
where
F: Flavor,
{
pub ident: Rc<Loc<String>>,
pub safe_ident: Rc<Option<String>>,
pub channel: Loc<RpChannel<F>>,
}
impl<F: 'static, T> Translate<T> for RpEndpointArgument<F>
where
F: Flavor,
T: Translator<Source = F>,
{
type Source = F;
type Out = RpEndpointArgument<T::Target>;
fn translate(
self,
diag: &mut Diagnostics,
translator: &T,
) -> Result<RpEndpointArgument<T::Target>> {
Ok(RpEndpointArgument {
ident: self.ident,
safe_ident: self.safe_ident,
channel: self.channel.translate(diag, translator)?,
})
}
}
impl<F: 'static> RpEndpointArgument<F>
where
F: Flavor,
{
pub fn ident(&self) -> &str {
self.ident.as_str()
}
pub fn safe_ident(&self) -> &str {
Option::as_ref(&self.safe_ident)
.map(|s| s.as_str())
.unwrap_or_else(|| self.ident.as_str())
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(bound = "F: ::serde::Serialize, F::Type: ::serde::Serialize")]
pub struct RpEndpoint<F: 'static>
where
F: Flavor,
{
pub ident: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub safe_ident: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
pub comment: Vec<String>,
pub attributes: Attributes,
pub arguments: Vec<RpEndpointArgument<F>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub request: Option<RpEndpointArgument<F>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub response: Option<Loc<RpChannel<F>>>,
pub http: RpEndpointHttp<F>,
}
impl<F: 'static> RpEndpoint<F>
where
F: Flavor,
{
pub fn id_parts<T>(&self, filter: T) -> Vec<String>
where
T: Fn(&str) -> String,
{
vec![filter(self.ident.as_str())]
}
pub fn name(&self) -> &str {
self.name
.as_ref()
.map(|s| s.as_str())
.unwrap_or(self.ident())
}
pub fn safe_ident(&self) -> &str {
self.safe_ident
.as_ref()
.map(|s| s.as_str())
.unwrap_or(self.ident.as_str())
}
pub fn ident(&self) -> &str {
self.ident.as_str()
}
pub fn has_http_support(&self) -> bool {
if !self.http.path.is_some() {
return false;
}
true
}
}
impl<F: 'static, T> Translate<T> for RpEndpoint<F>
where
F: Flavor,
T: Translator<Source = F>,
{
type Source = F;
type Out = RpEndpoint<T::Target>;
fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<RpEndpoint<T::Target>> {
Ok(RpEndpoint {
ident: self.ident,
safe_ident: self.safe_ident,
name: self.name,
comment: self.comment,
attributes: self.attributes,
arguments: self.arguments.translate(diag, translator)?,
request: self.request.translate(diag, translator)?,
response: self.response.translate(diag, translator)?,
http: self.http.translate(diag, translator)?,
})
}
}
#[derive(Debug, Clone)]
pub struct RpEndpointHttp1<F: 'static>
where
F: Flavor,
{
pub request: Option<F::Type>,
pub response: Option<F::Type>,
pub path: RpPathSpec<F>,
pub method: RpHttpMethod,
}
impl<F: 'static> RpEndpointHttp1<F>
where
F: Clone + Flavor,
{
pub fn from_endpoint(endpoint: &RpEndpoint<F>) -> Option<RpEndpointHttp1<F>> {
use self::RpChannel::*;
let path = match endpoint.http.path.as_ref() {
Some(path) => path.clone(),
None => return None,
};
let request_ty = endpoint.request.as_ref().map(|r| Loc::borrow(&r.channel));
let response_ty = endpoint.response.as_ref().map(|r| Loc::borrow(r));
let (request, response) = match (request_ty, response_ty) {
(Some(&Unary { ty: ref request }), Some(&Unary { ty: ref response })) => {
(Some(request.clone()), Some(response.clone()))
}
(None, Some(&Unary { ty: ref response })) => (None, Some(response.clone())),
(Some(&Unary { ty: ref request }), None) => (Some(request.clone()), None),
(None, None) => (None, None),
_ => return None,
};
let method = endpoint
.http
.method
.as_ref()
.cloned()
.unwrap_or(RpHttpMethod::Get);
return Some(RpEndpointHttp1 {
request: request,
response: response,
path: path,
method: method,
});
}
}