use std::marker::PhantomData;
use std::time::Duration;
use serde::de::DeserializeOwned;
use crate::api::auth_matrix::WireScheme;
use crate::api::response::types::decode;
use crate::error::{Error, Result};
use super::{CallOptions, Client, RequestOptions, RequestTarget};
#[must_use = "a Call does nothing until it is sent"]
pub struct Call<T> {
client: Client,
options: CallOptions,
request: RequestOptions,
paginated: bool,
failed: Option<Error>,
response: PhantomData<fn() -> T>,
}
crate::assert_send_sync!(Call<std::rc::Rc<()>>);
impl<T> std::fmt::Debug for Call<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Call")
.field("method", &self.request.method)
.field("target", &self.request.target)
.field("paginated", &self.paginated)
.field("failed", &self.failed)
.finish_non_exhaustive()
}
}
impl<T> Call<T> {
pub(crate) fn new(client: &Client, request: RequestOptions) -> Self {
Self {
client: client.clone(),
options: CallOptions::default(),
request,
paginated: false,
failed: None,
response: PhantomData,
}
}
pub(crate) fn failed(client: &Client, error: Error) -> Self {
let mut call = Self::new(client, RequestOptions::default());
call.failed = Some(error);
call
}
pub(crate) fn paginated(mut self) -> Self {
self.paginated = true;
self
}
#[doc(hidden)]
pub fn auth_wire_unchecked(mut self, scheme: impl Into<String>) -> Self {
self.options.auth_type = scheme.into();
self
}
}
impl<T: DeserializeOwned> Call<T> {
pub fn auth(self, scheme: WireScheme) -> Self {
self.auth_wire_unchecked(scheme.as_wire())
}
pub fn username(mut self, username: impl Into<String>) -> Self {
self.options.username = username.into();
self
}
pub fn trace(mut self, on: bool) -> Self {
self.options.trace = on;
self
}
pub fn no_auth(mut self, on: bool) -> Self {
self.options.no_auth = on;
self
}
pub fn timeout(mut self, timeout: Duration) -> Self {
self.options.timeout = Some(timeout);
self
}
pub fn pagination_token(mut self, token: impl Into<String>) -> Self {
self.options.pagination_token = token.into();
self
}
pub fn header(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
self.request
.headers
.push(format!("{}: {}", name.into(), value.into()));
self
}
pub async fn send(self) -> Result<T> {
let Self {
client,
options,
mut request,
paginated,
failed,
..
} = self;
if let Some(error) = failed {
return Err(error);
}
request.auth_type = options.auth_type;
request.username = options.username;
request.trace = options.trace;
request.no_auth = options.no_auth;
if paginated
&& !options.pagination_token.is_empty()
&& let RequestTarget::Template { query, .. } = &mut request.target
{
query.push(("pagination_token".to_string(), options.pagination_token));
}
let timeout = options.timeout.unwrap_or_else(|| client.request_timeout());
decode(client.send_request_with(&request, timeout).await?)
}
}