kanamaru-build 0.1.1

the build script required for kanamaru
Documentation
pub mod builder;
pub mod codegen;
pub mod generator;

pub use builder::ProstBuilder;

use proc_macro2::TokenStream;
use prost_build::{Method as PMethod, Service as PService};
use quote::ToTokens;

use crate::utils::{Method, Service};

impl Service for PService {
    type Comment = String;
    type Method = PMethod;

    fn name(&self) -> &str {
        &self.name
    }

    fn package(&self) -> &str {
        &self.package
    }

    fn identifier(&self) -> &str {
        &self.proto_name
    }

    fn methods(&self) -> &[Self::Method] {
        &self.methods
    }

    fn comment(&self) -> &[Self::Comment] {
        &self.comments.leading[..]
    }
}

const NON_PATH_TYPE_ALLOWLIST: &[&str] = &["()"];

impl Method for PMethod {
    type Comment = String;

    fn name(&self) -> &str {
        &self.name
    }

    fn identifier(&self) -> &str {
        &self.proto_name
    }

    fn client_streaming(&self) -> bool {
        self.client_streaming
    }

    fn server_streaming(&self) -> bool {
        self.server_streaming
    }

    fn comment(&self) -> &[Self::Comment] {
        &self.comments.leading[..]
    }

    fn request_response_name(
        &self,
        proto_path: &str,
        compile_well_known_types: bool,
    ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
        let request = convert_type(
            compile_well_known_types,
            proto_path,
            &self.input_proto_type,
            &self.input_type,
        );
        let response = convert_type(
            compile_well_known_types,
            proto_path,
            &self.output_proto_type,
            &self.output_type,
        );
        (request, response)
    }
}

fn convert_type(
    compile_well_known_types: bool,
    proto_path: &str,
    proto_type: &str,
    rust_type: &str,
) -> TokenStream {
    if (is_google_type(proto_type) && !compile_well_known_types)
        || rust_type.starts_with("::")
        || NON_PATH_TYPE_ALLOWLIST.iter().any(|ty| *ty == rust_type)
    {
        rust_type.parse::<TokenStream>().unwrap()
    } else if rust_type.starts_with("crate::") {
        syn::parse_str::<syn::Path>(rust_type)
            .unwrap()
            .to_token_stream()
    } else {
        syn::parse_str::<syn::Path>(&format!("{}::{}", proto_path, rust_type))
            .unwrap()
            .to_token_stream()
    }
}

fn is_google_type(ty: &str) -> bool {
    ty.starts_with(".google.protobuf")
}