Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
64a17e2
Experiment on UseNamespace and RedirectLookup
soareschen Mar 3, 2026
88353cc
More experiment
soareschen Mar 3, 2026
eacefb0
Simplify hierarchical namspace lookup with product type
soareschen Mar 3, 2026
9518c1f
More experiment on separator syntax
soareschen Mar 3, 2026
ace78b0
Remove Path from UseNamespace
soareschen Mar 3, 2026
108c2e6
Experiment on extended namespace
soareschen Mar 8, 2026
e0467bf
Experiment on overridding namespace path
soareschen Mar 8, 2026
bd4f5c9
More experiments
soareschen Mar 10, 2026
474adbc
Try expand lookup generics
soareschen Mar 10, 2026
7a6a692
RedirectLookup can now expand generics
soareschen Mar 10, 2026
1e3514c
Set provider directly in namespace
soareschen Mar 11, 2026
7f7dcb3
Add #[use_namespace] attribute
soareschen Mar 11, 2026
1618fb5
Implement derive_namespace_impls
soareschen Mar 11, 2026
35a169a
Use #[use_namespace] for HasErrorType
soareschen Mar 11, 2026
9cc550b
Refactoring derive_provider_impl
soareschen Mar 11, 2026
d6c52c6
Draft implement derive_redirect_lookup_impl
soareschen Mar 11, 2026
baaa8b8
Derive RedirectLookup in #[cgp_component]
soareschen Mar 11, 2026
8dfa03e
Move ExtendedNamespace
soareschen Mar 12, 2026
0b3f995
Experimenting with default provider
soareschen Mar 12, 2026
e04f87d
Allow namespace trait to be omitted
soareschen Mar 12, 2026
72702bd
Draft implement component path parsing
soareschen Mar 12, 2026
81bc70b
Use namespace path syntax
soareschen Mar 12, 2026
60cfd23
Test wildcard
soareschen Mar 12, 2026
7a91a13
Use separate PathCons type to allow unsized head
soareschen Mar 12, 2026
158f94e
Move back AppendProduct
soareschen Mar 12, 2026
f31df0b
Convert lowercase namespace ident to symbol
soareschen Mar 16, 2026
b40daa8
Add symbol_from_string_spanned
soareschen Mar 16, 2026
08f41a3
Use path symbol in #[use_namespace]
soareschen Mar 16, 2026
bb5d9a8
Remove obsolete constructs
soareschen Mar 16, 2026
2d46298
Rename CgpNamespace to DefaultNamespace
soareschen Mar 16, 2026
948a636
Use #[use_namespace] in foobar example
soareschen Mar 16, 2026
3ecdaa2
Accept attributes in delegate_components!
soareschen Mar 16, 2026
98b05e6
Implement parse_delegate_attributes
soareschen Mar 16, 2026
4dd1a79
Derive #[use_namespace]
soareschen Mar 16, 2026
108255f
Add derive_namespace_delegate helper
soareschen Mar 16, 2026
e887d94
Implement multi-path ComponentPath type
soareschen Mar 18, 2026
d268b55
Propagate wildcard info
soareschen Mar 18, 2026
34f20be
Use new path in single mode
soareschen Mar 18, 2026
e4471e0
Parse multi-path in DelegateEntry
soareschen Mar 18, 2026
8e74734
Remove path parsing in DelegateKey
soareschen Mar 18, 2026
4773240
Pass generics directly
soareschen Mar 18, 2026
29e03c3
Disallow empty path
soareschen Mar 19, 2026
0da56dd
Allow generic parameters to be specified in path
soareschen Mar 19, 2026
3d6a433
Add prepend path helper
soareschen Mar 19, 2026
f42554d
Fix clippy
soareschen Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion crates/cgp-component/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@
CGP component implementation.
*/

mod namespaces;
mod traits;
mod types;

