synapse-codegen 0.0.2

Code generation from protobuf service definitions for Synapse
Documentation
//! Client stub generation

use crate::ServiceDef;
use anyhow::Result;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

/// Generate client stub for a service
///
/// Generated clients accept a SynClient (unified connection pool) instead of creating their own.
/// This allows efficient connection reuse across all service clients.
///
/// Example output:
/// ```text
/// pub struct UserServiceClient {
///     client: synapse_sdk::SynClient,
/// }
///
/// impl UserServiceClient {
///     pub fn new(client: synapse_sdk::SynClient) -> Self { ... }
///     pub async fn get_user(&self, request: GetUserRequest) -> Result<GetUserResponse> { ... }
/// }
/// ```
pub fn generate_client_stub(service: &ServiceDef) -> Result<TokenStream> {
    let client_name = format_ident!("{}Client", service.service_name);
    let package = &service.package;

    let interface_id = service.interface_id_expr();

    // Generate method stubs
    let methods: Vec<TokenStream> = service
        .methods
        .iter()
        .map(|method| {
            let method_name = format_ident!("{}", method.method_name_snake());
            let method_id = method.method_id_expr();
            let input_type = method.input_type_path(package);
            let output_type = method.output_type_path(package);

            let comment = method.comment.as_ref().map(|c| {
                let doc = format!(" {}", c);
                quote! { #[doc = #doc] }
            });

            quote! {
                #comment
                pub async fn #method_name(&self, request: #input_type) -> anyhow::Result<#output_type> {
                    self.client.call_proto(#interface_id, #method_id, &request).await
                }
            }
        })
        .collect();

    Ok(quote! {
        /// Generated client for #client_name
        ///
        /// Uses the shared SynClient connection pool for efficient communication.
        #[derive(Clone)]
        pub struct #client_name {
            client: synapse_sdk::SynClient,
        }

        impl #client_name {
            /// Create a new client using a SynClient connection pool
            pub fn new(client: synapse_sdk::SynClient) -> Self {
                Self { client }
            }

            #(#methods)*
        }
    })
}