specta 2.0.0-rc.25

Easily export your Rust types to other languages
Documentation
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
macro_rules! _impl_primitives {
    ($($i:ident)+) => {$(
        impl Type for $i {
            fn definition(_: &mut Types) -> DataType {
                DataType::Primitive(datatype::Primitive::$i)
            }
        }
    )+};
}

macro_rules! _impl_tuple {
    ( impl $($i:ident),* ) => {
        #[allow(non_snake_case)]
        impl<$($i: Type),*> Type for ($($i,)*) {
            fn definition(_types: &mut Types) -> DataType {
                DataType::Tuple(datatype::Tuple {
                    elements: vec![$(<$i as Type>::definition(_types)),*],
                })
            }
        }
    };
    ( $i2:ident $(, $i:ident)* ) => {
        impl_tuple!(impl $($i),* );
        impl_tuple!($($i),*);
    };
    () => {};
}

macro_rules! _impl_ndt {
    () => {};

    // Multiple types
    (
        $module_path:literal $ty:ident
        $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)?
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $module_path $ty
            $(< $( $lifetime, )* $( $generic ),* >)?
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? >
        < $( $impl_generic:ident ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( $specta_generic ),* >
            < $( $impl_generic ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? >
        < $first_impl_generic:ident, $second_impl_generic:ident, $third_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( $specta_generic ),* >
            < $first_impl_generic, $second_impl_generic, $third_impl_generic, $( const $const_generic : $const_ty ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? >
        < $first_impl_generic:ident, $second_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( $specta_generic ),* >
            < $first_impl_generic, $second_impl_generic, $( const $const_generic : $const_ty ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? >
        < $first_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( $specta_generic ),* >
            < $first_impl_generic, $( const $const_generic : $const_ty, )* $( $rest_impl_generic ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? >
        < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( $specta_generic ),* >
            < $impl_generic, $( const $const_generic : $const_ty ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( const $const_generic : $const_ty ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $( const $const_generic : $const_ty, )* $( $rest_impl_generic ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $head:ident :: $( $tail:ident )::+ < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? >
        $( where { $($bounds:tt)* } )?
        as $as_ty:ty = $kind:ident;
        $($rest:tt)*
    ) => {
        impl_ndt!(@single
            $head :: $( $tail )::+ < $impl_generic, $( const $const_generic : $const_ty ),* >
            $( where { $($bounds)* } )?
            as $as_ty = $kind
        );
        impl_ndt!($($rest)*);
    };
    (
        $(
            $head:ident :: $( $tail:ident )::+
            $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)?
            $( where { $($bounds:tt)* } )?
            as $as_ty:ty = $kind:ident
        );+ $(;)?
    ) => {
        $(
            impl_ndt!(@single
                $head :: $( $tail )::+
                $(< $( $lifetime, )* $( $generic ),* >)?
                $( where { $($bounds)* } )?
                as $as_ty = $kind
            );
        )+
    };

    // Single type
    (@single $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(@kind inline $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(@kind passthrough $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = named) => {
        impl_ndt!(@kind named $module_path $ty $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [$( $specta_generic ),*] [$( $impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $( $impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [$( $specta_generic ),*] [$( $impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $( $impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $( $impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = named) => {
        impl_ndt!(false, false [$( $specta_generic ),*] [$( $impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $( $impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $third_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $third_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $third_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $third_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $third_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $third_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $second_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [$( $specta_generic ),*] [$first_impl_generic, $second_impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $second_impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [$( $specta_generic ),*] [$first_impl_generic, $( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $first_impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [$( $specta_generic ),*] [$first_impl_generic, $( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $first_impl_generic, $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [$( $specta_generic ),*] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( $specta_generic:ident ),* $(,)? > < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [$( $specta_generic ),*] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $( $specta_generic ),* >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [] [$( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [] [< $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [] [$( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [] [< $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [] [$( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [] [< $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $( const $const_generic:ident : $const_ty:ty ),+, $( $rest_impl_generic:ident ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [] [$( const $const_generic : $const_ty, )* $( $rest_impl_generic, )*] [$head :: $( $tail )::+] [] [< $( $const_generic, )* $( $rest_impl_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(true, false [$impl_generic] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $impl_generic >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ < $impl_generic:ident, $( const $const_generic:ident : $const_ty:ty ),+ $(,)? > $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(false, true [$impl_generic] [$impl_generic, $( const $const_generic : $const_ty, )*] [$head :: $( $tail )::+] [< $impl_generic >] [< $impl_generic, $( $const_generic ),* >] $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = inline) => {
        impl_ndt!(@kind inline $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = passthrough) => {
        impl_ndt!(@kind passthrough $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty);
    };
    (@single $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? $( where { $($bounds:tt)* } )? as $as_ty:ty = named) => {
        impl_ndt!(@kind named $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)? $( where { $($bounds)* } )? as $as_ty);
    };

    (@kind inline $($tokens:tt)*) => {
        impl_ndt!(true, false $($tokens)*);
    };
    (@kind passthrough $($tokens:tt)*) => {
        impl_ndt!(false, true $($tokens)*);
    };
    (@kind named $($tokens:tt)*) => {
        impl_ndt!(false, false $($tokens)*);
    };

    // Base implementation. Providing a where clause opts out of automatic Type bounds so
    // callers can use non-Specta impl generics.
    ($inline:literal, $container:literal $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? where { $($bounds:tt)* } as $as_ty:ty) => {
        impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $ty $(< $( $lifetime, )* $( $generic ),* >)?
        where
            $($bounds)*
        {
            fn definition(types: &mut Types) -> DataType {
                use $crate::datatype;

                impl_ndt!(@definition_body false stringify!($ty $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$ty $(< $( $generic ),* >)?], $module_path, $inline, $container, $as_ty, types)
            }
        }
    };
    ($inline:literal, $container:literal $module_path:literal $ty:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? as $as_ty:ty) => {
        impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $ty $(< $( $lifetime, )* $( $generic ),* >)?
        where
            $(
                $( $generic: Type, )*
            )?
        {
            fn definition(types: &mut Types) -> DataType {
                use $crate::datatype;

                impl_ndt!(@definition_body true stringify!($ty $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$ty $(< $( $generic ),* >)?], $module_path, $inline, $container, $as_ty, types)
            }
        }
    };
    ($inline:literal, $container:literal $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? where { $($bounds:tt)* } as $as_ty:ty) => {
        impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)?
        where
            $($bounds)*
        {
            fn definition(types: &mut Types) -> DataType {
                use $crate::datatype;

                impl_ndt!(@definition_body false stringify!($head::$( $tail )::+ $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$head :: $( $tail )::+ $(< $( $generic ),* >)?], impl_ndt!(@module_path $head :: $( $tail )::+), $inline, $container, $as_ty, types)
            }
        }
    };
    ($inline:literal, $container:literal $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)? as $as_ty:ty) => {
        impl<$( $( $lifetime, )* $( $generic ),* )?> Type for $head :: $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)?
        where
            $(
                $( $generic: Type, )*
            )?
        {
            fn definition(types: &mut Types) -> DataType {
                use $crate::datatype;

                impl_ndt!(@definition_body true stringify!($head::$( $tail )::+ $(< $( $generic ),* >)?), [$( $( $generic ),* )?], [$head :: $( $tail )::+ $(< $( $generic ),* >)?], impl_ndt!(@module_path $head :: $( $tail )::+), $inline, $container, $as_ty, types)
            }
        }
    };

    // Base implementation for types with const generics. Const generics are part of the Rust
    // implementation but not Specta generic definitions.
    ($inline:literal, $container:literal [$($generic:ident),*] [$($impl_generics:tt)*] [$($ty:tt)*] [$($specta_generics:tt)*] [$($ty_generics:tt)*] where { $($bounds:tt)* } as $as_ty:ty) => {
        impl<$($impl_generics)*> Type for $($ty)* $($ty_generics)*
        where
            $($bounds)*
        {
            fn definition(types: &mut Types) -> DataType {
                use $crate::datatype;

                impl_ndt!(@definition_body_const false stringify!($($ty)* $($ty_generics)*), [$($generic),*], [$($ty)* $($specta_generics)*], impl_ndt!(@module_path $($ty)*), $inline, $container, $as_ty, types)
            }
        }
    };
    ($inline:literal, $container:literal [$($generic:ident),*] [$($impl_generics:tt)*] [$($ty:tt)*] [$($specta_generics:tt)*] [$($ty_generics:tt)*] as $as_ty:ty) => {
        impl<$($impl_generics)*> Type for $($ty)* $($ty_generics)*
        where
            $($generic: Type,)*
        {
            fn definition(types: &mut Types) -> DataType {
                use $crate::datatype;

                impl_ndt!(@definition_body_const true stringify!($($ty)* $($ty_generics)*), [$($generic),*], [$($ty)* $($specta_generics)*], impl_ndt!(@module_path $($ty)*), $inline, $container, $as_ty, types)
            }
        }
    };

    (@definition_body $typed_generics:tt $sentinel:expr, [$($generic:ident),*], [$($type_name:tt)*], $module_path:expr, $inline:literal, $container:literal, $as_ty:ty, $types:ident) => {{
        impl_ndt!(@definition_body_inner false, $typed_generics $sentinel, [$($generic),*], [$($type_name)*], $module_path, $inline, $container, $as_ty, $types)
    }};
    (@definition_body_const $typed_generics:tt $sentinel:expr, [$($generic:ident),*], [$($type_name:tt)*], $module_path:expr, $inline:literal, $container:literal, $as_ty:ty, $types:ident) => {{
        impl_ndt!(@definition_body_inner true, $typed_generics $sentinel, [$($generic),*], [$($type_name)*], $module_path, $inline, $container, $as_ty, $types)
    }};

    // Helpers for determining NDT name
    (@definition_body_inner $has_const_param:literal, $typed_generics:tt $sentinel:expr, [$($generic:ident),*], [$($type_name:tt)*], $module_path:expr, $inline:literal, $container:literal, $as_ty:ty, $types:ident) => {{
        static SENTINEL: &str = $sentinel;
        static GENERICS: &[datatype::GenericDefinition] = &[
            $(
                datatype::GenericDefinition::new(
                    ::std::borrow::Cow::Borrowed(stringify!($generic)),
                    None,
                ),
            )*
        ];

        let definition = |types: &mut Types| {
            DataType::Reference(datatype::NamedDataType::init_with_sentinel(
                SENTINEL,
                &[
                    $(
                        (
                            datatype::Generic::new(::std::borrow::Cow::Borrowed(stringify!($generic))),
                            impl_ndt!(@generic_dt $typed_generics $generic types),
                        ),
                    )*
                ],
                $has_const_param,
                $container,
                types,
                |types, ndt| {
                    ndt.name = ::std::borrow::Cow::Borrowed(impl_ndt!(@type_name $($type_name)*));
                    ndt.module_path = ::std::borrow::Cow::Borrowed($module_path);
                    ndt.generics = ::std::borrow::Cow::Borrowed(GENERICS);
                    if !$inline && !$container {
                        $(
                            #[allow(dead_code)]
                            pub(crate) struct $generic;
                            impl Type for $generic {
                                fn definition(_: &mut Types) -> DataType {
                                    datatype::Generic::new(
                                        ::std::borrow::Cow::Borrowed(stringify!($generic))
                                    ).into()
                                }
                            }
                        )*
                        ndt.ty = Some(<$as_ty as Type>::definition(types));
                    }
                },
                |types| <$as_ty as Type>::definition(types),
            ))
        };

        if $inline {
            datatype::inline($types, definition)
        } else {
            definition($types)
        }
    }};
    (@generic_dt true $generic:ident $types:ident) => {
        <$generic as Type>::definition($types)
    };
    (@generic_dt false $generic:ident $types:ident) => {
        datatype::Generic::new(::std::borrow::Cow::Borrowed(stringify!($generic))).into()
    };

    // Helpers for determining NDT name
    (@type_name $head:ident :: $( $tail:ident )::+ $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)?) => {
        impl_ndt!(@type_name $( $tail )::+ $(< $( $lifetime, )* $( $generic ),* >)?)
    };
    (@type_name $name:ident $(< $( $lifetime:lifetime, )* $( $generic:ident ),* $(,)? >)?) => {
        stringify!($name)
    };

    // Helpers for determining NDT module path
    (@module_path $head:ident :: $name:ident) => {
        stringify!($head)
    };
    (@module_path $head:ident :: $next:ident :: $( $tail:ident )::+) => {
        concat!(
            stringify!($head),
            "::",
            impl_ndt!(@module_path $next :: $( $tail )::+)
        )
    };
}

#[allow(unused_imports)]
pub(crate) use _impl_ndt as impl_ndt;
pub(crate) use _impl_primitives as impl_primitives;
pub(crate) use _impl_tuple as impl_tuple;