1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#[doc(hidden)]
use proc_macro::TokenStream;
mod column;
pub(crate) mod column_meta;
use column::collect_meta;
use column_meta::COLUMN_META;

#[doc(hidden)]
use quote::quote;

#[doc(hidden)]
use syn::parse_macro_input;
pub(crate) mod indexes;

#[proc_macro_derive(
    Column,
    attributes(dropIndexes, singleIndex, compoundIndex, multikeyIndex)
)]
pub fn column_derive(input: TokenStream) -> TokenStream {
    let st = syn::parse_macro_input!(input as syn::DeriveInput);
    let drop_indexes = st
        .attrs
        .iter()
        .find(|attr| attr.path().is_ident("dropIndexes"));
    let mut drop = false;
    if drop_indexes.is_some() {
        drop = true;
    }
    collect_meta(&st, drop)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}

#[proc_macro_attribute]
pub fn main(_attr: TokenStream, input: TokenStream) -> TokenStream {
    let st = parse_macro_input!(input as syn::ItemFn);
    let mut res = proc_macro2::TokenStream::new();
    res.extend(quote!(
        #[derive(Debug, Clone)]
        pub struct Server<T>(mongodb::Collection<T>);

        unsafe impl<T> Send for Server<T> {}
        unsafe impl<T> Sync for Server<T> {}

        impl<T> std::ops::Deref for Server<T> {
            type Target = mongodb::Collection<T>;

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

        impl<T> AsRef<mongodb::Collection<T>> for Server<T> {
            fn as_ref(&self) -> &mongodb::Collection<T> {
                &self.0
            }
        }

        impl axum::extract::FromRef<axum_mongodb::MongoDbServer<Servers>> for crate::Server<User> {
            fn from_ref(input: &MongoDbServer<Servers>) -> Self {
                input.servers.users.clone()
            }
        }

        #[async_trait]
        impl<S, T> axum::extract::FromRequestParts<S> for crate::Server<T>
        where
            S: Send + Sync,
            Self: axum::extract::FromRef<S>,
            T: Clone,
        {
            type Rejection = std::convert::Infallible;
            async fn from_request_parts(
                _parts: &mut axum::http::request::Parts,
                state: &S,
            ) -> Result<Self, Self::Rejection> {
                use axum::extract::FromRef;
                Ok(Self::from_ref(state))
            }
        }

        #[axum_mongodb::async_trait]
        impl<T> axum_mongodb::NewWithDb for Server<T>
        where
            Self: axum_mongodb::CollectionInit,
        {
            async fn new(db: mongodb::Database) -> Self {
                //通过类型名称设置集合
                let type_name = std::any::type_name::<T>();
                let mut collection_name = type_name.split("::").last().unwrap().to_lowercase();
                collection_name.push('s');
                let collection = db.collection::<T>(&collection_name);
                let res = Self(collection);
                res.init().await;
                res
            }
        }

        #[axum_mongodb::inject_meta]
        pub struct Servers {}

        impl axum::extract::FromRef<axum_mongodb::MongoDbServer<crate::Servers>> for crate::Servers
        {
            fn from_ref(input: &axum_mongodb::MongoDbServer<crate::Servers>) -> Self {
                input.servers.clone()
            }
        }

        #[async_trait]
        impl<S> axum::extract::FromRequestParts<S> for crate::Servers
        where
            S: Send + Sync,
            Self: axum::extract::FromRef<S>,
        {
            type Rejection = std::convert::Infallible;
            async fn from_request_parts(
                _parts: &mut axum::http::request::Parts,
                state: &S,
            ) -> Result<Self, Self::Rejection> {
                use axum::extract::FromRef;
                Ok(Self::from_ref(state))
            }
        }
        #st
    ));
    res.into()
}

#[proc_macro_attribute]
pub fn inject_meta(_attr: TokenStream, input: TokenStream) -> TokenStream {
    let st = parse_macro_input!(input as syn::ItemStruct);
    column::inject_meta(&st)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}

#[proc_macro_attribute]
pub fn inject(_attr: TokenStream, input: TokenStream) -> TokenStream {
    let st = parse_macro_input!(input as syn::ItemFn);
    column::inject(&st)
        .unwrap_or_else(|e| e.to_compile_error())
        .into()
}