Skip to content

Commit 7c680b7

Browse files
authored
Redesign derive_component to cgp_component with improved syntax (#38)
* Rename derive_component to cgp_component * Redesign syntax for cgp_component macro * Update tests * Add changelog
1 parent 106990f commit 7c680b7

File tree

13 files changed

+138
-28
lines changed

13 files changed

+138
-28
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33
## Pre-Release
44

5+
- Redesign `derive_component` to `cgp_component` with improved syntax - [#38](https://github.com/contextgeneric/cgp/pull/38)
6+
- Rename the attribute `#[derive_component]` to `#[cgp_component]`
7+
- The macro syntax has been changed as follows:
8+
- Old: `#[derive_component(NameGetterComponent, NameGetter<MyContext>)]`
9+
- New: `#[cgp_component { name: NameGetterComponent, context: MyContext, provider: NameGetter }]`
10+
- For migration, the following regex can be used in a global search and replace:
11+
- Search: `#\[derive_component\(([\w<>, ]+), (\w+)<(\w+)>\)\]`
12+
- Replace: `#[cgp_component {\n name: $1,\n provider: $2,\n context: $3,\n}]`
13+
514
- Support async-generic feature flags in cgp-async - [#37](https://github.com/contextgeneric/cgp/pull/37)
615
- Introduce the following feature flags to `cgp-async`:
716
- `async`

crates/cgp-component-macro-lib/src/derive_component/component_spec.rs

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
use proc_macro2::Span;
2+
use quote::ToTokens;
13
use syn::parse::{Parse, ParseStream};
24
use syn::punctuated::Punctuated;
35
use syn::token::{Comma, Gt, Lt};
4-
use syn::Ident;
6+
use syn::{Error, Ident};
7+
8+
use crate::derive_component::entry::Entries;
59

610
pub struct ComponentSpec {
711
pub provider_name: Ident,
@@ -10,7 +14,60 @@ pub struct ComponentSpec {
1014
pub component_params: Punctuated<Ident, Comma>,
1115
}
1216

17+
pub struct ComponentNameSpec {
18+
pub component_name: Ident,
19+
pub component_params: Punctuated<Ident, Comma>,
20+
}
21+
1322
impl Parse for ComponentSpec {
23+
fn parse(input: ParseStream) -> syn::Result<Self> {
24+
let Entries { entries } = input.parse()?;
25+
26+
let context_type: Ident = {
27+
let raw_context_type = entries.get(&Ident::new("context", Span::call_site()));
28+
29+
if let Some(context_type) = raw_context_type {
30+
syn::parse2(context_type.to_token_stream())?
31+
} else {
32+
Ident::new("Context", Span::call_site())
33+
}
34+
};
35+
36+
let provider_name: Ident = {
37+
let raw_provider_name = entries
38+
.get(&Ident::new("provider", Span::call_site()))
39+
.ok_or_else(|| Error::new(input.span(), "expect provider name to be given"))?;
40+
41+
syn::parse2(raw_provider_name.to_token_stream())?
42+
};
43+
44+
let (component_name, component_params) = {
45+
let raw_component_name = entries.get(&Ident::new("name", Span::call_site()));
46+
47+
if let Some(raw_component_name) = raw_component_name {
48+
let ComponentNameSpec {
49+
component_name,
50+
component_params,
51+
} = syn::parse2(raw_component_name.to_token_stream())?;
52+
(component_name, component_params)
53+
} else {
54+
(
55+
Ident::new(&format!("{}Component", provider_name), provider_name.span()),
56+
Punctuated::default(),
57+
)
58+
}
59+
};
60+
61+
Ok(ComponentSpec {
62+
component_name,
63+
provider_name,
64+
context_type,
65+
component_params,
66+
})
67+
}
68+
}
69+
70+
impl Parse for ComponentNameSpec {
1471
fn parse(input: ParseStream) -> syn::Result<Self> {
1572
let component_name: Ident = input.parse()?;
1673

@@ -27,20 +84,8 @@ impl Parse for ComponentSpec {
2784
Punctuated::default()
2885
};
2986

30-
let _: Comma = input.parse()?;
31-
32-
let provider_name: Ident = input.parse()?;
33-
34-
let _: Lt = input.parse()?;
35-
36-
let context_type: Ident = input.parse()?;
37-
38-
let _: Gt = input.parse()?;
39-
40-
Ok(ComponentSpec {
87+
Ok(Self {
4188
component_name,
42-
provider_name,
43-
context_type,
4489
component_params,
4590
})
4691
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use std::collections::BTreeMap;
2+
3+
use syn::parse::{Parse, ParseStream};
4+
use syn::punctuated::Punctuated;
5+
use syn::token::{Colon, Comma};
6+
use syn::{Ident, Type};
7+
8+
pub struct Entry {
9+
pub key: Ident,
10+
pub value: Type,
11+
}
12+
13+
impl Parse for Entry {
14+
fn parse(input: ParseStream) -> syn::Result<Self> {
15+
let key = input.parse()?;
16+
let _colon: Colon = input.parse()?;
17+
let value = input.parse()?;
18+
19+
Ok(Entry { key, value })
20+
}
21+
}
22+
23+
pub struct Entries {
24+
pub entries: BTreeMap<Ident, Type>,
25+
}
26+
27+
impl Parse for Entries {
28+
fn parse(input: ParseStream) -> syn::Result<Self> {
29+
let entry_list: Punctuated<Entry, Comma> = Punctuated::parse_terminated(input)?;
30+
31+
let entries =
32+
BTreeMap::from_iter(entry_list.into_iter().map(|entry| (entry.key, entry.value)));
33+
34+
Ok(Entries { entries })
35+
}
36+
}

crates/cgp-component-macro-lib/src/derive_component/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod consumer_impl;
44
pub mod delegate_fn;
55
pub mod delegate_type;
66
pub mod derive;
7+
pub mod entry;
78
pub mod provider_impl;
89
pub mod provider_trait;
910
pub mod replace_self_receiver;

crates/cgp-component-macro-lib/src/tests/derive_component.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use crate::tests::helper::equal::equal_token_stream;
66
#[test]
77
fn test_basic_derive_component() {
88
derive_component(
9-
quote! { FooComponent, FooProvider<Context> },
9+
quote! {
10+
name: FooComponent,
11+
provider: FooProvider,
12+
},
1013
quote! {
1114
pub trait HasFoo<Bar> {
1215
type Foo;
@@ -20,7 +23,10 @@ fn test_basic_derive_component() {
2023
#[test]
2124
fn test_derive_component_with_const_generic() {
2225
let derived = derive_component(
23-
quote! { FooComponent, FooProvider<Context> },
26+
quote! {
27+
name: FooComponent,
28+
provider: FooProvider,
29+
},
2430
quote! {
2531
pub trait HasFoo<const BAR: usize> {
2632
type Foo;

crates/cgp-component-macro/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ extern crate proc_macro;
77
use proc_macro::TokenStream;
88

99
#[proc_macro_attribute]
10-
pub fn derive_component(attr: TokenStream, item: TokenStream) -> TokenStream {
10+
pub fn cgp_component(attr: TokenStream, item: TokenStream) -> TokenStream {
1111
cgp_component_macro_lib::derive_component(attr.into(), item.into()).into()
1212
}
1313

crates/cgp-component/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
pub mod traits;
99
pub mod types;
1010

11-
pub use cgp_component_macro::{define_components, delegate_components, derive_component};
11+
pub use cgp_component_macro::{cgp_component, define_components, delegate_components};
1212
pub use traits::{DelegateComponent, HasComponents};
1313
pub use types::{UseContext, UseDelegate, WithContext, WithProvider};

crates/cgp-core/src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub use cgp_async::{async_trait, Async, MaybeSend, MaybeStatic, MaybeSync};
22
pub use cgp_component::{
3-
define_components, delegate_components, derive_component, DelegateComponent, HasComponents,
3+
cgp_component, define_components, delegate_components, DelegateComponent, HasComponents,
44
};
55
pub use cgp_error::{CanRaiseError, HasErrorType};
66
pub use cgp_field::{

crates/cgp-error/src/can_raise_error.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use cgp_component::{derive_component, DelegateComponent, HasComponents, UseDelegate};
1+
use cgp_component::{cgp_component, DelegateComponent, HasComponents, UseDelegate};
22

33
use crate::has_error_type::HasErrorType;
44

@@ -10,7 +10,9 @@ use crate::has_error_type::HasErrorType;
1010
[`err: ParseIntError`](core::num::ParseIntError) and get back
1111
a [`Context::Error`](HasErrorType::Error) value.
1212
*/
13-
#[derive_component(ErrorRaiserComponent, ErrorRaiser<Context>)]
13+
#[cgp_component {
14+
provider: ErrorRaiser
15+
}]
1416
pub trait CanRaiseError<E>: HasErrorType {
1517
fn raise_error(e: E) -> Self::Error;
1618
}

crates/cgp-error/src/has_error_type.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use core::fmt::Debug;
22

33
use cgp_async::Async;
4-
use cgp_component::{derive_component, DelegateComponent, HasComponents, WithProvider};
4+
use cgp_component::{cgp_component, DelegateComponent, HasComponents, WithProvider};
55
use cgp_type::traits::has_type::ProvideType;
66

77
/**
@@ -15,7 +15,10 @@ use cgp_type::traits::has_type::ProvideType;
1515
parent traits, so that multiple traits can all refer to the same abstract
1616
`Self::Error` type.
1717
*/
18-
#[derive_component(ErrorTypeComponent, ProvideErrorType<Context>)]
18+
#[cgp_component {
19+
name: ErrorTypeComponent,
20+
provider: ProvideErrorType,
21+
}]
1922
pub trait HasErrorType {
2023
/**
2124
The `Error` associated type is also required to implement [`Debug`].

0 commit comments

Comments
 (0)