Documentation
use crate::body::VariantBody;
use hyper::client::conn::http1;
use hyper::http::uri::InvalidUri;
use hyper::{Method, Request, Uri, Version, http};
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use std::sync::Arc;

pub type SendRequest = http1::SendRequest<VariantBody>;

#[derive(Debug)]
pub struct Sender {
    sender: Arc<SendRequest>,
    base_url: String,
}

impl Sender {
    pub fn new(sender: Arc<SendRequest>, base_url: String) -> Self {
        Sender { sender, base_url }
    }

    pub fn base_url(&self) -> &String {
        &self.base_url
    }

    pub fn new_uri(&self, uri: &Uri) -> Result<Uri, InvalidUri> {
        crate::utils::new_uri(self.base_url.clone(), uri)
    }

    fn sender(&self) -> &SendRequest {
        &self.sender
    }

    fn sender_mut(&mut self) -> &mut SendRequest {
        // 这里是安全的, 库保证不会出现同时被引用的情况
        unsafe { &mut *(Arc::as_ptr(&self.sender) as *mut _) }
    }
}

impl Deref for Sender {
    type Target = SendRequest;

    fn deref(&self) -> &Self::Target {
        self.sender()
    }
}

impl DerefMut for Sender {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.sender_mut()
    }
}

/// request构造器, 要求是全路径的uri
pub fn request_builder<T>(uri: T, method: Method) -> http::request::Builder
where
    T: TryInto<Uri>,
    <T as TryInto<Uri>>::Error: Into<http::Error>,
{
    let uri = TryInto::<Uri>::try_into(uri).unwrap_or(Uri::from_static("/"));
    let host = uri.host().unwrap_or("").to_string();

    Request::builder()
        .version(Version::HTTP_11)
        .method(method)
        .uri(uri)
        .header(hyper::header::USER_AGENT, "proxy/0.1")
        .header(hyper::header::HOST, host)
}