Skip to content
5 changes: 3 additions & 2 deletions crates/cgp-core/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pub use cgp_field::types::{
pub use cgp_macro::{
BuildField, CgpData, CgpRecord, CgpVariant, ExtractField, FromVariant, HasField, HasFields,
Product, Sum, Symbol, cgp_auto_getter, cgp_component, cgp_fn, cgp_getter, cgp_impl,
cgp_inherit, cgp_new_provider, cgp_preset, cgp_provider, cgp_type, check_components,
delegate_and_check_components, delegate_components, product, re_export_imports, replace_with,
cgp_inherit, cgp_namespace, cgp_new_provider, cgp_preset, cgp_provider, cgp_type,
check_components, delegate_and_check_components, delegate_components, product,
re_export_imports, replace_with,
};
pub use cgp_type::{HasType, TypeProvider, UseType};
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
Expand Up @@ -12,7 +12,7 @@ use crate::traits::has_error_type::HasErrorType;
provider: ErrorRaiser,
derive_delegate: UseDelegate<SourceError>,
}]
#[use_namespace(cgp.core.error)]
#[use_namespace(@cgp.core.error.ErrorRaiserComponent)]
pub trait CanRaiseError<SourceError>: HasErrorType {
fn raise_error(error: SourceError) -> Self::Error;
}
2 changes: 2 additions & 0 deletions crates/cgp-error/src/traits/can_wrap_error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use cgp_component::*;
use cgp_field::types::*;
use cgp_macro::cgp_component;

use crate::traits::HasErrorType;
Expand All @@ -7,6 +8,7 @@ use crate::traits::HasErrorType;
provider: ErrorWrapper,
derive_delegate: UseDelegate<Detail>,
}]
#[use_namespace(@cgp.core.error.ErrorWrapperComponent)]
pub trait CanWrapError<Detail>: HasErrorType {
fn wrap_error(error: Self::Error, detail: Detail) -> Self::Error;
}
2 changes: 1 addition & 1 deletion crates/cgp-error/src/traits/has_error_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use cgp_type::{TypeProvider, UseType};
<https://patterns.contextgeneric.dev/error-handling.html>
*/
#[cgp_type]
#[use_namespace(cgp.core.error)]
#[use_namespace(@cgp.core.error.ErrorTypeProviderComponent)]
pub trait HasErrorType {
type Error: Debug;
}
Expand Down
19 changes: 15 additions & 4 deletions crates/cgp-macro-lib/src/attributes/use_namespace.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use syn::Ident;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::token::{Colon, Dot};
use syn::token::{At, Colon, Dot};
use syn::{Ident, Type, parse2};

use crate::parse::PathType;

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

impl Parse for UseNamespaceAttribute {
Expand All @@ -20,7 +21,17 @@ impl Parse for UseNamespaceAttribute {
Ident::new("DefaultNamespace", input.span())
};

let path = Punctuated::parse_separated_nonempty(input)?;
let _: At = input.parse()?;

let paths: Punctuated<PathType, Dot> = Punctuated::parse_separated_nonempty(input)?;

let raw_path_type = paths.into_iter().rev().fold(
quote!(PathNil),
|tail, PathType { path_type }| quote!(PathCons<#path_type, #tail>),
);

let path: Type = parse2(raw_path_type)?;

Ok(UseNamespaceAttribute { namespace, path })
}
}
1 change: 1 addition & 0 deletions crates/cgp-macro-lib/src/cgp_namespace/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod spec;
83 changes: 83 additions & 0 deletions crates/cgp-macro-lib/src/cgp_namespace/spec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::token::{At, Colon, Comma, Dot, Lt};
use syn::{Ident, Type, braced, parse2};

use crate::parse::{ComponentPath, ComponentPaths, ImplGenerics, PathType};

pub struct NamespaceSpec {
pub namespace_ident: Ident,
pub parent_namespace_ident: Option<Ident>,
pub entries: Punctuated<NamespaceEntry, Comma>,
}

pub struct NamespaceEntry {
pub keys: ComponentPaths,
pub value: Type,
}

impl Parse for NamespaceSpec {
fn parse(input: ParseStream) -> syn::Result<Self> {
let namespace_ident: Ident = input.parse()?;

let parent_namespace_ident: Option<Ident> = if input.peek(Colon) {
let _: Colon = input.parse()?;
let ident = input.parse()?;
Some(ident)
} else {
None
};

let content;
braced!(content in input);

let entries = Punctuated::parse_terminated(&content)?;

Ok(NamespaceSpec {
namespace_ident,
parent_namespace_ident,
entries,
})
}
}

