Skip to main content

step_p21_derive/
lib.rs

1//! Procedural macros for second step code generation
2//!
3//! ```text
4//! ┌────────────────┐
5//! │ EXPRESS schema │
6//! └──┬─────────────┘
7//!    │ expressc
8//! ┌──▼─────────────────┐
9//! │ Abstract Rust code │
10//! └──┬─────────────────┘
11//!    │ step_p21-derive
12//! ┌──▼───────────────┐
13//! │ Actual Rust code │
14//! └──────────────────┘
15//! ```
16//!
17//! Design
18//! -------
19//! - [step_p11::codegen::rust](../step_p11/codegen/rust/index.html) generates
20//!   Rust code with proc-macros defined in this crate.
21//! - This crate does not depends on step_p11 explicitly.
22
23use proc_macro::TokenStream;
24use proc_macro_error2::{abort_call_site, proc_macro_error};
25use proc_macro2::TokenStream as TokenStream2;
26use quote::quote;
27use std::convert::*;
28
29mod common;
30mod entity;
31mod field_type;
32mod holder_attr;
33mod select;
34mod table_init;
35mod type_decl;
36
37use common::*;
38use field_type::*;
39use holder_attr::*;
40use table_init::*;
41
42/// Derive `TableInit` for tables
43///
44/// ```
45/// use std::collections::HashMap;
46/// use step_p21_derive::{Holder, TableInit, as_holder};
47///
48/// #[derive(TableInit, Default)]
49/// pub struct Table {
50///     a: HashMap<u64, as_holder!(A)>,
51///     b: HashMap<u64, as_holder!(B)>,
52/// }
53///
54/// #[derive(Debug, Clone, PartialEq, Holder)]
55/// #[holder(table = Table)]
56/// #[holder(field = a)]
57/// #[holder(generate_deserialize)]
58/// pub struct A {
59///     pub x: f64,
60///     pub y: f64,
61/// }
62///
63/// #[derive(Debug, Clone, PartialEq, Holder)]
64/// #[holder(table = Table)]
65/// #[holder(field = b)]
66/// #[holder(generate_deserialize)]
67/// pub struct B {
68///     pub z: f64,
69///     #[holder(use_place_holder)]
70///     pub a: A,
71/// }
72/// ```
73#[proc_macro_error]
74#[proc_macro_derive(TableInit)]
75pub fn derive_table_init_entry(input: TokenStream) -> TokenStream {
76    derive_table_init(&syn::parse(input).unwrap()).into()
77}
78
79/// Generate `impl Deserialize` for entity structs
80#[proc_macro_error]
81#[proc_macro_derive(Deserialize)]
82pub fn derive_deserialize_entry(input: TokenStream) -> TokenStream {
83    derive_deserialize(&syn::parse(input).unwrap()).into()
84}
85
86fn derive_deserialize(ast: &syn::DeriveInput) -> TokenStream2 {
87    let ident = &ast.ident;
88    match &ast.data {
89        syn::Data::Struct(st) => entity::derive_deserialize(ident, st),
90        syn::Data::Enum(e) => select::derive_deserialize(ident, e),
91        _ => abort_call_site!("Only struct is supprted currently"),
92    }
93}
94
95/// Generates `Holder` struct and related implementation for each `ENTITY`
96/// struct
97///
98/// `#[holder]` attribute
99/// ---------------------
100///
101/// There are three types of attributes:
102///
103/// ```ignore
104/// #[derive(Holder)]
105/// #[holder(table = Table)] // <- container attribute
106/// #[holder(field = b)]     // <- this is also a container attribute
107/// pub struct B {
108///     pub z: f64,
109///     #[holder(use_place_holder)] // <- field attribute
110///     pub a: A,
111/// }
112///
113/// #[derive(Holder)]
114/// #[holder(table = Table)] // <- container attribute
115/// pub enum S2 {
116///     #[holder(use_place_holder)] // <- this is also a variant attribute
117///     A(Box<A>),
118///     P(f64),
119/// }
120/// ```
121///
122/// - `#[holder(table = {path::to::table::struct})]`
123///   - This must be a container attribute
124///   - Specify a struct path which contains a table for this Holder
125/// - `#[holder(field = {field_ident})]`
126///   - This can be both in container or variant attribute
127///   - Identifier of table field
128/// - `#[holder(generate_deserialize)]`
129///   - This must be a container attribute
130///   - Flag for generating `impl Deserialize for XxxHolder`
131/// - `#[holder(use_place_holder)]`
132///   - This can be both in field or variant attribute
133///   - Specify the field is not a simple type
134#[proc_macro_error]
135#[proc_macro_derive(Holder, attributes(holder))]
136pub fn derive_holder_entry(input: TokenStream) -> TokenStream {
137    derive_holder(&syn::parse(input).unwrap()).into()
138}
139
140fn derive_holder(ast: &syn::DeriveInput) -> TokenStream2 {
141    let attr = HolderAttr::parse(&ast.attrs);
142    let ident = &ast.ident;
143    match &ast.data {
144        syn::Data::Struct(st) => match st.fields {
145            syn::Fields::Named(_) => entity::derive_holder(ident, st, &attr),
146            syn::Fields::Unnamed(_) => {
147                type_decl::derive_holder(ident, st, &attr)
148            }
149            syn::Fields::Unit => {
150                abort_call_site!("Unit struct is not supported.")
151            }
152        },
153        syn::Data::Enum(e) => select::derive_holder(ident, e, &attr),
154        _ => abort_call_site!("Only struct is supprted currently"),
155    }
156}
157
158/// Get `Holder` struct identifier from `ENTITY` struct identifier
159///
160/// - e.g. `as_holder!(A)` to `AHolder`
161#[proc_macro_error]
162#[proc_macro]
163pub fn as_holder(input: TokenStream) -> TokenStream {
164    let path = as_holder_path(&syn::parse(input).unwrap());
165    let ts = quote! { #path };
166    ts.into()
167}
168
169#[cfg(test)]
170mod snapshot_tests {
171    use super::derive_holder;
172
173    #[test]
174    fn derive_holder_enum() {
175        let input: syn::DeriveInput = syn::parse_str(
176            r#"
177            #[holder(table = Table)]
178            #[holder(generate_deserialize)]
179            pub enum S1 {
180                #[holder(use_place_holder)]
181                A(Box<A>),
182                #[holder(use_place_holder)]
183                B(Box<B>),
184            }
185            "#,
186        )
187        .unwrap();
188
189        let tt = derive_holder(&input);
190        let out = step_p11::codegen::rust::rustfmt(tt.to_string());
191
192        insta::assert_snapshot!(out, @r#"
193        #[doc = r" Auto-generated by `#[derive(Holder)]`"]
194        #[derive(Clone, Debug, PartialEq)]
195        pub enum S1Holder {
196            A(Box<AHolder>),
197            B(Box<BHolder>),
198        }
199        impl ::step_p21::tables::IntoOwned for S1Holder {
200            type Owned = S1;
201            type Table = Table;
202
203            fn into_owned(
204                self,
205                table: &Self::Table,
206            ) -> ::step_p21::error::Result<Self::Owned> {
207                Ok(match self {
208                    S1Holder::A(sub) => S1::A(Box::new(sub.into_owned(table)?)),
209                    S1Holder::B(sub) => S1::B(Box::new(sub.into_owned(table)?)),
210                })
211            }
212        }
213        impl ::step_p21::tables::Holder for S1Holder {
214            fn name() -> &'static str {
215                "S1"
216            }
217
218            fn attr_len() -> usize {
219                0
220            }
221        }
222        impl<'de> ::step_p21::serde::de::Deserialize<'de> for S1Holder {
223            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
224            where
225                D: ::step_p21::serde::de::Deserializer<'de>,
226            {
227                deserializer.deserialize_tuple_struct("S1", 0, S1HolderVisitor {})
228            }
229        }
230        #[doc(hidden)]
231        pub struct S1HolderVisitor;
232        impl<'de> ::step_p21::serde::de::Visitor<'de> for S1HolderVisitor {
233            type Value = S1Holder;
234
235            fn expecting(
236                &self,
237                formatter: &mut ::std::fmt::Formatter,
238            ) -> ::std::fmt::Result {
239                write!(formatter, "S1")
240            }
241
242            fn visit_map<A>(
243                self,
244                mut map: A,
245            ) -> ::std::result::Result<Self::Value, A::Error>
246            where
247                A: ::step_p21::serde::de::MapAccess<'de>,
248            {
249                let key: String = map
250                    .next_key()?
251                    .expect("Empty map cannot be accepted as step_p21 Holder");
252                match key.as_str() {
253                    "A" => {
254                        let owned = map.next_value()?;
255                        return Ok(S1Holder::A(Box::new(owned)));
256                    }
257                    "B" => {
258                        let owned = map.next_value()?;
259                        return Ok(S1Holder::B(Box::new(owned)));
260                    }
261                    _ => {
262                        use step_p21::serde::de::{Error, Unexpected};
263                        return Err(A::Error::invalid_value(
264                            Unexpected::Other(&key),
265                            &self,
266                        ));
267                    }
268                }
269            }
270        }
271        impl ::step_p21::tables::WithVisitor for S1Holder {
272            type Visitor = S1HolderVisitor;
273
274            fn visitor_new() -> Self::Visitor {
275                S1HolderVisitor {}
276            }
277        }
278        impl ::step_p21::tables::EntityTable<S1Holder> for Table {
279            fn get_owned(&self, entity_id: u64) -> ::step_p21::error::Result<S1> {
280                if let Ok(owned) = ::step_p21::tables::EntityTable::<AHolder>::get_owned(
281                    self, entity_id,
282                ) {
283                    return Ok(S1::A(Box::new(owned.into())));
284                }
285                if let Ok(owned) = ::step_p21::tables::EntityTable::<BHolder>::get_owned(
286                    self, entity_id,
287                ) {
288                    return Ok(S1::B(Box::new(owned.into())));
289                }
290                Err(::step_p21::error::Error::UnknownEntity(entity_id))
291            }
292
293            fn owned_iter<'table>(
294                &'table self,
295            ) -> Box<dyn Iterator<Item = ::step_p21::error::Result<S1>> + 'table> {
296                Box::new(::step_p21::itertools::chain![
297                    ::step_p21::tables::EntityTable::<AHolder>::owned_iter(self)
298                        .map(|owned| owned.map(|owned| S1::A(Box::new(owned.into())))),
299                    ::step_p21::tables::EntityTable::<BHolder>::owned_iter(self)
300                        .map(|owned| owned.map(|owned| S1::B(Box::new(owned.into()))))
301                ])
302            }
303        }
304        "#);
305    }
306
307    #[test]
308    fn derive_holder_enum_any_subsuper() {
309        let input: syn::DeriveInput = syn::parse_str(
310            r#"
311            # [holder (table = Tables)]
312            #[holder(generate_deserialize)]
313            pub enum BaseAny {
314                #[holder(use_place_holder)]
315                # [holder (field = base)]
316                Base(Box<Base>),
317                #[holder(use_place_holder)]
318                # [holder (field = sub)]
319                Sub(Box<SubAny>),
320            }
321            "#,
322        )
323        .unwrap();
324
325        let tt = derive_holder(&input);
326        let out = step_p11::codegen::rust::rustfmt(tt.to_string());
327
328        insta::assert_snapshot!(out, @r#"
329        #[doc = r" Auto-generated by `#[derive(Holder)]`"]
330        #[derive(Clone, Debug, PartialEq)]
331        pub enum BaseAnyHolder {
332            Base(Box<BaseHolder>),
333            Sub(Box<SubAnyHolder>),
334        }
335        impl ::step_p21::tables::IntoOwned for BaseAnyHolder {
336            type Owned = BaseAny;
337            type Table = Tables;
338
339            fn into_owned(
340                self,
341                table: &Self::Table,
342            ) -> ::step_p21::error::Result<Self::Owned> {
343                Ok(match self {
344                    BaseAnyHolder::Base(sub) => {
345                        BaseAny::Base(Box::new(sub.into_owned(table)?))
346                    }
347                    BaseAnyHolder::Sub(sub) => {
348                        BaseAny::Sub(Box::new(sub.into_owned(table)?))
349                    }
350                })
351            }
352        }
353        impl ::step_p21::tables::Holder for BaseAnyHolder {
354            fn name() -> &'static str {
355                "BASE_ANY"
356            }
357
358            fn attr_len() -> usize {
359                0
360            }
361        }
362        impl<'de> ::step_p21::serde::de::Deserialize<'de> for BaseAnyHolder {
363            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
364            where
365                D: ::step_p21::serde::de::Deserializer<'de>,
366            {
367                deserializer.deserialize_tuple_struct(
368                    "BASE_ANY",
369                    0,
370                    BaseAnyHolderVisitor {},
371                )
372            }
373        }
374        #[doc(hidden)]
375        pub struct BaseAnyHolderVisitor;
376        impl<'de> ::step_p21::serde::de::Visitor<'de> for BaseAnyHolderVisitor {
377            type Value = BaseAnyHolder;
378
379            fn expecting(
380                &self,
381                formatter: &mut ::std::fmt::Formatter,
382            ) -> ::std::fmt::Result {
383                write!(formatter, "BASE_ANY")
384            }
385
386            fn visit_map<A>(
387                self,
388                mut map: A,
389            ) -> ::std::result::Result<Self::Value, A::Error>
390            where
391                A: ::step_p21::serde::de::MapAccess<'de>,
392            {
393                let key: String = map
394                    .next_key()?
395                    .expect("Empty map cannot be accepted as step_p21 Holder");
396                match key.as_str() {
397                    "BASE" => {
398                        let owned = map.next_value()?;
399                        return Ok(BaseAnyHolder::Base(Box::new(owned)));
400                    }
401                    "SUB" => {
402                        let owned = map.next_value()?;
403                        return Ok(BaseAnyHolder::Sub(Box::new(owned)));
404                    }
405                    _ => {
406                        use step_p21::serde::de::{Error, Unexpected};
407                        return Err(A::Error::invalid_value(
408                            Unexpected::Other(&key),
409                            &self,
410                        ));
411                    }
412                }
413            }
414        }
415        impl ::step_p21::tables::WithVisitor for BaseAnyHolder {
416            type Visitor = BaseAnyHolderVisitor;
417
418            fn visitor_new() -> Self::Visitor {
419                BaseAnyHolderVisitor {}
420            }
421        }
422        impl ::step_p21::tables::EntityTable<BaseAnyHolder> for Tables {
423            fn get_owned(&self, entity_id: u64) -> ::step_p21::error::Result<BaseAny> {
424                if let Ok(owned) =
425                    ::step_p21::tables::EntityTable::<BaseHolder>::get_owned(
426                        self, entity_id,
427                    )
428                {
429                    return Ok(BaseAny::Base(Box::new(owned.into())));
430                }
431                if let Ok(owned) =
432                    ::step_p21::tables::EntityTable::<SubAnyHolder>::get_owned(
433                        self, entity_id,
434                    )
435                {
436                    return Ok(BaseAny::Sub(Box::new(owned.into())));
437                }
438                Err(::step_p21::error::Error::UnknownEntity(entity_id))
439            }
440
441            fn owned_iter<'table>(
442                &'table self,
443            ) -> Box<dyn Iterator<Item = ::step_p21::error::Result<BaseAny>> + 'table>
444            {
445                Box::new(::step_p21::itertools::chain![
446                    ::step_p21::tables::EntityTable::<BaseHolder>::owned_iter(self)
447                        .map(|owned| owned
448                            .map(|owned| BaseAny::Base(Box::new(owned.into())))),
449                    ::step_p21::tables::EntityTable::<SubAnyHolder>::owned_iter(self)
450                        .map(|owned| owned
451                            .map(|owned| BaseAny::Sub(Box::new(owned.into()))))
452                ])
453            }
454        }
455        "#);
456    }
457
458    #[test]
459    fn skip_unrelated_attributes() {
460        let input: syn::DeriveInput = syn::parse_str(
461            r#"
462            #[derive(
463                Debug, Clone, PartialEq, AsRef, AsMut, Deref, DerefMut, :: derive_new :: new, Holder,
464            )]
465            # [holder (table = Tables)]
466            # [holder (field = sub1)]
467            #[holder(generate_deserialize)]
468            pub struct Sub1 {
469                #[as_ref]
470                #[as_mut]
471                #[deref]
472                #[deref_mut]
473                #[holder(use_place_holder)]
474                pub base: Base,
475                pub y1: f64,
476            }
477            "#,
478        )
479        .unwrap();
480
481        let tt = derive_holder(&input);
482        let out = step_p11::codegen::rust::rustfmt(tt.to_string());
483
484        insta::assert_snapshot!(out, @r#"
485        #[doc = r" Auto-generated by `#[derive(Holder)]`"]
486        #[derive(Debug, Clone, PartialEq)]
487        pub struct Sub1Holder {
488            pub base: ::step_p21::tables::PlaceHolder<BaseHolder>,
489            pub y1: f64,
490        }
491        #[automatically_derived]
492        impl ::step_p21::tables::IntoOwned for Sub1Holder {
493            type Owned = Sub1;
494            type Table = Tables;
495
496            fn into_owned(
497                self,
498                table: &Self::Table,
499            ) -> ::step_p21::error::Result<Self::Owned> {
500                let Sub1Holder { base, y1 } = self;
501                Ok(Sub1 {
502                    base: base.into_owned(table)?,
503                    y1,
504                })
505            }
506        }
507        #[automatically_derived]
508        impl ::step_p21::tables::Holder for Sub1Holder {
509            fn name() -> &'static str {
510                "SUB_1"
511            }
512
513            fn attr_len() -> usize {
514                2usize
515            }
516        }
517        #[automatically_derived]
518        impl ::step_p21::tables::EntityTable<Sub1Holder> for Tables {
519            fn get_owned(&self, entity_id: u64) -> ::step_p21::error::Result<Sub1> {
520                ::step_p21::tables::get_owned(self, &self.sub1, entity_id)
521            }
522
523            fn owned_iter<'table>(
524                &'table self,
525            ) -> Box<dyn Iterator<Item = ::step_p21::error::Result<Sub1>> + 'table>
526            {
527                ::step_p21::tables::owned_iter(self, &self.sub1)
528            }
529        }
530        #[doc(hidden)]
531        pub struct Sub1HolderVisitor;
532        #[automatically_derived]
533        impl<'de> ::step_p21::serde::de::Visitor<'de> for Sub1HolderVisitor {
534            type Value = Sub1Holder;
535
536            fn expecting(
537                &self,
538                formatter: &mut ::std::fmt::Formatter,
539            ) -> ::std::fmt::Result {
540                write!(formatter, "SUB_1")
541            }
542
543            fn visit_seq<A>(
544                self,
545                mut seq: A,
546            ) -> ::std::result::Result<Self::Value, A::Error>
547            where
548                A: ::step_p21::serde::de::SeqAccess<'de>,
549            {
550                if let Some(size) = seq.size_hint() {
551                    if size != 2usize {
552                        use step_p21::serde::de::Error;
553                        return Err(A::Error::invalid_length(size, &self));
554                    }
555                }
556                let base = seq.next_element()?.unwrap();
557                let y1 = seq.next_element()?.unwrap();
558                Ok(Sub1Holder { base, y1 })
559            }
560
561            fn visit_map<A>(
562                self,
563                mut map: A,
564            ) -> ::std::result::Result<Self::Value, A::Error>
565            where
566                A: ::step_p21::serde::de::MapAccess<'de>,
567            {
568                let key: String = map
569                    .next_key()?
570                    .expect("Empty map cannot be accepted as step_p21 Holder");
571                if key != "SUB_1" {
572                    use step_p21::serde::de::{Error, Unexpected};
573                    return Err(A::Error::invalid_value(
574                        Unexpected::Other(&key),
575                        &self,
576                    ));
577                }
578                let value = map.next_value()?;
579                Ok(value)
580            }
581        }
582        #[automatically_derived]
583        impl<'de> ::step_p21::serde::de::Deserialize<'de> for Sub1Holder {
584            fn deserialize<D>(deserializer: D) -> ::std::result::Result<Self, D::Error>
585            where
586                D: ::step_p21::serde::de::Deserializer<'de>,
587            {
588                deserializer.deserialize_tuple_struct(
589                    "SUB_1",
590                    2usize,
591                    Sub1HolderVisitor {},
592                )
593            }
594        }
595        #[automatically_derived]
596        impl ::step_p21::tables::WithVisitor for Sub1Holder {
597            type Visitor = Sub1HolderVisitor;
598
599            fn visitor_new() -> Self::Visitor {
600                Sub1HolderVisitor {}
601            }
602        }
603        "#);
604    }
605}