pub use namespaces::DefaultNamespace;
pub use traits::{CanUseComponent, DelegateComponent, IsProviderFor};
pub use types::{UseContext, UseDelegate, UseFields, WithContext, WithProvider};
pub use types::{
ConcatPath, PathCons, PathNil, RedirectLookup, UseContext, UseDefault, UseDelegate, UseFields,
WithContext, WithProvider,
};
3 changes: 3 additions & 0 deletions crates/cgp-component/src/namespaces.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub trait DefaultNamespace<Components> {
type Provider;
}
6 changes: 6 additions & 0 deletions crates/cgp-component/src/types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
mod path;
mod redirect_lookup;
mod use_context;
mod use_default;
mod use_delegate;
mod use_fields;
mod with_provider;

pub use path::{ConcatPath, PathCons, PathNil};
pub use redirect_lookup::RedirectLookup;
pub use use_context::{UseContext, WithContext};
pub use use_default::UseDefault;
pub use use_delegate::UseDelegate;
pub use use_fields::UseFields;
pub use with_provider::WithProvider;
20 changes: 20 additions & 0 deletions crates/cgp-component/src/types/path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use core::marker::PhantomData;

pub struct PathCons<Head: ?Sized, Tail: ?Sized>(pub PhantomData<Head>, pub PhantomData<Tail>);

pub struct PathNil;

pub trait ConcatPath<Other: ?Sized> {
type Output: ?Sized;
}

impl<Head: ?Sized, Tail: ?Sized, Other: ?Sized> ConcatPath<Other> for PathCons<Head, Tail>
where
Tail: ConcatPath<Other>,
{
type Output = PathCons<Head, <Tail as ConcatPath<Other>>::Output>;
}

impl<Other: ?Sized> ConcatPath<Other> for PathNil {
type Output = Other;
}
3 changes: 3 additions & 0 deletions crates/cgp-component/src/types/redirect_lookup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use core::marker::PhantomData;

pub struct RedirectLookup<Key, Components>(pub PhantomData<(Key, Components)>);
1 change: 1 addition & 0 deletions crates/cgp-component/src/types/use_default.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct UseDefault;
4 changes: 2 additions & 2 deletions crates/cgp-core/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ pub use core::marker::PhantomData;

