use std::marker::PhantomData;
use polyoxide_core::{HttpClient, QueryBuilder, Request};
use serde::de::DeserializeOwned;
use crate::usdm::{
error::UsdmError,
weight::{Cost, Route},
};
pub const USED_WEIGHT_HEADER: &str = "x-mbx-used-weight-1m";
pub(crate) struct Routed<T> {
http: HttpClient,
route: Route,
query: Vec<(&'static str, String)>,
_marker: PhantomData<fn() -> T>,
}
impl<T> Routed<T> {
pub(crate) fn new(http: &HttpClient, route: Route) -> Self {
Self {
http: http.clone(),
route,
query: Vec::new(),
_marker: PhantomData,
}
}
pub(crate) fn query(mut self, key: &'static str, value: impl ToString) -> Self {
let value = value.to_string();
match self.query.iter_mut().find(|(k, _)| *k == key) {
Some(slot) => slot.1 = value,
None => self.query.push((key, value)),
}
self
}
pub(crate) fn route(mut self, route: Route) -> Self {
self.route = route;
self
}
pub(crate) fn cost(&self) -> Cost {
self.route.cost()
}
}
impl<T: DeserializeOwned> Routed<T> {
pub(crate) async fn send(self) -> Result<T, UsdmError> {
let mut request = Request::<T, UsdmError>::new(self.http, self.route.path())
.with_cost(self.route.cost().into());
for (key, value) in self.query {
request = request.query(key, value);
}
request.send().await
}
}
macro_rules! route_builder {
($(#[$doc:meta])* $name:ident => $output:ty) => {
$(#[$doc])*
#[must_use = "a request does nothing until it is sent"]
pub struct $name {
pub(crate) request: $crate::usdm::request::Routed<$output>,
}
impl $name {
pub fn cost(&self) -> $crate::usdm::weight::Cost {
self.request.cost()
}
pub async fn send(self) -> Result<$output, $crate::usdm::UsdmError> {
self.request.send().await
}
}
};
}
pub(crate) use route_builder;