keypath_proc_macros/
lib.rs

1//! derive macros for the keypath crate.
2
3#![deny(clippy::trivially_copy_pass_by_ref)]
4
5extern crate proc_macro;
6
7mod attr;
8mod keyable;
9mod keypath;
10mod keypath_parse;
11mod shared;
12
13use proc_macro::TokenStream;
14use syn::parse_macro_input;
15
16#[proc_macro_derive(Keyable)]
17pub fn derive_keyable(input: TokenStream) -> TokenStream {
18    let input = parse_macro_input!(input as syn::DeriveInput);
19    keyable::derive_keyable_impl(input)
20        .unwrap_or_else(|err| err.to_compile_error())
21        .into()
22}
23
24/// Create a strongly-typed `KeyPath`.
25///
26/// This verifies at compile-time that the path is valid.
27///
28/// This macro expects a *type name*, followed by one or more *path components*.
29/// Path components may be either *fields* or *indices*.
30///
31/// - field: a single '`.`' character, followed by either a valid identifier or
32///   a single unsized integer.
33/// - indicies: a pair of brackets (`[]`) containing either a string literal or
34///   an unsized integer.
35///
36/// Fields should correspond to named or unnamed fields on the base type.
37/// Indicies refer to members of collections.
38///
39/// # Examples
40///
41/// The following are *semantically* valid keypaths. (Their actual validity
42/// would depend on these fields existing in the underlying types.)
43///
44/// ```no_compile
45/// keypath!(Person.profile.name);
46/// keypath!(Element.size.0);
47/// keypath!(Person.friends[10].name);
48/// keypath!(Person.friends["常羽辰"].address);
49/// keypath!(Thing.field.0["friends"].count);
50/// keypath!(Thing.1[2][3].size.width);
51/// ```
52#[proc_macro]
53pub fn keypath(input: TokenStream) -> TokenStream {
54    match keypath::keypath_impl(input) {
55        Ok(expanded) => expanded,
56        Err(error) => error.into_compile_error(),
57    }
58}