pub use cgp_async_macro::async_trait;
pub use cgp_component::{
CanUseComponent, DelegateComponent, IsProviderFor, UseContext, UseDelegate, UseFields,
WithContext, WithProvider,
CanUseComponent, ConcatPath, DefaultNamespace, DelegateComponent, IsProviderFor, PathCons,
PathNil, RedirectLookup, UseContext, UseDelegate, UseFields, WithContext, WithProvider,
};
pub use cgp_error::{CanRaiseError, CanWrapError, HasErrorType};
pub use cgp_field::impls::{IsMut, IsNothing, IsPresent, IsRef, IsVoid, UseField};
Expand Down
1 change: 1 addition & 0 deletions crates/cgp-error/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ description = """
cgp-component = { workspace = true }
cgp-macro = { workspace = true }
cgp-type = { workspace = true }
cgp-field = { workspace = true }
2 changes: 1 addition & 1 deletion crates/cgp-error/src/traits/can_raise_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cgp_component::{DelegateComponent, IsProviderFor, UseContext, UseDelegate};
use cgp_component::*;
use cgp_macro::cgp_component;

use crate::traits::has_error_type::HasErrorType;
Expand Down
2 changes: 1 addition & 1 deletion crates/cgp-error/src/traits/can_wrap_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use cgp_component::{DelegateComponent, IsProviderFor, UseContext, UseDelegate};
use cgp_component::*;
use cgp_macro::cgp_component;

use crate::traits::HasErrorType;
Expand Down
7 changes: 6 additions & 1 deletion crates/cgp-error/src/traits/has_error_type.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
use core::fmt::Debug;

use cgp_component::{DelegateComponent, IsProviderFor, UseContext, WithProvider};
use cgp_component::{
DefaultNamespace, DelegateComponent, IsProviderFor, PathCons, PathNil, RedirectLookup,
UseContext, WithProvider,
};
use cgp_field::types::*;
use cgp_macro::cgp_type;
use cgp_type::{TypeProvider, UseType};

Expand All @@ -24,6 +28,7 @@ use cgp_type::{TypeProvider, UseType};
<https://patterns.contextgeneric.dev/error-handling.html>
*/
#[cgp_type]
#[use_namespace(cgp.core.error)]
pub trait HasErrorType {
type Error: Debug;
}
Expand Down
16 changes: 16 additions & 0 deletions crates/cgp-field/src/traits/append_product.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::types::{Cons, Nil};

pub trait AppendProduct<Item: ?Sized> {
type Output;
}

impl<Item> AppendProduct<Item> for Nil {
type Output = Cons<Item, Nil>;
}

impl<Head, Tail, Item> AppendProduct<Item> for Cons<Head, Tail>
where
Tail: AppendProduct<Item>,
{
type Output = Cons<Head, Tail::Output>;
}
16 changes: 16 additions & 0 deletions crates/cgp-field/src/traits/concat_product.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use crate::types::{Cons, Nil};

pub trait ConcatProduct<Items> {
type Output;
}

impl<Items> ConcatProduct<Items> for Nil {
type Output = Items;
}

impl<Head, Tail, Items> ConcatProduct<Items> for Cons<Head, Tail>
where
Tail: ConcatProduct<Items>,
{
type Output = Cons<Head, Tail::Output>;
}
4 changes: 4 additions & 0 deletions crates/cgp-field/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod append_product;
mod build_field;
mod concat_product;
mod extract_field;
mod from_fields;
mod from_variant;
Expand All @@ -18,7 +20,9 @@ mod to_fields;
mod transform_map;
mod update_field;

pub use append_product::*;
pub use build_field::*;
pub use concat_product::*;
pub use extract_field::*;
pub use from_fields::*;
pub use from_variant::*;
Expand Down
3 changes: 3 additions & 0 deletions crates/cgp-macro-lib/src/attributes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mod use_namespace;

pub use use_namespace::*;
26 changes: 26 additions & 0 deletions crates/cgp-macro-lib/src/attributes/use_namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use syn::Ident;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::token::{Colon, Dot};

use crate::parse::PathType;

pub struct UseNamespaceAttribute {
pub namespace: Ident,
pub path: Punctuated<PathType, Dot>,
}

impl Parse for UseNamespaceAttribute {
fn parse(input: ParseStream) -> syn::Result<Self> {
let namespace = if input.peek2(Colon) {
let namespace = input.parse()?;
let _: Colon = input.parse()?;
namespace
} else {
Ident::new("DefaultNamespace", input.span())
};

let path = Punctuated::parse_separated_nonempty(input)?;
Ok(UseNamespaceAttribute { namespace, path })
}
}
2 changes: 1 addition & 1 deletion crates/cgp-macro-lib/src/cgp_fn/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub fn build_implicit_args_bounds(
let mut constraints: Punctuated<TypeParamBound, Plus> = Punctuated::new();

for arg in implicit_args {
let field_symbol = symbol_from_string(&arg.field_name.to_string());
let field_symbol = symbol_from_string(&arg.field_name.to_string())?;

let constraint = derive_getter_constraint(
&arg.field_type,
Expand Down
2 changes: 1 addition & 1 deletion crates/cgp-macro-lib/src/cgp_fn/fn_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn inject_implicit_arg(arg: &ImplicitArgField, body: &mut Block) -> syn::Res
let field_name = &arg.field_name;
let arg_type = &arg.arg_type;

let field_symbol = symbol_from_string(&field_name.to_string());
let field_symbol = symbol_from_string(&field_name.to_string())?;

let call_expr = if arg.field_mut.is_none() {
quote! {
Expand Down
48 changes: 48 additions & 0 deletions crates/cgp-macro-lib/src/delegate_components/attributes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use syn::{Attribute, Ident, Meta};

pub fn parse_delegate_attributes(attributes: Vec<Attribute>) -> syn::Result<DelegateAttributes> {
let mut parsed_attributes = DelegateAttributes::default();

for attribute in attributes.iter() {
if let Some(ident) = attribute.path().get_ident() {
if ident == "use_namespace" {
if parsed_attributes.use_namespace.is_some() {
return Err(syn::Error::new_spanned(
attribute,
"Multiple #[use_namespace] attributes are not allowed",
));
}

if let Meta::Path(_) = attribute.meta {
parsed_attributes.use_namespace =
Some(DelegateNamespaceAttribute { namespace: None });
} else {
let namespace = attribute.parse_args::<Option<Ident>>()?;
parsed_attributes.use_namespace =
Some(DelegateNamespaceAttribute { namespace });
}
} else {
return Err(syn::Error::new_spanned(
attribute,
format!("Unknown attribute {} for delegate_components", ident),
));
}
} else {
return Err(syn::Error::new_spanned(
attribute,
"Unexpected attribute format for delegate_components",
));
}
}

Ok(parsed_attributes)
}

#[derive(Default)]
pub struct DelegateAttributes {
pub use_namespace: Option<DelegateNamespaceAttribute>,
}

pub struct DelegateNamespaceAttribute {
pub namespace: Option<Ident>,
}
49 changes: 49 additions & 0 deletions crates/cgp-macro-lib/src/delegate_components/derive_namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::{Generics, Ident, Type, parse2};

pub fn derive_namespace_delegate(
namespace: Option<Ident>,
target_type: &Type,
target_generics: &Generics,
) -> syn::Result<TokenStream> {
let namespace = namespace.unwrap_or_else(|| Ident::new("DefaultNamespace", Span::call_site()));

let mut generics = target_generics.clone();
generics.params.push(parse2(quote! { __Component__ })?);

let impl_generics = generics.split_for_impl().0;

let namespace_impl = quote! {
impl #impl_generics
DelegateComponent<__Component__>
for #target_type
where
__Component__: #namespace< #target_type >,
{
type Delegate = < __Component__ as #namespace< #target_type >>::Provider;
}
};

let mut generics = generics.clone();
generics.params.push(parse2(quote! { __Context__ })?);
generics.params.push(parse2(quote! { __Params__ })?);

let impl_generics = generics.split_for_impl().0;

let is_provider_for_impl = quote! {
impl #impl_generics
IsProviderFor<__Component__, __Context__, __Params__>
for #target_type
where
__Component__: #namespace< #target_type >,
< __Component__ as #namespace< #target_type >>::Provider: IsProviderFor<__Component__, __Context__, __Params__>,
{
}
};

Ok(quote! {
#namespace_impl
#is_provider_for_impl
})
}
4 changes: 4 additions & 0 deletions crates/cgp-macro-lib/src/delegate_components/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
mod attributes;
mod define_struct;
mod derive_namespace;
mod impl_delegate;
mod merge_generics;

pub use attributes::*;
pub use define_struct::*;
pub use derive_namespace::*;
pub use impl_delegate::*;
2 changes: 1 addition & 1 deletion crates/cgp-macro-lib/src/derive_builder/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn field_to_member(index: usize, field: &Field) -> Member {

pub fn field_to_tag(index: usize, field: &Field) -> syn::Result<Type> {
match &field.ident {
Some(ident) => Ok(symbol_from_string(&ident.to_string())),
Some(ident) => symbol_from_string(&ident.to_string()),
None => {
let index = LitInt::new(&format!("{index}"), field.span());
parse2(quote! { δ< #index > })
Expand Down
7 changes: 7 additions & 0 deletions crates/cgp-macro-lib/src/derive_component/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use syn::punctuated::Punctuated;
use syn::token::Comma;
use syn::{Attribute, TypeParamBound};

use crate::attributes::UseNamespaceAttribute;
use crate::cgp_fn::UseTypeSpec;

pub fn parse_component_attributes(
Expand Down Expand Up @@ -35,6 +36,11 @@ pub fn parse_component_attributes(
}

parsed_attributes.use_type.extend(use_type_specs);
} else if ident == "use_namespace" {
let use_namespace_specs = attribute.parse_args_with(
Punctuated::<UseNamespaceAttribute, Comma>::parse_terminated,
)?;
parsed_attributes.use_namespace.extend(use_namespace_specs);
} else {
attributes.push(attribute);
}
Expand All @@ -50,4 +56,5 @@ pub fn parse_component_attributes(
pub struct ComponentAttributes {
pub extend: Vec<TypeParamBound>,
pub use_type: Vec<UseTypeSpec>,
pub use_namespace: Vec<UseNamespaceAttribute>,
}
Loading
Loading