1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//! # `comfund`: WCF-like Service Contracts in Rust
//!
//! `proc-macro` crate for comfund `contract` attribute.
//!
//! *Contract* is a rust trait representing possible requests to a service,
//! parameters of each request and its return type.
//!
//! For client side, either
//! a stateful client or static implementation will be generated.
//!
//! For server side, a service trait will be generated. Implementation of this trait
//! can then be passed to a generated configure function to create configuration/router with
//! corresponding handlers and middleware mounted on specified paths.
//!
//! ## Additional attributes and options
//!
//! Every `fn` of contract trait should be annotated with `#[endpoint]` attribute with two
//! required arguments:
//!
//! - Method [get, post, put, delete]
//! - Endpoint path ("/"-prefixed string literal)
//!
//! ```
//! use comfund::contract;
//!
//! #[contract]
//! pub trait Service {
//! #[endpoint(get, "/")]
//! fn endpoint();
//! }
//! ```
//!
//! Endpoints can accept parameters. Each parameter should be annotated with `#[param]`
//! attribute with one required arg - type of transport:
//! - through endpoint URL path (`path`),
//! - URL query param (`query`)
//! - Request body (`plain text` or `json`)
//!
//! ```
//! use comfund::contract;
//!
//! #[contract]
//! pub trait Service {
//! #[endpoint(get, "/path/{a}")]
//! fn path(#[param(path)] a: String);
//!
//! #[endpoint(get, "/query")]
//! fn query(#[param(query)] a: String);
//!
//! #[endpoint(post, "/body")]
//! fn body(#[param(body)]) a: String);
//!
//! #[endpoint(post, "/body/json")]
//! fn json(#[param(json)]) a: Vec<String>);
//! }
//! ```
//!
//! Endpoints can also have return types. If you want to be able to return/read error info as well,
//! you can set [`Result`] as return type.
//!
//! ```
//! use comfund::contract;
//!
//! #[contract]
//! pub trait Service {
//! #[endpoint(get, "/")]
//! fn infallible() -> String;
//!
//! #[endpoint(get, "/may_fail")]
//! fn may_fail() -> Result<String, Error>;
//! }
//! ```
//!
//! Endpoints can also specify `content-type` for returned value. Generated server and client code will
//! handle the conversion accordingly.
//!
//! ```
//! use comfund::contract;
//! use comfund::serde::{Serialize, Deserialize};
//!
//! #[derive(Serialize, Deserialize)]
//! #[serde(crate = comfund::serde)]
//! struct Return {
//! status: u16,
//! string: String
//! }
//!
//! #[contract]
//! pub trait Service {
//! #[endpoint(get, "/may_fail", content_type = "application/json")]
//! fn may_fail() -> Return;
//! }
//! ```
use TokenStream;
/// # `contract` attribute macro
///
/// `contract` should be applied to a `trait`. Сurrently, only `fn` items are supported for parsing
/// and presense of other types of items (like consts and associated types) will trigger compile errors,
/// as well as presence of generic parameters (though it's planned to support
/// trait level type generics in the future).