impl Parse for NamespaceEntry {
fn parse(input: ParseStream) -> syn::Result<Self> {
let keys: ComponentPaths = if input.peek(At) {
let _: At = input.parse()?;

input.parse()?
} else {
let generics: ImplGenerics = if input.peek(Lt) {
input.parse()?
} else {
Default::default()
};

let path_type: Type = input.parse()?;

let path = ComponentPath {
generics,
path_type,
};

ComponentPaths { paths: vec![path] }
};

let _: Colon = input.parse()?;

let _: At = input.parse()?;

let value_path: Punctuated<PathType, Dot> = Punctuated::parse_separated_nonempty(input)?;

let value = value_path.into_iter().rev().fold(
quote!(PathNil),
|tail, PathType { path_type }| quote!( PathCons< #path_type, #tail > ),
);

let value: Type = parse2(value)?;

Ok(Self { keys, value })
}
}
21 changes: 3 additions & 18 deletions crates/cgp-macro-lib/src/derive_component/derive_namespace.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use quote::{ToTokens, quote};
use syn::{Ident, ItemImpl, Type, parse2};
use quote::quote;
use syn::{Ident, ItemImpl, parse2};

use crate::attributes::UseNamespaceAttribute;

Expand All @@ -21,10 +21,7 @@ pub fn derive_namespace_impl(
component_name: &Ident,
) -> syn::Result<ItemImpl> {
let namespace = &attribute.namespace;
let mut paths = Vec::from_iter(attribute.path.iter().map(|path| path.path_type.clone()));
paths.push(parse2(component_name.to_token_stream())?);

let path = path_to_product(&paths)?;
let path = &attribute.path;

let out = quote! {
impl<__Components__> #namespace < __Components__ > for #component_name
Expand All @@ -35,15 +32,3 @@ pub fn derive_namespace_impl(

parse2(out)
}

pub fn path_to_product(paths: &[Type]) -> syn::Result<Type> {
let mut out = quote! { PathNil };

for path in paths.iter().rev() {
out = quote! {
PathCons< #path , #out >
};
}

parse2(out)
}
82 changes: 82 additions & 0 deletions crates/cgp-macro-lib/src/entrypoints/cgp_namespace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Ident, ItemImpl, ItemStruct, ItemTrait, parse2};

use crate::cgp_namespace::spec::NamespaceSpec;

pub fn cgp_namespace(body: TokenStream) -> syn::Result<TokenStream> {
let spec: NamespaceSpec = parse2(body)?;

let mut out = TokenStream::new();

let namespace_ident = &spec.namespace_ident;

let namespace_trait: ItemTrait = parse2(quote! {
pub trait #namespace_ident< __Components__ > {
type Provider;
}
})?;

out.extend(quote! {
#namespace_trait
});

if let Some(parent_namespace_ident) = spec.parent_namespace_ident {
let namespace_struct_ident = Ident::new(
&format!("__{}Components", namespace_ident),
namespace_ident.span(),
);

let namespace_struct: ItemStruct = parse2(quote! {
pub struct #namespace_struct_ident;
})?;

let item_impl: ItemImpl = parse2(quote! {
impl<__Context__, __Components__, __Provider__>
#namespace_ident< __Components__ >
for __Context__
where
__Context__: #parent_namespace_ident< __Components__, Provider = __Provider__ >
+ #parent_namespace_ident< #namespace_struct_ident >,
{
type Provider = __Provider__;
}
})?;

out.extend(quote! {
#namespace_struct

#item_impl
})
}

for entry in spec.entries.into_iter() {
let value = entry.value;
for path in entry.keys.paths.into_iter() {
let path_type = path.path_type;

let mut generics = path.generics.generics;
generics.params.push(parse2(quote!(__Components__))?);

let impl_generics = generics.split_for_impl().0;

let item_impl: ItemImpl = parse2(quote! {
impl #impl_generics
#namespace_ident< __Components__ >
for #path_type
{
type Provider = RedirectLookup<
__Components__,
#value,
>;
}
})?;

out.extend(quote! {
#item_impl
})
}
}

Ok(out)
}
2 changes: 2 additions & 0 deletions crates/cgp-macro-lib/src/entrypoints/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod cgp_fn;
mod cgp_getter;
mod cgp_impl;
mod cgp_inherit;
mod cgp_namespace;
mod cgp_new_provider;
mod cgp_preset;
mod cgp_provider;
Expand All @@ -30,6 +31,7 @@ pub use cgp_fn::*;
pub use cgp_getter::*;
pub use cgp_impl::*;
pub use cgp_inherit::*;
pub use cgp_namespace::*;
pub use cgp_new_provider::*;
pub use cgp_preset::*;
pub use cgp_provider::*;
Expand Down
1 change: 1 addition & 0 deletions crates/cgp-macro-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub(crate) mod attributes;
pub(crate) mod blanket_trait;
pub(crate) mod cgp_fn;
pub(crate) mod cgp_impl;
pub(crate) mod cgp_namespace;
pub(crate) mod check_components;
pub(crate) mod delegate_components;
pub(crate) mod derive_builder;
Expand Down
Loading
Loading