predawn-core 0.9.0

Core types and traits for predawn
Documentation
use std::collections::BTreeMap;

use bytes::Bytes;
use http::{HeaderMap, Method, Uri, Version};

use crate::{
    body::RequestBody,
    media_type::MultiRequestMediaType,
    openapi::{self, Parameter, Schema},
    private::{ViaRequest, ViaRequestHead},
    request::{BodyLimit, Head, LocalAddr, OriginalUri, RemoteAddr},
};

pub trait ApiRequestHead {
    fn parameters(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<Vec<Parameter>>;
}

pub trait ApiRequest<M = ViaRequest> {
    fn parameters(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<Vec<Parameter>>;

    fn request_body(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<openapi::RequestBody>;
}

impl<T> ApiRequest<ViaRequestHead> for T
where
    T: ApiRequestHead,
{
    fn parameters(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<Vec<Parameter>> {
        T::parameters(schemas, schemas_in_progress)
    }

    fn request_body(
        _: &mut BTreeMap<String, Schema>,
        _: &mut Vec<String>,
    ) -> Option<openapi::RequestBody> {
        None
    }
}

impl ApiRequest for RequestBody {
    fn parameters(_: &mut BTreeMap<String, Schema>, _: &mut Vec<String>) -> Option<Vec<Parameter>> {
        None
    }

    fn request_body(
        _: &mut BTreeMap<String, Schema>,
        _: &mut Vec<String>,
    ) -> Option<openapi::RequestBody> {
        None
    }
}

macro_rules! some_api_request_impl {
    ($($ty:ty),+ $(,)?) => {
        $(
            impl ApiRequest for $ty {
                fn parameters(_: &mut BTreeMap<String, Schema>, _: &mut Vec<String>) -> Option<Vec<Parameter>> {
                    None
                }

                fn request_body(schemas: &mut BTreeMap<String, Schema>, schemas_in_progress: &mut Vec<String>) -> Option<openapi::RequestBody> {
                    Some(openapi::RequestBody {
                        content: <$ty as MultiRequestMediaType>::content(schemas, schemas_in_progress),
                        required: true,
                        ..Default::default()
                    })
                }
            }
        )+
    };
}

some_api_request_impl![Bytes, Vec<u8>, String];

macro_rules! some_api_request_head_impl {
    ($($ty:ty),+ $(,)?) => {
        $(
            impl ApiRequestHead for $ty {
                fn parameters(_: &mut BTreeMap<String, Schema>, _: &mut Vec<String>) -> Option<Vec<Parameter>> {
                    None
                }
            }
        )+
    };
}

some_api_request_head_impl![
    Uri,
    Method,
    HeaderMap,
    OriginalUri,
    Version,
    LocalAddr,
    RemoteAddr,
    BodyLimit,
    Head,
];

macro_rules! optional_parameters {
    ($ty:ty) => {
        fn parameters(
            schemas: &mut BTreeMap<String, Schema>,
            schemas_in_progress: &mut Vec<String>,
        ) -> Option<Vec<Parameter>> {
            let mut parameters = <$ty>::parameters(schemas, schemas_in_progress)?;

            parameters.iter_mut().for_each(|parameter| match parameter {
                Parameter::Query { parameter_data, .. } => parameter_data.required = false,
                Parameter::Header { parameter_data, .. } => parameter_data.required = false,
                Parameter::Path { parameter_data, .. } => parameter_data.required = false,
                Parameter::Cookie { parameter_data, .. } => parameter_data.required = false,
            });

            Some(parameters)
        }
    };
}

impl<T: ApiRequestHead> ApiRequestHead for Option<T> {
    optional_parameters!(T);
}

impl<T: ApiRequest> ApiRequest for Option<T> {
    optional_parameters!(T);

    fn request_body(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<openapi::RequestBody> {
        let mut request_body = T::request_body(schemas, schemas_in_progress)?;
        request_body.required = false;
        Some(request_body)
    }
}

impl<T, E> ApiRequestHead for Result<T, E>
where
    T: ApiRequestHead,
{
    fn parameters(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<Vec<Parameter>> {
        T::parameters(schemas, schemas_in_progress)
    }
}

impl<T, E> ApiRequest for Result<T, E>
where
    T: ApiRequest,
{
    fn parameters(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<Vec<Parameter>> {
        T::parameters(schemas, schemas_in_progress)
    }

    fn request_body(
        schemas: &mut BTreeMap<String, Schema>,
        schemas_in_progress: &mut Vec<String>,
    ) -> Option<openapi::RequestBody> {
        T::request_body(schemas, schemas_in_progress)
    }
}