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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//! Abstract types representing requests and how they are executed.
//!
//!

use DigitalOcean;
use api::{HasPagination, HasResponse};
use error::*;
use method::{Create, Delete, Get, List, Method, Update};
use serde_json::Value;
use std::marker::PhantomData;
use url::Url;
use url_serde;

/// A type alias with [`Request<_, Account>`](struct.Request.html) specific functions.
pub type AccountRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Action>`](struct.Request.html) specific functions.
pub type ActionRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Certificate>`](struct.Request.html) specific functions.
pub type CertificateRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, DomainRecord>`](struct.Request.html) specific functions.
pub type DomainRecordRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Domain>`](struct.Request.html) specific functions.
pub type DomainRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, DropletAction>`](struct.Request.html) specific functions.
pub type DropletActionRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Droplet>`](struct.Request.html) specific functions.
pub type DropletRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, FloatingIpAction>`](struct.Request.html) specific functions.
pub type FloatingIpActionRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, FloatingIp>`](struct.Request.html) specific functions.
pub type FloatingIpRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, ImageAction>`](struct.Request.html) specific functions.
pub type ImageActionRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Image>`](struct.Request.html) specific functions.
pub type ImageRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, LoadBalancer>`](struct.Request.html) specific functions.
pub type LoadBalancerRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Region>`](struct.Request.html) specific functions.
pub type RegionRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Size>`](struct.Request.html) specific functions.
pub type SizeRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Snapshot>`](struct.Request.html) specific functions.
pub type SnapshotRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, SshKey>`](struct.Request.html) specific functions.
pub type SshKeyRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Tag>`](struct.Request.html) specific functions.
pub type TagRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, VolumeAction>`](struct.Request.html) specific functions.
pub type VolumeActionRequest<M, V> = Request<M, V>;
/// A type alias with [`Request<_, Volume>`](struct.Request.html) specific functions.
pub type VolumeRequest<M, V> = Request<M, V>;

/// A consuming builder which can be used to build up API calls.
///
/// In general consumers of the crate should not need to use this type directly.
/// Instead, build up requests from what is found in [`api::*`](../api/index.html).
#[derive(Debug, Clone, Serialize, Deserialize, MutGetters, Getters, Setters)]
pub struct Request<A, R>
where
    A: Method,
{
    #[get_mut = "pub"]
    #[set = "pub"]
    #[get = "pub"]
    #[serde(with = "url_serde")]
    url: Url,
    /// The JSON body of the request.
    #[get_mut = "pub"]
    #[set = "pub"]
    #[get = "pub"]
    body: Value,
    #[get = "pub"]
    method: A,
    value: PhantomData<R>,
}

impl<A, V> Request<A, V>
where
    A: Method,
{
    /// Create a request pointing at the given url. `V` is the value ultimately
    /// returned when the call is executed.
    pub fn new(url: Url) -> Self {
        Request {
            url: url,
            body: Value::Null,
            method: A::default(),
            value: PhantomData,
        }
    }
    pub(crate) fn transmute<C, D>(self) -> Request<C, D>
    where
        C: Method,
    {
        let mut req = Request::new(self.url);
        req.set_body(self.body);
        req
    }
}

impl<V> Request<List, V> {
    /// Impose a limit on the number of values which may be retrieved from a request.
    pub fn limit(mut self, limit: Option<usize>) -> Self {
        self.method.0 = limit;
        self
    }
}

/// Describes an API call which can be executed.
pub trait Executable<T>: Sized
where
    T: HasResponse,
{
    /// Execute the corresponding call.
    fn execute(self, instance: &DigitalOcean) -> Result<T>;
}

impl<V> Executable<Vec<V>> for Request<List, Vec<V>>
where
    Vec<V>: HasResponse,
    <Vec<V> as HasResponse>::Response: HasPagination,
{
    fn execute(self, instance: &DigitalOcean) -> Result<Vec<V>> {
        let response: Vec<V> = instance.list(self)?;
        Ok(response)
    }
}

impl<V> Executable<V> for Request<Create, V>
where
    V: HasResponse,
{
    fn execute(self, instance: &DigitalOcean) -> Result<V> {
        let response = instance.post(self)?;
        Ok(response)
    }
}

impl<V> Executable<V> for Request<Update, V>
where
    V: HasResponse,
{
    fn execute(self, instance: &DigitalOcean) -> Result<V> {
        let response = instance.put(self)?;
        Ok(response)
    }
}

impl<V> Executable<V> for Request<Get, V>
where
    V: HasResponse,
{
    fn execute(self, instance: &DigitalOcean) -> Result<V> {
        let response = instance.get(self)?;
        Ok(response)
    }
}

impl Executable<()> for Request<Delete, ()> {
    fn execute(self, instance: &DigitalOcean) -> Result<()> {
        let response = instance.delete(self)?;
        Ok(response)
    }
}