bson_comp 0.1.0

A derive macro that implements `Into<bson::Bson>` for a struct or enum.
Documentation
extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

/// A derive macro that implements `Into<bson::Bson>` for a struct or enum.
///
/// This allows the type to be used directly inside the `doc!` macro.
///
/// # Requirements
/// The type must also derive `serde::Serialize`.
///
/// # Example
/// ```ignore
/// #[derive(Serialize, Deserialize, BsonComp)]
/// enum Role {
///     Admin,
///     User
/// }
///
/// // Now this works:
/// let doc = doc! { "role": Role::Admin };
/// ```
#[proc_macro_derive(BsonComp)]
pub fn derive_bson_comp(input: TokenStream) -> TokenStream {
    // 1. Parse the input (the struct or enum)
    let input = parse_macro_input!(input as DeriveInput);

    let name = input.ident;
    let generics = input.generics;

    // 2. Handle Generics (e.g., struct Wrapper<T>)
    // split_for_impl allows us to handle lifetimes and generic parameters correctly
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    // 3. Generate the implementation
    // We implement Into<bson::Bson> for the User's type.
    let expanded = quote! {
        #[automatically_derived]
        impl #impl_generics Into<bson::Bson> for #name #ty_generics #where_clause {
            fn into(self) -> bson::Bson {
                // We use bson::to_bson to handle the actual conversion.
                // Since the doc! macro creates a Bson document usually for queries or inserts,
                // failure to serialize here is typically a developer error (bug in Serialize impl),
                // so panicking is the standard ergonomic trade-off for macros like doc!.
                bson::to_bson(&self).unwrap_or_else(|err| {
                    panic!(
                        "BsonComp: Failed to convert type `{}` to BSON. Ensure it implements Serialize correctly. Error: {}",
                        stringify!(#name),
                        err
                    )
                })
            }
        }
    };

    TokenStream::from(expanded)
}