retrofit_rs/
types.rs

1//! Type wrappers for parameter identification
2//!
3//! These types are used to identify parameter types in API definitions
4//! without requiring attribute macros on function parameters.
5
6use std::ops::Deref;
7
8/// Path parameter wrapper
9///
10/// Use this to mark a parameter as a path parameter.
11///
12/// # Example
13///
14/// ```ignore
15/// #[get("/users/{id}")]
16/// async fn get_user(&self, id: Path<u64>) -> Result<User>;
17/// ```
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
19pub struct Path<T>(pub T);
20
21impl<T> Path<T> {
22    pub fn new(value: T) -> Self {
23        Self(value)
24    }
25
26    pub fn into_inner(self) -> T {
27        self.0
28    }
29}
30
31impl<T> Deref for Path<T> {
32    type Target = T;
33
34    fn deref(&self) -> &Self::Target {
35        &self.0
36    }
37}
38
39impl<T> From<T> for Path<T> {
40    fn from(value: T) -> Self {
41        Self(value)
42    }
43}
44
45/// Query parameter wrapper
46///
47/// Use this to mark a parameter as a query parameter.
48///
49/// # Example
50///
51/// ```ignore
52/// #[get("/search")]
53/// async fn search(&self, q: Query<String>, page: Query<u32>) -> Result<SearchResult>;
54/// ```
55#[derive(Debug, Clone, PartialEq, Eq, Hash)]
56pub struct Query<T>(pub T);
57
58impl<T> Query<T> {
59    pub fn new(value: T) -> Self {
60        Self(value)
61    }
62
63    pub fn into_inner(self) -> T {
64        self.0
65    }
66}
67
68impl<T> Deref for Query<T> {
69    type Target = T;
70
71    fn deref(&self) -> &Self::Target {
72        &self.0
73    }
74}
75
76impl<T> From<T> for Query<T> {
77    fn from(value: T) -> Self {
78        Self(value)
79    }
80}
81
82/// Request body wrapper
83///
84/// Use this to mark a parameter as the request body.
85///
86/// # Example
87///
88/// ```ignore
89/// #[post("/users")]
90/// async fn create_user(&self, user: Body<CreateUser>) -> Result<User>;
91/// ```
92#[derive(Debug, Clone, PartialEq, Eq, Hash)]
93pub struct Body<T>(pub T);
94
95impl<T> Body<T> {
96    pub fn new(value: T) -> Self {
97        Self(value)
98    }
99
100    pub fn into_inner(self) -> T {
101        self.0
102    }
103}
104
105impl<T> Deref for Body<T> {
106    type Target = T;
107
108    fn deref(&self) -> &Self::Target {
109        &self.0
110    }
111}
112
113impl<T> From<T> for Body<T> {
114    fn from(value: T) -> Self {
115        Self(value)
116    }
117}
118
119/// HTTP Header parameter wrapper
120///
121/// Use this to mark a parameter as an HTTP header.
122/// The parameter name will be used as the header name unless specified.
123///
124/// # Example
125///
126/// ```ignore
127/// #[get("/user")]
128/// async fn get_current_user(&self, auth: Header<String>) -> Result<User>;
129/// ```
130#[derive(Debug, Clone, PartialEq, Eq, Hash)]
131pub struct Header<T> {
132    value: T,
133    name: Option<String>,
134}
135
136impl<T> Header<T> {
137    pub fn new(value: T) -> Self {
138        Self { value, name: None }
139    }
140
141    pub fn with_name(value: T, name: impl Into<String>) -> Self {
142        Self {
143            value,
144            name: Some(name.into()),
145        }
146    }
147
148    pub fn into_inner(self) -> T {
149        self.value
150    }
151
152    pub fn name(&self) -> Option<&str> {
153        self.name.as_deref()
154    }
155}
156
157impl<T> Deref for Header<T> {
158    type Target = T;
159
160    fn deref(&self) -> &Self::Target {
161        &self.value
162    }
163}
164
165impl<T> From<T> for Header<T> {
166    fn from(value: T) -> Self {
167        Self::new(value)
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_path_wrapper() {
177        let path = Path::new(42u64);
178        assert_eq!(*path, 42);
179        assert_eq!(path.into_inner(), 42);
180    }
181
182    #[test]
183    fn test_query_wrapper() {
184        let query = Query::new("rust".to_string());
185        assert_eq!(*query, "rust");
186        assert_eq!(query.into_inner(), "rust");
187    }
188
189    #[test]
190    fn test_body_wrapper() {
191        let body = Body::new(vec![1, 2, 3]);
192        assert_eq!(*body, vec![1, 2, 3]);
193        assert_eq!(body.into_inner(), vec![1, 2, 3]);
194    }
195
196    #[test]
197    fn test_header_wrapper() {
198        let header = Header::new("Bearer token".to_string());
199        assert_eq!(*header, "Bearer token");
200        assert_eq!(header.name(), None);
201
202        let header = Header::with_name("token123", "Authorization");
203        assert_eq!(*header, "token123");
204        assert_eq!(header.name(), Some("Authorization"));
205    }
206}