1use crate::api::{HasPagination, HasResponse};
6use crate::error::Error;
7use crate::method::{Create, Delete, Get, List, Method, Update};
8use crate::DigitalOcean;
9use async_trait::async_trait;
10use getset::{Getters, MutGetters, Setters};
11use serde::Deserialize;
12use serde_json::Value;
13use std::marker::PhantomData;
14use url::Url;
15
16mod url_serde {
17 #![allow(unused)]
18
19 use serde::{Deserialize, Deserializer, Serialize, Serializer};
20 use url::Url;
21
22 pub fn serialize<S>(url: &Url, serializer: S) -> Result<S::Ok, S::Error>
23 where
24 S: Serializer,
25 {
26 url.to_string().serialize(serializer)
27 }
28
29 pub fn deserialize<'de, D>(deserializer: D) -> Result<Url, D::Error>
30 where
31 D: Deserializer<'de>,
32 {
33 let url_str: String = String::deserialize(deserializer)?;
34 Url::parse(&url_str).map_err(serde::de::Error::custom)
35 }
36}
37
38pub type AccountRequest<M, V> = Request<M, V>;
40pub type ActionRequest<M, V> = Request<M, V>;
42pub type CertificateRequest<M, V> = Request<M, V>;
44pub type DomainRecordRequest<M, V> = Request<M, V>;
46pub type DomainRequest<M, V> = Request<M, V>;
48pub type DropletActionRequest<M, V> = Request<M, V>;
50pub type DropletRequest<M, V> = Request<M, V>;
52pub type FloatingIpActionRequest<M, V> = Request<M, V>;
54pub type FloatingIpRequest<M, V> = Request<M, V>;
56pub type ImageActionRequest<M, V> = Request<M, V>;
58pub type ImageRequest<M, V> = Request<M, V>;
60pub type CustomImageRequest<M, V> = Request<M, V>;
62pub type LoadBalancerRequest<M, V> = Request<M, V>;
64pub type RegionRequest<M, V> = Request<M, V>;
66pub type SizeRequest<M, V> = Request<M, V>;
68pub type SnapshotRequest<M, V> = Request<M, V>;
70pub type SshKeyRequest<M, V> = Request<M, V>;
72pub type TagRequest<M, V> = Request<M, V>;
74pub type VolumeActionRequest<M, V> = Request<M, V>;
76pub type VolumeRequest<M, V> = Request<M, V>;
78
79#[derive(Debug, Clone, Deserialize, MutGetters, Getters, Setters)]
84pub struct Request<A: Method, R> {
85 #[get_mut = "pub"]
86 #[set = "pub"]
87 #[get = "pub"]
88 #[serde(with = "url_serde")]
89 url: Url,
90
91 #[get_mut = "pub"]
93 #[set = "pub"]
94 #[get = "pub"]
95 body: Value,
96
97 #[get = "pub"]
98 method: A,
99
100 value: PhantomData<R>,
101}
102
103impl<A: Method, V> Request<A, V> {
104 pub fn new(url: Url) -> Self {
107 Request {
108 url,
109 body: Value::Null,
110 method: A::default(),
111 value: PhantomData,
112 }
113 }
114
115 pub(crate) fn transmute<C: Method, D>(self) -> Request<C, D> {
116 let mut req = Request::new(self.url);
117 req.set_body(self.body);
118 req
119 }
120}
121
122impl<V> Request<List, V> {
123 pub fn limit(mut self, limit: Option<usize>) -> Self {
125 self.method.0 = limit;
126 self
127 }
128}
129
130#[async_trait]
132pub trait Executable<T: HasResponse>: Sized {
133 async fn execute(self, instance: &DigitalOcean) -> Result<T, Error>;
135}
136
137#[async_trait]
138impl<V> Executable<Vec<V>> for Request<List, Vec<V>>
139where
140 Vec<V>: HasResponse,
141 <Vec<V> as HasResponse>::Response: HasPagination,
142 V: std::marker::Send,
143{
144 async fn execute(self, instance: &DigitalOcean) -> Result<Vec<V>, Error> {
145 let response: Vec<V> = instance.list(self).await?;
146 Ok(response)
147 }
148}
149
150#[async_trait]
151impl<V: HasResponse + std::marker::Send> Executable<V> for Request<Create, V> {
152 async fn execute(self, instance: &DigitalOcean) -> Result<V, Error> {
153 let response = instance.post(self).await?;
154 Ok(response)
155 }
156}
157
158#[async_trait]
159impl<V: HasResponse + std::marker::Send> Executable<V> for Request<Update, V> {
160 async fn execute(self, instance: &DigitalOcean) -> Result<V, Error> {
161 let response = instance.put(self).await?;
162 Ok(response)
163 }
164}
165
166#[async_trait]
167impl<V: HasResponse + std::marker::Send> Executable<V> for Request<Get, V> {
168 async fn execute(self, instance: &DigitalOcean) -> Result<V, Error> {
169 let response = instance.get(self).await?;
170 Ok(response)
171 }
172}
173
174#[async_trait]
175impl Executable<()> for Request<Delete, ()> {
176 async fn execute(self, instance: &DigitalOcean) -> Result<(), Error> {
177 instance.delete(self).await
178 }
179}