1use errors::Result;
4use std::default;
5use std::rc::Rc;
6use {Attributes, Diagnostics, Flavor, Loc, RpChannel, RpPathSpec, Translate, Translator};
7
8#[derive(Debug, Clone, Serialize)]
9pub enum RpHttpMethod {
10 Get,
11 Post,
12 Put,
13 Update,
14 Delete,
15 Patch,
16 Head,
17}
18
19impl RpHttpMethod {
20 pub fn as_str(&self) -> &str {
22 use self::RpHttpMethod::*;
23
24 match *self {
25 Get => "GET",
26 Post => "POST",
27 Put => "PUT",
28 Update => "UPDATE",
29 Delete => "DELETE",
30 Patch => "PATCH",
31 Head => "HEAD",
32 }
33 }
34}
35
36#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
37pub enum RpAccept {
38 #[serde(rename = "json")]
39 Json,
40 #[serde(rename = "text")]
41 Text,
42}
43
44impl default::Default for RpAccept {
45 fn default() -> Self {
46 RpAccept::Json
47 }
48}
49
50#[derive(Debug, Clone, Serialize, Default)]
51#[serde(bound = "F: ::serde::Serialize, F::Type: ::serde::Serialize")]
52pub struct RpEndpointHttp<F: 'static>
53where
54 F: Flavor,
55{
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub path: Option<RpPathSpec<F>>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub body: Option<RpEndpointArgument<F>>,
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub method: Option<RpHttpMethod>,
65 pub accept: RpAccept,
67}
68
69impl<F: 'static, T> Translate<T> for RpEndpointHttp<F>
70where
71 F: Flavor,
72 T: Translator<Source = F>,
73{
74 type Source = F;
75 type Out = RpEndpointHttp<T::Target>;
76
77 fn translate(
79 self,
80 diag: &mut Diagnostics,
81 translator: &T,
82 ) -> Result<RpEndpointHttp<T::Target>> {
83 Ok(RpEndpointHttp {
84 path: self.path.translate(diag, translator)?,
85 body: self.body.translate(diag, translator)?,
86 method: self.method,
87 accept: self.accept,
88 })
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
94#[serde(bound = "F::Type: ::serde::Serialize")]
95pub struct RpEndpointArgument<F: 'static>
96where
97 F: Flavor,
98{
99 pub ident: Rc<Loc<String>>,
101 pub safe_ident: Rc<Option<String>>,
103 pub channel: Loc<RpChannel<F>>,
105}
106
107impl<F: 'static, T> Translate<T> for RpEndpointArgument<F>
108where
109 F: Flavor,
110 T: Translator<Source = F>,
111{
112 type Source = F;
113 type Out = RpEndpointArgument<T::Target>;
114
115 fn translate(
117 self,
118 diag: &mut Diagnostics,
119 translator: &T,
120 ) -> Result<RpEndpointArgument<T::Target>> {
121 Ok(RpEndpointArgument {
122 ident: self.ident,
123 safe_ident: self.safe_ident,
124 channel: self.channel.translate(diag, translator)?,
125 })
126 }
127}
128
129impl<F: 'static> RpEndpointArgument<F>
130where
131 F: Flavor,
132{
133 pub fn ident(&self) -> &str {
135 self.ident.as_str()
136 }
137
138 pub fn safe_ident(&self) -> &str {
140 Option::as_ref(&self.safe_ident)
141 .map(|s| s.as_str())
142 .unwrap_or_else(|| self.ident.as_str())
143 }
144}
145
146#[derive(Debug, Clone, Serialize)]
147#[serde(bound = "F: ::serde::Serialize, F::Type: ::serde::Serialize")]
148pub struct RpEndpoint<F: 'static>
149where
150 F: Flavor,
151{
152 pub ident: String,
154 #[serde(skip_serializing_if = "Option::is_none")]
156 pub safe_ident: Option<String>,
157 #[serde(skip_serializing_if = "Option::is_none")]
159 pub name: Option<String>,
160 pub comment: Vec<String>,
162 pub attributes: Attributes,
164 pub arguments: Vec<RpEndpointArgument<F>>,
166 #[serde(skip_serializing_if = "Option::is_none")]
168 pub request: Option<RpEndpointArgument<F>>,
169 #[serde(skip_serializing_if = "Option::is_none")]
171 pub response: Option<Loc<RpChannel<F>>>,
172 pub http: RpEndpointHttp<F>,
174}
175
176impl<F: 'static> RpEndpoint<F>
177where
178 F: Flavor,
179{
180 pub fn id_parts<T>(&self, filter: T) -> Vec<String>
181 where
182 T: Fn(&str) -> String,
183 {
184 vec![filter(self.ident.as_str())]
185 }
186
187 pub fn name(&self) -> &str {
189 self.name
190 .as_ref()
191 .map(|s| s.as_str())
192 .unwrap_or(self.ident())
193 }
194
195 pub fn safe_ident(&self) -> &str {
197 self.safe_ident
198 .as_ref()
199 .map(|s| s.as_str())
200 .unwrap_or(self.ident.as_str())
201 }
202
203 pub fn ident(&self) -> &str {
205 self.ident.as_str()
206 }
207
208 pub fn has_http_support(&self) -> bool {
210 if !self.http.path.is_some() {
211 return false;
212 }
213
214 true
215 }
216}
217
218impl<F: 'static, T> Translate<T> for RpEndpoint<F>
219where
220 F: Flavor,
221 T: Translator<Source = F>,
222{
223 type Source = F;
224 type Out = RpEndpoint<T::Target>;
225
226 fn translate(self, diag: &mut Diagnostics, translator: &T) -> Result<RpEndpoint<T::Target>> {
228 Ok(RpEndpoint {
229 ident: self.ident,
230 safe_ident: self.safe_ident,
231 name: self.name,
232 comment: self.comment,
233 attributes: self.attributes,
234 arguments: self.arguments.translate(diag, translator)?,
235 request: self.request.translate(diag, translator)?,
236 response: self.response.translate(diag, translator)?,
237 http: self.http.translate(diag, translator)?,
238 })
239 }
240}
241
242#[derive(Debug, Clone)]
244pub struct RpEndpointHttp1<F: 'static>
245where
246 F: Flavor,
247{
248 pub request: Option<F::Type>,
249 pub response: Option<F::Type>,
250 pub path: RpPathSpec<F>,
251 pub method: RpHttpMethod,
252}
253
254impl<F: 'static> RpEndpointHttp1<F>
255where
256 F: Clone + Flavor,
257{
258 pub fn from_endpoint(endpoint: &RpEndpoint<F>) -> Option<RpEndpointHttp1<F>> {
260 use self::RpChannel::*;
261
262 let path = match endpoint.http.path.as_ref() {
264 Some(path) => path.clone(),
265 None => return None,
266 };
267
268 let request_ty = endpoint.request.as_ref().map(|r| Loc::borrow(&r.channel));
269 let response_ty = endpoint.response.as_ref().map(|r| Loc::borrow(r));
270
271 let (request, response) = match (request_ty, response_ty) {
272 (Some(&Unary { ty: ref request }), Some(&Unary { ty: ref response })) => {
273 (Some(request.clone()), Some(response.clone()))
274 }
275 (None, Some(&Unary { ty: ref response })) => (None, Some(response.clone())),
276 (Some(&Unary { ty: ref request }), None) => (Some(request.clone()), None),
277 (None, None) => (None, None),
278 _ => return None,
279 };
280
281 let method = endpoint
282 .http
283 .method
284 .as_ref()
285 .cloned()
286 .unwrap_or(RpHttpMethod::Get);
287
288 return Some(RpEndpointHttp1 {
289 request: request,
290 response: response,
291 path: path,
292 method: method,
293 });
294 }
295}