diff --git a/Cargo.lock b/Cargo.lock index 293dceca..2fa9c205 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,6 +46,14 @@ dependencies = [ "cgp-macro", ] +[[package]] +name = "cgp-base-extra" +version = "0.7.0" +dependencies = [ + "cgp-base", + "cgp-type", +] + [[package]] name = "cgp-base-types" version = "0.7.0" @@ -80,7 +88,7 @@ dependencies = [ name = "cgp-error" version = "0.7.0" dependencies = [ - "cgp-base", + "cgp-base-extra", "cgp-field", "cgp-macro", "cgp-type", diff --git a/Cargo.toml b/Cargo.toml index 8fe89c64..7a3f0b0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ resolver = "3" members = [ "crates/main/cgp", "crates/main/cgp-base", + "crates/main/cgp-base-extra", "crates/main/cgp-core", "crates/main/cgp-extra", @@ -50,6 +51,7 @@ keywords = ["cgp"] [workspace.dependencies] cgp = { version = "0.7.0", path = "./crates/main/cgp" } cgp-base = { version = "0.7.0", path = "./crates/main/cgp-base" } +cgp-base-extra = { version = "0.7.0", path = "./crates/main/cgp-base-extra" } cgp-core = { version = "0.7.0", path = "./crates/main/cgp-core" } cgp-extra = { version = "0.7.0", path = "./crates/main/cgp-extra" } diff --git a/crates/core/cgp-base-types/src/lib.rs b/crates/core/cgp-base-types/src/lib.rs index b59e7464..592301f5 100644 --- a/crates/core/cgp-base-types/src/lib.rs +++ b/crates/core/cgp-base-types/src/lib.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - pub mod macro_prelude; pub mod traits; pub mod types; diff --git a/crates/core/cgp-base-types/src/types/chars.rs b/crates/core/cgp-base-types/src/types/chars.rs index e8751c08..9e31f744 100644 --- a/crates/core/cgp-base-types/src/types/chars.rs +++ b/crates/core/cgp-base-types/src/types/chars.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use crate::traits::StaticFormat; /** - The `Chars` type, a.k.a. `ζ`, is used to represent _type-level_ list of + The `Chars` type is used to represent _type-level_ list of `Chars`s, which are equivalent to type-level strings. `Chars` is a specialized version of [`Cons`](crate::types::Cons), with the @@ -13,11 +13,6 @@ use crate::traits::StaticFormat; expected to be either the next `Chars`, or [`Nil`](crate::types::Nil) to represent the end of the string. - Instead of reusing `Cons`, we combine the use of `Cons` within `Chars` so - that its representation is more compact when shown in compiler error messages. - Similar to `Cons`, `Chars` is also shown as `ζ` to further improve its - readability. - We represent type-level strings as list of `Chars`s, because it is currently not possible to use types like `String` or `&str` as const-generic parameters. On the other hand, a single `Chars` can be used as a const-generic parameter, @@ -40,17 +35,9 @@ use crate::traits::StaticFormat; ```rust,ignore type Hello = Chars<'h', Chars<'e', Chars<'l', Chars<'l', Chars<'o', Nil>>>>>; ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - type Hello = ζ<'h', ζ<'e', ζ<'l', ζ<'l', ζ<'o', ε>>>>>; - ``` */ #[derive(Eq, PartialEq, Clone, Copy, Default)] -pub struct ζ(pub PhantomData); - -pub use ζ as Chars; +pub struct Chars(pub PhantomData); impl Display for Chars where diff --git a/crates/core/cgp-base-types/src/types/cons.rs b/crates/core/cgp-base-types/src/types/cons.rs index 315c3f39..92543c28 100644 --- a/crates/core/cgp-base-types/src/types/cons.rs +++ b/crates/core/cgp-base-types/src/types/cons.rs @@ -1,15 +1,10 @@ /** - The `Cons` type, a.k.a. `π`, is used to represent the head of a _type-level list_, + The `Cons` type is used to represent the head of a _type-level list_, also known as an _anonymous product type_. `Cons` is used together with [`Nil`] to produce a type-level list using the `Product!` macro. - `Cons` is also shown as `π`, together with [`Nil`] shown as `ε`, to improve the - readability of compiler error messages. Through the shortened name, a product - type would take slightly less space, making it more likely to fit on a single - line for the user to read what the type is. - ## Example Given the following product type definition: @@ -23,15 +18,6 @@ ```rust,ignore type MyTypes = Cons>>; ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - type MyTypes = π>>; - ``` */ #[derive(Eq, PartialEq, Clone, Default, Debug)] -#[allow(non_camel_case_types)] -pub struct π(pub Head, pub Tail); - -pub use π as Cons; +pub struct Cons(pub Head, pub Tail); diff --git a/crates/core/cgp-base-types/src/types/nil.rs b/crates/core/cgp-base-types/src/types/nil.rs index 9f6ee60d..a132ba41 100644 --- a/crates/core/cgp-base-types/src/types/nil.rs +++ b/crates/core/cgp-base-types/src/types/nil.rs @@ -1,5 +1,5 @@ /** - The `Nil` type, a.k.a. `ε`, is used to represent the end of a _type-level list_, + The `Nil` type is used to represent the end of a _type-level list_, or an empty type-level list. `Nil` is commonly used as the `Tail` of a [`Cons`] type, to terminate the list. @@ -8,7 +8,4 @@ Read more about type-level lists, a.k.a. the product types, in [`Cons`]. */ #[derive(Eq, PartialEq, Clone, Default, Debug)] -#[allow(non_camel_case_types)] -pub struct ε; - -pub use ε as Nil; +pub struct Nil; diff --git a/crates/core/cgp-base-types/src/types/symbol.rs b/crates/core/cgp-base-types/src/types/symbol.rs index 22fd8705..7b88158a 100644 --- a/crates/core/cgp-base-types/src/types/symbol.rs +++ b/crates/core/cgp-base-types/src/types/symbol.rs @@ -1,9 +1,7 @@ use core::fmt::Display; use core::marker::PhantomData; -pub struct ψ(pub PhantomData); - -pub use ψ as Symbol; +pub struct Symbol(pub PhantomData); use crate::traits::StaticFormat; diff --git a/crates/core/cgp-error/Cargo.toml b/crates/core/cgp-error/Cargo.toml index 52093733..b3411256 100644 --- a/crates/core/cgp-error/Cargo.toml +++ b/crates/core/cgp-error/Cargo.toml @@ -9,7 +9,7 @@ rust-version = { workspace = true } keywords = { workspace = true } [dependencies] -cgp = { version = "0.7.0", path = "../../main/cgp-base", package = "cgp-base" } +cgp = { version = "0.7.0", path = "../../main/cgp-base-extra", package = "cgp-base-extra" } cgp-macro = { workspace = true } cgp-type = { workspace = true } cgp-field = { workspace = true } diff --git a/crates/core/cgp-error/src/traits/can_raise_error.rs b/crates/core/cgp-error/src/traits/can_raise_error.rs index 0717eaa4..ea91d7aa 100644 --- a/crates/core/cgp-error/src/traits/can_raise_error.rs +++ b/crates/core/cgp-error/src/traits/can_raise_error.rs @@ -1,4 +1,4 @@ -use cgp::macro_prelude::*; +use cgp::component::{DefaultNamespace, UseDelegate}; use cgp_macro::cgp_component; use crate::traits::has_error_type::HasErrorType; diff --git a/crates/core/cgp-error/src/traits/can_wrap_error.rs b/crates/core/cgp-error/src/traits/can_wrap_error.rs index 745f6bef..f32321a4 100644 --- a/crates/core/cgp-error/src/traits/can_wrap_error.rs +++ b/crates/core/cgp-error/src/traits/can_wrap_error.rs @@ -1,4 +1,4 @@ -use cgp::macro_prelude::*; +use cgp::component::{DefaultNamespace, UseDelegate}; use cgp_macro::cgp_component; use crate::traits::HasErrorType; diff --git a/crates/core/cgp-error/src/traits/has_error_type.rs b/crates/core/cgp-error/src/traits/has_error_type.rs index 7907f5da..a1e7f357 100644 --- a/crates/core/cgp-error/src/traits/has_error_type.rs +++ b/crates/core/cgp-error/src/traits/has_error_type.rs @@ -1,8 +1,7 @@ use core::fmt::Debug; -use cgp::macro_prelude::*; +use cgp::component::DefaultNamespace; use cgp_macro::cgp_type; -use cgp_type::{TypeProvider, UseType}; /** The `HasErrorType` trait provides an abstract error type that can be used by diff --git a/crates/core/cgp-field/src/lib.rs b/crates/core/cgp-field/src/lib.rs index a03b7ce0..e4988ac9 100644 --- a/crates/core/cgp-field/src/lib.rs +++ b/crates/core/cgp-field/src/lib.rs @@ -1,6 +1,4 @@ #![no_std] -#![allow(mixed_script_confusables)] -#![allow(non_camel_case_types)] pub mod impls; pub mod traits; diff --git a/crates/core/cgp-field/src/types/field.rs b/crates/core/cgp-field/src/types/field.rs index ca4ddca2..09238186 100644 --- a/crates/core/cgp-field/src/types/field.rs +++ b/crates/core/cgp-field/src/types/field.rs @@ -2,7 +2,7 @@ use core::fmt::Debug; use core::marker::PhantomData; /** - The `Field` type, a.k.a. `ω`, is used to represent a _named_ field entry + The `Field` type is used to represent a _named_ field entry within a product type or a sum type. `Field` is parameterized by a phantom `Tag` type, which is used to represent @@ -14,11 +14,6 @@ use core::marker::PhantomData; implementations, to include the field name in the generic product or sum representation of the given struct or enum. - `Field` is also shown as `ω` to improve the readability of compiler error - messages. It is mainly useful when the type from `HasFields::Fields` is shown, - which would contain a lot of `Field`s and tend to take up a lot of screen space - to read. - ## Example Given the following struct definition: @@ -38,25 +33,12 @@ use core::marker::PhantomData; type Fields = Product![Field, Field]; } ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - impl HasFields for MyContext { - type Fields = - π<ω, - π<ω, - ε>>; - } - ``` */ -pub struct ω { +pub struct Field { pub value: Value, pub phantom: PhantomData, } -pub use ω as Field; - impl From for Field { fn from(value: Value) -> Self { Self { diff --git a/crates/core/cgp-field/src/types/index.rs b/crates/core/cgp-field/src/types/index.rs index 3a5096ff..d8d46219 100644 --- a/crates/core/cgp-field/src/types/index.rs +++ b/crates/core/cgp-field/src/types/index.rs @@ -1,16 +1,13 @@ use core::fmt::{Debug, Display}; /** - The `Index` type, a.k.a. `δ`, is used to represent a `usize` value at + The `Index` type is used to represent a `usize` value at the _type level_. `Index` is simply defined to be parameterized by a _const-generic_ value of type `usize`. It is most often used to access generic fields by their _index_, instead of by their _name_. - `Index` is also shown as `δ` to improve the readability of compiler error - messages. - ## Example Given the following struct definition: @@ -32,9 +29,7 @@ use core::fmt::{Debug, Display}; } */ #[derive(Eq, PartialEq, Clone, Copy, Default)] -pub struct δ; - -pub use δ as Index; +pub struct Index; impl Display for Index { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { diff --git a/crates/core/cgp-field/src/types/sum.rs b/crates/core/cgp-field/src/types/sum.rs index 3aab93f5..f2511c8b 100644 --- a/crates/core/cgp-field/src/types/sum.rs +++ b/crates/core/cgp-field/src/types/sum.rs @@ -1,16 +1,11 @@ /** - The `Either` type, a.k.a. `σ`, is used to represent an _anonymous sum type_. + The `Either` type is used to represent an _anonymous sum type_. Similar to [`Cons`](crate::types::Cons), `Either` is used to form a sum type by combining a chain of `Either` types, and terminated with a [`Void`] type. But unlike product types, a sum type has values that belong to one of the variants in the list. - `Either` is also shown as `σ`, together with [`Void`] shown as `θ`, to improve - the readability of compiler error messages. Through the shortened name, a sum - type would take slightly less space, making it more likely to fit on a single - line for the user to read what the type is. - `Either` is most often used through the `Sum!` macro, which accepts a list of types and turns them into a chain of `Either` types. @@ -27,21 +22,15 @@ ```rust,ignore type MyUnion = Either>>; ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - type MyUnion = σ>>; - ``` */ #[derive(Eq, PartialEq, Debug, Clone)] -pub enum σ { +pub enum Either { Left(Head), Right(Tail), } /** - The `Void` type, a.k.a. `θ`, is used to represent the end of an _anonymous sum type_, + The `Void` type is used to represent the end of an _anonymous sum type_, or an _empty_ sum type. `Void` is commonly used as the `Tail` of a [`Either`] type, to terminate the list. @@ -57,7 +46,4 @@ pub enum σ { Read more about sum types in [`Either`]. */ #[derive(Eq, PartialEq, Debug, Clone)] -pub enum θ {} - -pub use θ as Void; -pub use σ as Either; +pub enum Void {} diff --git a/crates/macros/cgp-macro-core/src/exports.rs b/crates/macros/cgp-macro-core/src/exports.rs index 1bd2ae8e..35a81199 100644 --- a/crates/macros/cgp-macro-core/src/exports.rs +++ b/crates/macros/cgp-macro-core/src/exports.rs @@ -3,17 +3,51 @@ use crate::export_constructs; export_constructs! { Nil, Cons, + Void, + Either, Chars, Symbol, Index, + Field, PathCons, ConcatPath, RedirectLookup, DelegateComponent, IsProviderFor, CanUseComponent, - HasField, - HasFieldMut, UseContext, + UseType, + TypeProvider, + WithProvider, + UseFields, + UseField, Life, + + HasField, + HasFields, + HasFieldsRef, + HasFieldMut, + FieldGetter, + MutFieldGetter, + FromFields, + FromVariant, + HasBuilder, + HasExtractor, + HasExtractorRef, + HasExtractorMut, + ExtractField, + IntoBuilder, + UpdateField, + ToFields, + ToFieldsRef, + FinalizeBuild, + FinalizeExtract, + PartialData, + IsPresent, + IsNothing, + IsVoid, + IsRef, + IsMut, + MapType, + MapTypeRef, } diff --git a/crates/macros/cgp-macro-core/src/lib.rs b/crates/macros/cgp-macro-core/src/lib.rs index 7ac9a313..694d7518 100644 --- a/crates/macros/cgp-macro-core/src/lib.rs +++ b/crates/macros/cgp-macro-core/src/lib.rs @@ -1,5 +1,3 @@ -#![allow(mixed_script_confusables)] - pub mod exports; pub mod functions; pub mod macros; diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/builder_struct.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/builder_struct.rs similarity index 78% rename from crates/macros/cgp-macro-lib/src/derive_builder/builder_struct.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/builder_struct.rs index c260a799..e6bb01c9 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/builder_struct.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/builder_struct.rs @@ -1,13 +1,16 @@ use quote::quote; use syn::{GenericParam, Ident, ItemStruct, Type, TypeParam, parse2}; -use crate::derive_builder::index_to_generic_ident; +use crate::exports::MapType; +use crate::types::cgp_data::index_to_generic_ident; pub fn derive_builder_struct( context_struct: &ItemStruct, builder_ident: &Ident, ) -> syn::Result { let mut builder_struct = context_struct.clone(); + + builder_struct.attrs.clear(); builder_struct.ident = builder_ident.clone(); let generics = &mut builder_struct.generics; @@ -16,7 +19,7 @@ pub fn derive_builder_struct( let generic_param_name = index_to_generic_ident(i); let generic_param: TypeParam = parse2(quote! { - #generic_param_name : MapType + #generic_param_name : #MapType })?; generics.params.push(GenericParam::Type(generic_param)); @@ -24,7 +27,7 @@ pub fn derive_builder_struct( let field_type = &field.ty; let mapped_type: Type = parse2(quote! { - <#generic_param_name as MapType>::Map<#field_type> + <#generic_param_name as #MapType>::Map<#field_type> })?; field.ty = mapped_type; diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/finalize_build_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/finalize_build_impl.rs similarity index 85% rename from crates/macros/cgp-macro-lib/src/derive_builder/finalize_build_impl.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/finalize_build_impl.rs index feb50e86..9b01e6d6 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/finalize_build_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/finalize_build_impl.rs @@ -3,7 +3,8 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{FieldValue, Ident, ItemImpl, ItemStruct, Type, parse2}; -use crate::derive_builder::{field_to_member, field_value_expr, to_generic_args}; +use crate::exports::{FinalizeBuild, IsPresent}; +use crate::types::cgp_data::{field_to_member, field_value_expr, to_generic_args}; pub fn derive_finalize_build_impl( context_struct: &ItemStruct, @@ -18,7 +19,7 @@ pub fn derive_finalize_build_impl( for (i, field) in context_struct.fields.iter().enumerate() { generic_args.args.push(parse2(quote! { - IsPresent + #IsPresent })?); let field_member = field_to_member(i, field); @@ -36,7 +37,7 @@ pub fn derive_finalize_build_impl( })?; let item_impl = parse2(quote! { - impl #impl_generics FinalizeBuild for #builder_type + impl #impl_generics #FinalizeBuild for #builder_type #where_clause { fn finalize_build(self) -> Self::Target { diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/has_builder_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/has_builder_impl.rs similarity index 86% rename from crates/macros/cgp-macro-lib/src/derive_builder/has_builder_impl.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/has_builder_impl.rs index 07e92ccd..c0476d36 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/has_builder_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/has_builder_impl.rs @@ -3,7 +3,8 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{FieldValue, Ident, ItemImpl, ItemStruct, parse2}; -use crate::derive_builder::{field_to_member, field_value_expr, to_generic_args}; +use crate::exports::{HasBuilder, IsNothing}; +use crate::types::cgp_data::{field_to_member, field_value_expr, to_generic_args}; pub fn derive_has_builder_impl( context_struct: &ItemStruct, @@ -19,7 +20,7 @@ pub fn derive_has_builder_impl( for (i, field) in context_struct.fields.iter().enumerate() { builder_generics.args.push(parse2(quote! { - IsNothing + #IsNothing })?); let field_member = field_to_member(i, field); @@ -28,7 +29,7 @@ pub fn derive_has_builder_impl( } let item_impl = parse2(quote! { - impl #impl_generics HasBuilder + impl #impl_generics #HasBuilder for #context_ident #ty_generics #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/has_field_impls.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/has_field_impls.rs similarity index 89% rename from crates/macros/cgp-macro-lib/src/derive_builder/has_field_impls.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/has_field_impls.rs index f35cc11b..38f4a1f2 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/has_field_impls.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/has_field_impls.rs @@ -1,7 +1,8 @@ use quote::quote; use syn::{Ident, ItemImpl, ItemStruct, parse2}; -use crate::derive_builder::{ +use crate::exports::{HasField, IsPresent, MapType}; +use crate::types::cgp_data::{ field_to_member, field_to_tag, index_to_generic_ident, to_generic_args, }; @@ -15,7 +16,7 @@ pub fn derive_has_field_impls( for (current_index, current_field) in context_struct.fields.iter().enumerate() { let field_member = field_to_member(current_index, current_field); - let tag_type = field_to_tag(current_index, current_field)?; + let tag_type = field_to_tag(current_index, current_field); let value_type = ¤t_field.ty; let mut generics = context_struct.generics.clone(); @@ -26,7 +27,7 @@ pub fn derive_has_field_impls( let generic_param_name = index_to_generic_ident(other_index); generics.params.push(parse2(quote! { - #generic_param_name: MapType + #generic_param_name: #MapType })?); source_generic_args.push(parse2(quote! { @@ -34,7 +35,7 @@ pub fn derive_has_field_impls( })?); } else { source_generic_args.push(parse2(quote! { - IsPresent + #IsPresent })?); } } @@ -42,7 +43,7 @@ pub fn derive_has_field_impls( let (impl_generics, _, where_clause) = generics.split_for_impl(); let item_impl = parse2(quote! { - impl #impl_generics HasField< #tag_type > + impl #impl_generics #HasField< #tag_type > for #builder_ident < #source_generic_args > #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/into_builder_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/into_builder_impl.rs similarity index 86% rename from crates/macros/cgp-macro-lib/src/derive_builder/into_builder_impl.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/into_builder_impl.rs index dbc9b139..1aa7d6a7 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/into_builder_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/into_builder_impl.rs @@ -3,7 +3,8 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{FieldValue, Ident, ItemImpl, ItemStruct, parse2}; -use crate::derive_builder::{field_to_member, field_value_expr, to_generic_args}; +use crate::exports::{IntoBuilder, IsPresent}; +use crate::types::cgp_data::{field_to_member, field_value_expr, to_generic_args}; pub fn derive_into_builder_impl( context_struct: &ItemStruct, @@ -19,7 +20,7 @@ pub fn derive_into_builder_impl( for (i, field) in context_struct.fields.iter().enumerate() { builder_generics.args.push(parse2(quote! { - IsPresent + #IsPresent })?); let field_member = field_to_member(i, field); @@ -31,7 +32,7 @@ pub fn derive_into_builder_impl( } let item_impl = parse2(quote! { - impl #impl_generics IntoBuilder + impl #impl_generics #IntoBuilder for #context_ident #ty_generics #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/mod.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/mod.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/derive_builder/mod.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/mod.rs diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/partial_data.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/partial_data.rs similarity index 78% rename from crates/macros/cgp-macro-lib/src/derive_builder/partial_data.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/partial_data.rs index 41be3349..a1b85f99 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/partial_data.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/partial_data.rs @@ -1,9 +1,10 @@ use quote::quote; use syn::{Ident, ItemImpl, ItemStruct, parse2}; -use crate::derive_builder::index_to_generic_ident; +use crate::exports::{MapType, PartialData}; +use crate::types::cgp_data::index_to_generic_ident; -pub fn derive_partial_data_impl( +pub fn derive_partial_data_impl_from_struct( context_struct: &ItemStruct, builder_ident: &Ident, ) -> syn::Result { @@ -13,7 +14,7 @@ pub fn derive_partial_data_impl( let generic_param_name = index_to_generic_ident(index); generics.params.push(parse2(quote! { - #generic_param_name: MapType + #generic_param_name: #MapType })?); } @@ -23,7 +24,7 @@ pub fn derive_partial_data_impl( let context_generics = context_struct.generics.split_for_impl().1; let item_impl = parse2(quote! { - impl #impl_generics PartialData + impl #impl_generics #PartialData for #builder_ident #type_generics #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/update_field_impls.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/update_field_impls.rs similarity index 92% rename from crates/macros/cgp-macro-lib/src/derive_builder/update_field_impls.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/update_field_impls.rs index 91fb0a3e..778c93c9 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/update_field_impls.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/update_field_impls.rs @@ -3,7 +3,8 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{FieldValue, GenericArgument, Ident, ItemImpl, ItemStruct, Type, parse2}; -use crate::derive_builder::{ +use crate::exports::{MapType, UpdateField}; +use crate::types::cgp_data::{ field_to_member, field_to_tag, field_value_expr, index_to_generic_ident, to_generic_args, }; @@ -30,7 +31,7 @@ pub fn derive_update_field_impls( let generic_param_name = index_to_generic_ident(other_index); generics.params.push(parse2(quote! { - #generic_param_name: MapType + #generic_param_name: #MapType })?); let generic_arg: GenericArgument = parse2(quote! { #generic_param_name })?; @@ -46,11 +47,11 @@ pub fn derive_update_field_impls( output_generic_args.push(parse2(quote! { __M2__ })?); generics.params.push(parse2(quote! { - __M1__: MapType + __M1__: #MapType })?); generics.params.push(parse2(quote! { - __M2__: MapType + __M2__: #MapType })?); builder_fields.push(field_value_expr(field_member, quote! { value })?); @@ -65,14 +66,14 @@ pub fn derive_update_field_impls( #builder_ident < #output_generic_args > })?; - let tag_type = field_to_tag(current_index, current_field)?; + let tag_type = field_to_tag(current_index, current_field); let (impl_generics, _, where_clause) = generics.split_for_impl(); let member = field_to_member(current_index, current_field); let item_impl = parse2(quote! { - impl #impl_generics UpdateField< #tag_type, __M2__ > + impl #impl_generics #UpdateField< #tag_type, __M2__ > for #source_type #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_builder/utils.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/utils.rs similarity index 69% rename from crates/macros/cgp-macro-lib/src/derive_builder/utils.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/utils.rs index 07f86f90..45d19841 100644 --- a/crates/macros/cgp-macro-lib/src/derive_builder/utils.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_builder/utils.rs @@ -2,12 +2,9 @@ use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::token::Colon; -use syn::{ - AngleBracketedGenericArguments, Field, FieldValue, Generics, Ident, LitInt, Member, Type, - parse2, -}; +use syn::{AngleBracketedGenericArguments, Field, FieldValue, Generics, Ident, Member, parse2}; -use crate::symbol::symbol_from_string; +use crate::types::field::{FieldName, Index, Symbol}; pub fn to_generic_args(generics: &Generics) -> syn::Result { if generics.params.is_empty() { @@ -24,13 +21,13 @@ pub fn field_to_member(index: usize, field: &Field) -> Member { } } -pub fn field_to_tag(index: usize, field: &Field) -> syn::Result { +pub fn field_to_tag(index: usize, field: &Field) -> FieldName { match &field.ident { - Some(ident) => symbol_from_string(&ident.to_string()), - None => { - let index = LitInt::new(&format!("{index}"), field.span()); - parse2(quote! { δ< #index > }) - } + Some(ident) => FieldName::Ident(Symbol::from_ident(ident.clone())), + None => FieldName::Index(Index { + index, + span: field.span(), + }), } } diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/extract_field_impls.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/extract_field_impls.rs similarity index 82% rename from crates/macros/cgp-macro-lib/src/derive_extractor/extract_field_impls.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/extract_field_impls.rs index ccb941aa..9d2e9369 100644 --- a/crates/macros/cgp-macro-lib/src/derive_extractor/extract_field_impls.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/extract_field_impls.rs @@ -1,9 +1,9 @@ use quote::quote; use syn::{Arm, GenericArgument, Ident, ItemEnum, ItemImpl, Type, parse2}; -use crate::derive_builder::{index_to_generic_ident, to_generic_args}; -use crate::derive_extractor::get_variant_type; -use crate::symbol::symbol_from_string; +use crate::exports::{ExtractField, IsPresent, IsVoid, MapType, MapTypeRef}; +use crate::types::cgp_data::{get_variant_type, index_to_generic_ident, to_generic_args}; +use crate::types::field::Symbol; pub fn derive_extract_field_impls( context_enum: &ItemEnum, @@ -26,7 +26,7 @@ pub fn derive_extract_field_impls( generics.params.insert( 1, parse2(quote! { - __R__: MapTypeRef + __R__: #MapTypeRef })?, ); } @@ -49,7 +49,7 @@ pub fn derive_extract_field_impls( let generic_param_name = index_to_generic_ident(other_index); generics.params.push(parse2(quote! { - #generic_param_name: MapType + #generic_param_name: #MapType })?); let generic_arg: GenericArgument = parse2(quote! { #generic_param_name })?; @@ -62,8 +62,8 @@ pub fn derive_extract_field_impls( } })?); } else { - source_generic_args.push(parse2(quote! { IsPresent })?); - output_generic_args.push(parse2(quote! { IsVoid })?); + source_generic_args.push(parse2(quote! { #IsPresent })?); + output_generic_args.push(parse2(quote! { #IsVoid })?); match_arms.push(parse2(quote! { #extractor_ident :: #variant_ident ( value ) => { @@ -77,13 +77,13 @@ pub fn derive_extract_field_impls( let value_type = get_variant_type(current_variant)?; if is_ref { - parse2(quote! { <__R__ as MapTypeRef>::Map<'__a__, #value_type> })? + parse2(quote! { <__R__ as #MapTypeRef>::Map<'__a__, #value_type> })? } else { value_type.clone() } }; - let tag_type = symbol_from_string(¤t_variant.ident.to_string())?; + let tag_type = Symbol::from_ident(current_variant.ident.clone()); let source_type: Type = parse2(quote! { #extractor_ident < #source_generic_args > @@ -96,7 +96,7 @@ pub fn derive_extract_field_impls( let (impl_generics, _, where_clause) = generics.split_for_impl(); let item_impl = parse2(quote! { - impl #impl_generics ExtractField< #tag_type > + impl #impl_generics #ExtractField< #tag_type > for #source_type #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/extractor_enum.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/extractor_enum.rs similarity index 82% rename from crates/macros/cgp-macro-lib/src/derive_extractor/extractor_enum.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/extractor_enum.rs index 2e44c92c..625c660e 100644 --- a/crates/macros/cgp-macro-lib/src/derive_extractor/extractor_enum.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/extractor_enum.rs @@ -2,8 +2,8 @@ use proc_macro2::Span; use quote::quote; use syn::{GenericParam, Ident, ItemEnum, Lifetime, LifetimeParam, Type, TypeParam, parse2}; -use crate::derive_builder::index_to_generic_ident; -use crate::derive_extractor::{get_variant_type, type_to_variant_fields}; +use crate::exports::{MapType, MapTypeRef}; +use crate::types::cgp_data::{get_variant_type, index_to_generic_ident, type_to_variant_fields}; pub fn derive_extractor_enum( context_enum: &ItemEnum, @@ -11,6 +11,8 @@ pub fn derive_extractor_enum( ) -> syn::Result { let mut extractor_enum = context_enum.clone(); + extractor_enum.attrs.clear(); + extractor_enum.ident = extractor_ident.clone(); let generics = &mut extractor_enum.generics; @@ -19,7 +21,7 @@ pub fn derive_extractor_enum( let generic_param_name = index_to_generic_ident(i); let generic_param: TypeParam = parse2(quote! { - #generic_param_name : MapType + #generic_param_name : #MapType })?; generics.params.push(GenericParam::Type(generic_param)); @@ -27,7 +29,7 @@ pub fn derive_extractor_enum( let field_type = get_variant_type(variant)?; let mapped_type: Type = parse2(quote! { - <#generic_param_name as MapType>::Map<#field_type> + <#generic_param_name as #MapType>::Map<#field_type> })?; variant.fields = type_to_variant_fields(&mapped_type); @@ -42,6 +44,8 @@ pub fn derive_extractor_enum_ref( ) -> syn::Result { let mut extractor_enum = context_enum.clone(); + extractor_enum.attrs.clear(); + extractor_enum.ident = extractor_ident.clone(); let generics = &mut extractor_enum.generics; @@ -75,7 +79,7 @@ pub fn derive_extractor_enum_ref( generics.params.insert( 1, parse2(quote! { - __R__: MapTypeRef + __R__: #MapTypeRef })?, ); @@ -83,7 +87,7 @@ pub fn derive_extractor_enum_ref( let generic_param_name = index_to_generic_ident(i); let generic_param: TypeParam = parse2(quote! { - #generic_param_name : MapType + #generic_param_name : #MapType })?; generics.params.push(GenericParam::Type(generic_param)); @@ -91,8 +95,8 @@ pub fn derive_extractor_enum_ref( let field_type = get_variant_type(variant)?; let mapped_type: Type = parse2(quote! { - <#generic_param_name as MapType>::Map< - <__R__ as MapTypeRef>::Map<'__a__ , #field_type > + <#generic_param_name as #MapType>::Map< + <__R__ as #MapTypeRef>::Map<'__a__ , #field_type > > })?; diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/finalize_extract_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/finalize_extract_impl.rs similarity index 83% rename from crates/macros/cgp-macro-lib/src/derive_extractor/finalize_extract_impl.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/finalize_extract_impl.rs index ff72b386..968bc69f 100644 --- a/crates/macros/cgp-macro-lib/src/derive_extractor/finalize_extract_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/finalize_extract_impl.rs @@ -1,7 +1,8 @@ use quote::quote; use syn::{Ident, ItemEnum, ItemImpl, Type, parse2}; -use crate::derive_builder::to_generic_args; +use crate::exports::{FinalizeExtract, IsVoid, MapTypeRef}; +use crate::types::cgp_data::to_generic_args; pub fn derive_finalize_extract_impl( context_enum: &ItemEnum, @@ -22,7 +23,7 @@ pub fn derive_finalize_extract_impl( generics.params.insert( 0, parse2(quote! { - __R__: MapTypeRef + __R__: #MapTypeRef })?, ); } @@ -34,7 +35,7 @@ pub fn derive_finalize_extract_impl( for _variant in context_enum.variants.iter() { generic_args.args.push(parse2(quote! { - IsVoid + #IsVoid })?); } @@ -45,7 +46,7 @@ pub fn derive_finalize_extract_impl( })?; let item_impl = parse2(quote! { - impl #impl_generics FinalizeExtract for #extractor_type + impl #impl_generics #FinalizeExtract for #extractor_type #where_clause { fn finalize_extract<__T__>(self) -> __T__ { diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/has_extractor_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/has_extractor_impl.rs similarity index 91% rename from crates/macros/cgp-macro-lib/src/derive_extractor/has_extractor_impl.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/has_extractor_impl.rs index 97417ed5..a53300bf 100644 --- a/crates/macros/cgp-macro-lib/src/derive_extractor/has_extractor_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/has_extractor_impl.rs @@ -1,7 +1,8 @@ use quote::quote; use syn::{Arm, Ident, ItemEnum, ItemImpl, parse2}; -use crate::derive_builder::to_generic_args; +use crate::exports::{HasExtractor, HasExtractorMut, HasExtractorRef, IsMut, IsPresent, IsRef}; +use crate::types::cgp_data::to_generic_args; pub fn derive_has_extractor_impl( context_enum: &ItemEnum, @@ -19,7 +20,7 @@ pub fn derive_has_extractor_impl( for variant in context_enum.variants.iter() { extractor_generics.args.push(parse2(quote! { - IsPresent + #IsPresent })?); let variant_ident = &variant.ident; @@ -38,7 +39,7 @@ pub fn derive_has_extractor_impl( } let item_impl = parse2(quote! { - impl #impl_generics HasExtractor + impl #impl_generics #HasExtractor for #context_ident #ty_generics #where_clause { @@ -80,7 +81,7 @@ pub fn derive_has_extractor_ref_impl( extractor_generics.args.insert( 1, parse2(quote! { - IsRef + #IsRef })?, ); @@ -88,7 +89,7 @@ pub fn derive_has_extractor_ref_impl( for variant in context_enum.variants.iter() { extractor_generics.args.push(parse2(quote! { - IsPresent + #IsPresent })?); let variant_ident = &variant.ident; @@ -101,7 +102,7 @@ pub fn derive_has_extractor_ref_impl( } let item_impl = parse2(quote! { - impl #impl_generics HasExtractorRef + impl #impl_generics #HasExtractorRef for #context_ident #ty_generics #where_clause { @@ -139,7 +140,7 @@ pub fn derive_has_extractor_mut_impl( extractor_generics.args.insert( 1, parse2(quote! { - IsMut + #IsMut })?, ); @@ -147,7 +148,7 @@ pub fn derive_has_extractor_mut_impl( for variant in context_enum.variants.iter() { extractor_generics.args.push(parse2(quote! { - IsPresent + #IsPresent })?); let variant_ident = &variant.ident; @@ -160,7 +161,7 @@ pub fn derive_has_extractor_mut_impl( } let item_impl = parse2(quote! { - impl #impl_generics HasExtractorMut + impl #impl_generics #HasExtractorMut for #context_ident #ty_generics #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/mod.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/mod.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/derive_extractor/mod.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/mod.rs diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/partial_data.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/partial_data.rs similarity index 80% rename from crates/macros/cgp-macro-lib/src/derive_extractor/partial_data.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/partial_data.rs index f5140b7b..1db83a25 100644 --- a/crates/macros/cgp-macro-lib/src/derive_extractor/partial_data.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/partial_data.rs @@ -1,9 +1,10 @@ use quote::quote; use syn::{Ident, ItemEnum, ItemImpl, parse2}; -use crate::derive_builder::index_to_generic_ident; +use crate::exports::{MapType, MapTypeRef, PartialData}; +use crate::types::cgp_data::index_to_generic_ident; -pub fn derive_partial_data_impl( +pub fn derive_partial_data_impl_from_enum( context_struct: &ItemEnum, builder_ident: &Ident, is_ref: bool, @@ -21,7 +22,7 @@ pub fn derive_partial_data_impl( generics.params.insert( 0, parse2(quote! { - __R__: MapTypeRef + __R__: #MapTypeRef })?, ); } @@ -30,7 +31,7 @@ pub fn derive_partial_data_impl( let generic_param_name = index_to_generic_ident(index); generics.params.push(parse2(quote! { - #generic_param_name: MapType + #generic_param_name: #MapType })?); } @@ -40,7 +41,7 @@ pub fn derive_partial_data_impl( let context_generics = context_struct.generics.split_for_impl().1; let item_impl = parse2(quote! { - impl #impl_generics PartialData + impl #impl_generics #PartialData for #builder_ident #type_generics #where_clause { diff --git a/crates/macros/cgp-macro-lib/src/derive_extractor/utils.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/utils.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/derive_extractor/utils.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_extractor/utils.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/derive_from_variant.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs similarity index 52% rename from crates/macros/cgp-macro-lib/src/entrypoints/derive_from_variant.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs index ffcf6bce..0891e853 100644 --- a/crates/macros/cgp-macro-lib/src/entrypoints/derive_from_variant.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_from_variant.rs @@ -1,17 +1,11 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{ItemEnum, ItemImpl, parse2}; +use syn::{ItemEnum, ItemImpl}; -use crate::derive_extractor::get_variant_type; -use crate::symbol::symbol_from_string; +use crate::exports::FromVariant; +use crate::parse_internal; +use crate::types::cgp_data::get_variant_type; +use crate::types::field::Symbol; -pub fn derive_from_variant(body: TokenStream) -> syn::Result { - let item_enum: ItemEnum = parse2(body)?; - - derive_from_variant_from_enum(&item_enum) -} - -pub fn derive_from_variant_from_enum(item_enum: &ItemEnum) -> syn::Result { +pub fn derive_from_variant_from_enum(item_enum: &ItemEnum) -> syn::Result> { let enum_ident = &item_enum.ident; let (impl_generics, ty_generics, where_clause) = item_enum.generics.split_for_impl(); @@ -20,11 +14,11 @@ pub fn derive_from_variant_from_enum(item_enum: &ItemEnum) -> syn::Result for #enum_ident #ty_generics + let item_impl: ItemImpl = parse_internal! { + impl #impl_generics #FromVariant<#variant_tag> for #enum_ident #ty_generics #where_clause { type Value = #variant_type; @@ -33,14 +27,10 @@ pub fn derive_from_variant_from_enum(item_enum: &ItemEnum) -> syn::Result syn::Result> { let struct_ident = &item_struct.ident; @@ -20,12 +17,12 @@ pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> syn::Resu for field in fields.named.iter() { let field_ident = field.ident.as_ref().unwrap(); - let field_symbol = symbol_from_string(&field_ident.to_string())?; + let field_symbol = Symbol::from_ident(field_ident.clone()); let field_type = &field.ty; - let has_field_impl: ItemImpl = parse_quote! { - impl #impl_generics HasField< #field_symbol > + let has_field_impl: ItemImpl = parse_internal! { + impl #impl_generics #HasField< #field_symbol > for #struct_ident #ty_generics #where_clause { @@ -41,8 +38,8 @@ pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> syn::Resu } }; - let has_field_mut_impl: ItemImpl = parse_quote! { - impl #impl_generics HasFieldMut< #field_symbol > + let has_field_mut_impl: ItemImpl = parse_internal! { + impl #impl_generics #HasFieldMut< #field_symbol > for #struct_ident #ty_generics #where_clause { @@ -62,13 +59,17 @@ pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> syn::Resu } Fields::Unnamed(fields) => { for (i, field) in fields.unnamed.iter().enumerate() { + let field_tag = Index { + index: i, + span: field.span(), + }; + let field_ident = LitInt::new(&format!("{i}"), field.span()); - let field_symbol = quote! { δ< #field_ident > }; let field_type = &field.ty; - let has_field_impl: ItemImpl = parse_quote! { - impl #impl_generics HasField< #field_symbol > + let has_field_impl: ItemImpl = parse_internal! { + impl #impl_generics #HasField< #field_tag > for #struct_ident #ty_generics #where_clause { @@ -76,7 +77,7 @@ pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> syn::Resu fn get_field( &self, - key: ::core::marker::PhantomData< #field_symbol >, + key: ::core::marker::PhantomData< #field_tag >, ) -> &Self::Value { &self. #field_ident @@ -84,14 +85,14 @@ pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> syn::Resu } }; - let has_field_mut_impl: ItemImpl = parse_quote! { - impl #impl_generics HasFieldMut< #field_symbol > + let has_field_mut_impl: ItemImpl = parse_internal! { + impl #impl_generics #HasFieldMut< #field_tag > for #struct_ident #ty_generics #where_clause { fn get_field_mut( &mut self, - key: ::core::marker::PhantomData< #field_symbol >, + key: ::core::marker::PhantomData< #field_tag >, ) -> &mut Self::Value { &mut self. #field_ident @@ -108,13 +109,3 @@ pub fn derive_has_field_impls_from_struct(item_struct: &ItemStruct) -> syn::Resu Ok(item_impls) } - -pub fn derive_has_field(input: TokenStream) -> syn::Result { - let item_struct: ItemStruct = syn::parse2(input)?; - - let item_impls = derive_has_field_impls_from_struct(&item_struct)?; - - Ok(quote! { - #( #item_impls )* - }) -} diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/derive_enum.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/derive_enum.rs similarity index 76% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/derive_enum.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/derive_enum.rs index 61600c6a..3d495b81 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/derive_enum.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/derive_enum.rs @@ -2,10 +2,11 @@ use proc_macro2::TokenStream; use quote::quote; use syn::{ItemEnum, ItemImpl, parse2}; -use crate::derive_has_fields::from_fields_enum::derive_from_fields_for_enum; -use crate::derive_has_fields::sum::variants_to_sum_type; -use crate::derive_has_fields::to_fields_enum::derive_to_fields_for_enum; -use crate::derive_has_fields::to_fields_ref_enum::derive_to_fields_ref_for_enum; +use crate::exports::{HasFields, HasFieldsRef}; +use crate::types::cgp_data::{ + derive_from_fields_for_enum, derive_to_fields_for_enum, derive_to_fields_ref_for_enum, + variants_to_sum_type, +}; pub fn derive_has_fields_impls_from_enum(item_enum: &ItemEnum) -> syn::Result> { let struct_name = &item_enum.ident; @@ -18,7 +19,7 @@ pub fn derive_has_fields_impls_from_enum(item_enum: &ItemEnum) -> syn::Result syn::Result = #sum_type_ref diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/derive_struct.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/derive_struct.rs similarity index 76% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/derive_struct.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/derive_struct.rs index a33b60f0..cd4c125a 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/derive_struct.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/derive_struct.rs @@ -2,10 +2,11 @@ use proc_macro2::TokenStream; use quote::quote; use syn::{ItemImpl, ItemStruct, parse2}; -use crate::derive_has_fields::from_fields_struct::derive_from_fields_for_struct; -use crate::derive_has_fields::product::item_fields_to_product_type; -use crate::derive_has_fields::to_fields_ref_struct::derive_to_fields_ref_for_struct; -use crate::derive_has_fields::to_fields_struct::derive_to_fields_for_struct; +use crate::exports::{HasFields, HasFieldsRef}; +use crate::types::cgp_data::{ + derive_from_fields_for_struct, derive_to_fields_for_struct, derive_to_fields_ref_for_struct, + item_fields_to_product_type, +}; pub fn derive_has_fields_impls_from_struct(item_struct: &ItemStruct) -> syn::Result> { let struct_name = &item_struct.ident; @@ -19,7 +20,7 @@ pub fn derive_has_fields_impls_from_struct(item_struct: &ItemStruct) -> syn::Res let has_fields_impl: ItemImpl = parse2(quote! { impl #impl_generics - HasFields for #struct_name #type_generics + #HasFields for #struct_name #type_generics #where_clause { type Fields = #fields_type ; @@ -28,7 +29,7 @@ pub fn derive_has_fields_impls_from_struct(item_struct: &ItemStruct) -> syn::Res let has_fields_ref_impl: ItemImpl = parse2(quote! { impl #impl_generics - HasFieldsRef for #struct_name #type_generics + #HasFieldsRef for #struct_name #type_generics #where_clause { type FieldsRef< #life > = #fields_ref_type diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/from_fields_enum.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/from_fields_enum.rs similarity index 81% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/from_fields_enum.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/from_fields_enum.rs index 9390fec5..90ea9929 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/from_fields_enum.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/from_fields_enum.rs @@ -1,7 +1,8 @@ use quote::quote; use syn::{ItemEnum, ItemImpl, parse2}; -use crate::derive_has_fields::from_fields_struct::derive_from_field_params; +use crate::exports::{Either, FromFields}; +use crate::types::cgp_data::derive_from_field_params; pub fn derive_from_fields_for_enum(item_enum: &ItemEnum) -> syn::Result { let enum_name = &item_enum.ident; @@ -18,11 +19,11 @@ pub fn derive_from_fields_for_enum(item_enum: &ItemEnum) -> syn::Result { + #Either::Left( field ) => { let #product_arg = field.value; Self:: #variant_ident #product_constructor_args } - σ::Right(rest) => { + #Either::Right(rest) => { #match_expr } } @@ -31,7 +32,7 @@ pub fn derive_from_fields_for_enum(item_enum: &ItemEnum) -> syn::Result syn::Result { let struct_name = &item_struct.ident; let (impl_generics, type_generics, where_clause) = item_struct.generics.split_for_impl(); @@ -11,7 +13,7 @@ pub fn derive_from_fields_for_struct(item_struct: &ItemStruct) -> syn::Result syn::Result syn::Result<(TokenStream, TokenStream)> { match fields { Fields::Named(fields) => { - let mut fields_arg = quote! { ε }; + let mut fields_arg = quote! { #Nil }; let mut constructor_args = quote! {}; for field in fields.named.iter().rev() { @@ -37,7 +39,7 @@ pub fn derive_from_field_params(fields: &Fields) -> syn::Result<(TokenStream, To })?; fields_arg = quote! { - π( #field_name, #fields_arg ) + #Cons( #field_name, #fields_arg ) }; constructor_args = quote! { @@ -60,14 +62,14 @@ pub fn derive_from_field_params(fields: &Fields) -> syn::Result<(TokenStream, To Ok((fields_arg, constructor_args)) } else { - let mut fields_arg = quote! { ε }; + let mut fields_arg = quote! { #Nil }; let mut constructor_args = quote! {}; for (i, field) in fields.unnamed.iter().enumerate() { let field_name: Ident = Ident::new(&format!("field_{i}"), field.span()); fields_arg = quote! { - π( #field_name, #fields_arg ) + #Cons( #field_name, #fields_arg ) }; constructor_args = quote! { @@ -84,6 +86,6 @@ pub fn derive_from_field_params(fields: &Fields) -> syn::Result<(TokenStream, To )) } } - Fields::Unit => Ok((quote! { ε }, TokenStream::new())), + Fields::Unit => Ok((quote! { #Nil }, TokenStream::new())), } } diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/mod.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/mod.rs similarity index 53% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/mod.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/mod.rs index 8b42af8f..7393c6ab 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/mod.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/mod.rs @@ -11,3 +11,11 @@ mod to_fields_struct; pub use derive_enum::*; pub use derive_struct::*; +pub use from_fields_enum::*; +pub use from_fields_struct::*; +pub use product::*; +pub use sum::*; +pub use to_fields_enum::*; +pub use to_fields_ref_enum::*; +pub use to_fields_ref_struct::*; +pub use to_fields_struct::*; diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/product.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/product.rs similarity index 74% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/product.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/product.rs index 7ca37440..44e323dd 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/product.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/product.rs @@ -3,10 +3,11 @@ use quote::quote; use syn::spanned::Spanned; use syn::{Error, Fields, LitInt, Type, parse2}; -use crate::symbol::symbol_from_string; +use crate::exports::{Cons, Field, Index, Nil}; +use crate::types::field::Symbol; pub fn item_fields_to_product_type(fields: &Fields, reference: &TokenStream) -> syn::Result { - let mut fields_type = quote! { ε }; + let mut fields_type = quote! { #Nil }; match fields { Fields::Named(fields) => { @@ -15,11 +16,11 @@ pub fn item_fields_to_product_type(fields: &Fields, reference: &TokenStream) -> Error::new_spanned(field, "expect struct field to contain name identifier") })?; - let field_tag = symbol_from_string(&field_name.to_string())?; + let field_tag = Symbol::from_ident(field_name.clone()); let field_type = &field.ty; fields_type = parse2(quote! { - π< ω< #field_tag, #reference #field_type >, #fields_type > + #Cons< #Field< #field_tag, #reference #field_type >, #fields_type > })?; } } @@ -33,11 +34,11 @@ pub fn item_fields_to_product_type(fields: &Fields, reference: &TokenStream) -> for (i, field) in fields.unnamed.iter().enumerate().rev() { let index = LitInt::new(&format!("{i}"), field.span()); - let field_tag = quote! { δ< #index > }; + let field_tag = quote! { #Index< #index > }; let field_type = &field.ty; fields_type = parse2(quote! { - π< ω< #field_tag, #reference #field_type >, #fields_type > + #Cons< #Field< #field_tag, #reference #field_type >, #fields_type > })?; } } diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/sum.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs similarity index 62% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/sum.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs index 8f9ce680..e1007ae3 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/sum.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/sum.rs @@ -4,24 +4,25 @@ use syn::punctuated::Punctuated; use syn::token::Comma; use syn::{Type, Variant, parse2}; -use crate::derive_has_fields::product::item_fields_to_product_type; -use crate::symbol::symbol_from_string; +use crate::exports::{Either, Field, Void}; +use crate::types::cgp_data::item_fields_to_product_type; +use crate::types::field::Symbol; pub fn variants_to_sum_type( variants: &Punctuated, reference: &TokenStream, ) -> syn::Result { - let mut out = quote! { θ }; + let mut out = quote! { #Void }; for variant in variants.iter().rev() { let variant_ident = &variant.ident; - let variant_symbol = symbol_from_string(&variant_ident.to_string())?; + let variant_symbol = Symbol::from_ident(variant_ident.clone()); let variant_fields = item_fields_to_product_type(&variant.fields, reference)?; out = quote! { - σ< - ω< #variant_symbol, #variant_fields >, + #Either< + #Field< #variant_symbol, #variant_fields >, #out, > }; diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_enum.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_enum.rs similarity index 92% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_enum.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_enum.rs index f9c188dd..5c9bc335 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_enum.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_enum.rs @@ -5,7 +5,8 @@ use syn::spanned::Spanned; use syn::token::Comma; use syn::{Error, Fields, Ident, ItemEnum, ItemImpl, Variant, parse2}; -use crate::derive_has_fields::to_fields_struct::{FieldLabel, derive_to_fields_constructor}; +use crate::exports::{Either, ToFields}; +use crate::types::cgp_data::{FieldLabel, derive_to_fields_constructor}; pub fn derive_to_fields_for_enum(item_enum: &ItemEnum) -> syn::Result { let enum_name = &item_enum.ident; @@ -15,7 +16,7 @@ pub fn derive_to_fields_for_enum(item_enum: &ItemEnum) -> syn::Result let item_impl = quote! { impl #impl_generics - ToFields for #enum_name #type_generics + #ToFields for #enum_name #type_generics #where_clause { fn to_fields( @@ -58,14 +59,14 @@ pub fn derive_to_fields_match_arms( let variant_args = extract_variant_args(&variant.fields)?; let inject_variant = inject_prefix(quote! { - σ::Left( #constructor .into() ) + #Either::Left( #constructor .into() ) }); inject_prefix = Box::new(move |inner| { let outer = inject_prefix(inner); quote! { - σ::Right( #outer ) + #Either::Right( #outer ) } }); diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_ref_enum.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_ref_enum.rs similarity index 84% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_ref_enum.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_ref_enum.rs index 4b03d43d..2350b6c9 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_ref_enum.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_ref_enum.rs @@ -1,7 +1,8 @@ use quote::quote; use syn::{ItemEnum, ItemImpl, parse2}; -use crate::derive_has_fields::to_fields_enum::derive_to_fields_match_arms; +use crate::exports::ToFieldsRef; +use crate::types::cgp_data::derive_to_fields_match_arms; pub fn derive_to_fields_ref_for_enum(item_enum: &ItemEnum) -> syn::Result { let struct_name = &item_enum.ident; @@ -13,7 +14,7 @@ pub fn derive_to_fields_ref_for_enum(item_enum: &ItemEnum) -> syn::Result( diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_ref_struct.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_ref_struct.rs similarity index 86% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_ref_struct.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_ref_struct.rs index 7aa238f6..b5f20353 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_ref_struct.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_ref_struct.rs @@ -1,7 +1,8 @@ use quote::quote; use syn::{ItemImpl, ItemStruct, Lifetime, parse_quote, parse2}; -use crate::derive_has_fields::to_fields_struct::{FieldLabel, derive_to_fields_constructor}; +use crate::exports::ToFieldsRef; +use crate::types::cgp_data::{FieldLabel, derive_to_fields_constructor}; pub fn derive_to_fields_ref_for_struct(item_struct: &ItemStruct) -> syn::Result { let struct_name = &item_struct.ident; @@ -21,7 +22,7 @@ pub fn derive_to_fields_ref_for_struct(item_struct: &ItemStruct) -> syn::Result< let item_impl = parse2(quote! { impl #impl_generics - ToFieldsRef for #struct_name #type_generics + #ToFieldsRef for #struct_name #type_generics #where_clause { fn to_fields_ref< #life >( diff --git a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_struct.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_struct.rs similarity index 91% rename from crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_struct.rs rename to crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_struct.rs index 14b90ccb..e9c92173 100644 --- a/crates/macros/cgp-macro-lib/src/derive_has_fields/to_fields_struct.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/derive_has_fields/to_fields_struct.rs @@ -3,6 +3,8 @@ use quote::{ToTokens, quote}; use syn::spanned::Spanned; use syn::{Error, Fields, Ident, ItemImpl, ItemStruct, LitInt, parse2}; +use crate::exports::{Cons, Nil, ToFields}; + pub fn derive_to_fields_for_struct(item_struct: &ItemStruct) -> syn::Result { let struct_name = &item_struct.ident; let (impl_generics, type_generics, where_clause) = item_struct.generics.split_for_impl(); @@ -19,7 +21,7 @@ pub fn derive_to_fields_for_struct(item_struct: &ItemStruct) -> syn::Result TokenStream, ) -> syn::Result { - let mut constructors = quote! { ε }; + let mut constructors = quote! { #Nil }; match &fields { Fields::Named(fields) => { @@ -65,7 +67,7 @@ pub fn derive_to_fields_constructor( let constructor = construct_field(FieldLabel::Named(field_name)); constructors = quote! { - π( + #Cons( #constructor, #constructors ) @@ -74,9 +76,6 @@ pub fn derive_to_fields_constructor( } Fields::Unnamed(fields) => { if fields.unnamed.len() == 1 { - // constructors = quote! { - // field - // } constructors = construct_field(FieldLabel::None); } else { for (i, field) in fields.unnamed.iter().enumerate().rev() { @@ -85,7 +84,7 @@ pub fn derive_to_fields_constructor( let constructor = construct_field(FieldLabel::Unnamed(field_name)); constructors = quote! { - π( + #Cons( #constructor, #constructors ) diff --git a/crates/macros/cgp-macro-core/src/types/cgp_data/item.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/item.rs new file mode 100644 index 00000000..1cb7658e --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/item.rs @@ -0,0 +1,33 @@ +use syn::parse::{Parse, ParseStream}; +use syn::{Error, Item}; + +use crate::types::cgp_data::{ItemCgpRecord, ItemCgpVariant}; + +pub enum ItemCgpData { + Record(ItemCgpRecord), + Variant(ItemCgpVariant), +} + +impl ItemCgpData { + pub fn to_items(&self) -> syn::Result> { + match self { + ItemCgpData::Record(record) => record.to_items(), + ItemCgpData::Variant(variant) => variant.to_items(), + } + } +} + +impl Parse for ItemCgpData { + fn parse(input: ParseStream) -> syn::Result { + let item: Item = input.parse()?; + + match item { + Item::Struct(item_struct) => Ok(Self::Record(ItemCgpRecord { item_struct })), + Item::Enum(item_enum) => Ok(Self::Variant(ItemCgpVariant { item_enum })), + _ => Err(Error::new_spanned( + item, + "expect body to be either a struct or enum", + )), + } + } +} diff --git a/crates/macros/cgp-macro-core/src/types/cgp_data/mod.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/mod.rs new file mode 100644 index 00000000..e5eb3941 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/mod.rs @@ -0,0 +1,17 @@ +mod derive_builder; +mod derive_extractor; +mod derive_from_variant; +mod derive_has_field; +mod derive_has_fields; +mod item; +mod record; +mod variant; + +pub use derive_builder::*; +pub use derive_extractor::*; +pub use derive_from_variant::*; +pub use derive_has_field::*; +pub use derive_has_fields::*; +pub use item::*; +pub use record::*; +pub use variant::*; diff --git a/crates/macros/cgp-macro-core/src/types/cgp_data/record.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/record.rs new file mode 100644 index 00000000..c4219bdf --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/record.rs @@ -0,0 +1,79 @@ +use syn::parse::{Parse, ParseStream}; +use syn::{Ident, Item, ItemImpl, ItemStruct}; + +use crate::types::cgp_data::{ + derive_builder_struct, derive_finalize_build_impl, derive_has_builder_impl, + derive_has_field_impls, derive_has_field_impls_from_struct, + derive_has_fields_impls_from_struct, derive_into_builder_impl, + derive_partial_data_impl_from_struct, derive_update_field_impls, +}; + +pub struct ItemCgpRecord { + pub item_struct: ItemStruct, +} + +impl ItemCgpRecord { + pub fn to_items(&self) -> syn::Result> { + let has_field_impls = self.to_has_field_impls()?; + let has_fields_impls = self.to_has_fields_impls()?; + let build_field_impls = self.to_build_field_items()?; + + let mut items = Vec::new(); + + items.extend(has_field_impls.into_iter().map(Item::from)); + items.extend(has_fields_impls.into_iter().map(Item::from)); + items.extend(build_field_impls); + + Ok(items) + } + + pub fn to_has_field_impls(&self) -> syn::Result> { + derive_has_field_impls_from_struct(&self.item_struct) + } + + pub fn to_has_fields_impls(&self) -> syn::Result> { + derive_has_fields_impls_from_struct(&self.item_struct) + } + + pub fn to_build_field_items(&self) -> syn::Result> { + let item_struct = &self.item_struct; + + let context_ident = &item_struct.ident; + let builder_ident = Ident::new(&format!("__Partial{context_ident}"), context_ident.span()); + + let builder_struct = derive_builder_struct(item_struct, &builder_ident)?; + + let has_builder_impl = derive_has_builder_impl(item_struct, &builder_ident)?; + + let into_builder_impl = derive_into_builder_impl(item_struct, &builder_ident)?; + + let partial_data_impl = derive_partial_data_impl_from_struct(item_struct, &builder_ident)?; + + let finalize_build_impl = derive_finalize_build_impl(item_struct, &builder_ident)?; + + let update_field_impls = derive_update_field_impls(item_struct, &builder_ident)?; + + let has_field_impls = derive_has_field_impls(item_struct, &builder_ident)?; + + let mut items = vec![ + builder_struct.into(), + has_builder_impl.into(), + into_builder_impl.into(), + partial_data_impl.into(), + finalize_build_impl.into(), + ]; + + items.extend(update_field_impls.into_iter().map(Item::from)); + items.extend(has_field_impls.into_iter().map(Item::from)); + + Ok(items) + } +} + +impl Parse for ItemCgpRecord { + fn parse(input: ParseStream) -> syn::Result { + let item_struct = input.parse()?; + + Ok(Self { item_struct }) + } +} diff --git a/crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs b/crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs new file mode 100644 index 00000000..0de415f0 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/cgp_data/variant.rs @@ -0,0 +1,104 @@ +use syn::parse::{Parse, ParseStream}; +use syn::{Ident, Item, ItemEnum, ItemImpl}; + +use crate::types::cgp_data::{ + derive_extract_field_impls, derive_extractor_enum, derive_extractor_enum_ref, + derive_finalize_extract_impl, derive_from_variant_from_enum, derive_has_extractor_impl, + derive_has_extractor_mut_impl, derive_has_extractor_ref_impl, + derive_has_fields_impls_from_enum, derive_partial_data_impl_from_enum, +}; + +pub struct ItemCgpVariant { + pub item_enum: ItemEnum, +} + +impl ItemCgpVariant { + pub fn to_items(&self) -> syn::Result> { + let has_fields = self.to_has_fields_impls()?; + let from_variant_impls = self.to_from_variant_impls()?; + let extract_field = self.to_extract_field_items()?; + + let mut items = Vec::new(); + + items.extend(has_fields.into_iter().map(Item::from)); + items.extend(from_variant_impls.into_iter().map(Item::from)); + items.extend(extract_field); + + Ok(items) + } + + pub fn to_from_variant_impls(&self) -> syn::Result> { + derive_from_variant_from_enum(&self.item_enum) + } + + pub fn to_has_fields_impls(&self) -> syn::Result> { + derive_has_fields_impls_from_enum(&self.item_enum) + } + + pub fn to_extract_field_items(&self) -> syn::Result> { + let item_enum = &self.item_enum; + + let context_ident = &item_enum.ident; + + let extractor_ident = + Ident::new(&format!("__Partial{context_ident}"), context_ident.span()); + + let extractor_enum = derive_extractor_enum(item_enum, &extractor_ident)?; + + let extractor_ref_ident = Ident::new( + &format!("__PartialRef{context_ident}"), + context_ident.span(), + ); + let extractor_ref_enum = derive_extractor_enum_ref(item_enum, &extractor_ref_ident)?; + + let has_extractor_impl = derive_has_extractor_impl(item_enum, &extractor_ident)?; + + let has_extractor_ref_impl = + derive_has_extractor_ref_impl(item_enum, &extractor_ref_ident)?; + + let has_extractor_mut_impl = + derive_has_extractor_mut_impl(item_enum, &extractor_ref_ident)?; + + let finalize_extract_impl = + derive_finalize_extract_impl(item_enum, &extractor_ident, false)?; + + let finalize_extract_ref_impl = + derive_finalize_extract_impl(item_enum, &extractor_ref_ident, true)?; + + let partial_data_impl = + derive_partial_data_impl_from_enum(item_enum, &extractor_ident, false)?; + + let partial_ref_data_impl = + derive_partial_data_impl_from_enum(item_enum, &extractor_ref_ident, true)?; + + let extractor_impls = derive_extract_field_impls(item_enum, &extractor_ident, false)?; + + let extractor_ref_impls = + derive_extract_field_impls(item_enum, &extractor_ref_ident, true)?; + + let mut items = vec![ + extractor_enum.into(), + extractor_ref_enum.into(), + partial_data_impl.into(), + partial_ref_data_impl.into(), + has_extractor_impl.into(), + has_extractor_ref_impl.into(), + has_extractor_mut_impl.into(), + finalize_extract_impl.into(), + finalize_extract_ref_impl.into(), + ]; + + items.extend(extractor_impls.into_iter().map(Item::from)); + items.extend(extractor_ref_impls.into_iter().map(Item::from)); + + Ok(items) + } +} + +impl Parse for ItemCgpVariant { + fn parse(input: ParseStream) -> syn::Result { + let item_enum = input.parse()?; + + Ok(Self { item_enum }) + } +} diff --git a/crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs b/crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs index 6c5447f5..e4b0454e 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_getter/to_use_fields_impl.rs @@ -1,6 +1,7 @@ use quote::ToTokens; use syn::{ImplItem, ItemImpl, Type}; +use crate::exports::UseFields; use crate::functions::parse_internal; use crate::types::cgp_getter::{ItemCgpGetter, ReceiverMode}; use crate::types::field::{HasFieldBound, Symbol}; @@ -53,7 +54,7 @@ impl ItemCgpGetter { ReceiverMode::Type(ty) => ty.clone(), }; - let field_name = Symbol::new(field.field_name.clone()); + let field_name = Symbol::from_ident(field.field_name.clone()); let tag_type: Type = parse_internal!(#field_name); let method = derive_getter_method( @@ -88,7 +89,7 @@ impl ItemCgpGetter { let (impl_generics, _, where_clause) = provider_generics.split_for_impl(); let item_impl: ItemImpl = parse_internal! { - impl #impl_generics #provider_name #type_generics for UseFields + impl #impl_generics #provider_name #type_generics for #UseFields #where_clause { #( #items )* diff --git a/crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs b/crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs index 533f4c9e..922398b1 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_getter/use_field.rs @@ -4,6 +4,7 @@ use syn::punctuated::Punctuated; use syn::token::Plus; use syn::{Generics, ItemImpl, Type, TypeParamBound}; +use crate::exports::UseField; use crate::functions::parse_internal; use crate::types::cgp_getter::{GetterField, ItemCgpGetter, ReceiverMode}; use crate::types::field::HasFieldBound; @@ -112,7 +113,7 @@ impl ItemCgpGetter { }; let use_field_impl: ItemImpl = parse_internal! { - impl #impl_generics #provider_name #type_generics for UseField< #tag_type > + impl #impl_generics #provider_name #type_generics for #UseField< #tag_type > #where_clause { #items diff --git a/crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs b/crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs index eefd22be..0ed6ec96 100644 --- a/crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs +++ b/crates/macros/cgp-macro-core/src/types/cgp_getter/with_provider.rs @@ -2,6 +2,7 @@ use proc_macro2::Span; use quote::{ToTokens, quote}; use syn::{Generics, Ident, ImplItem, ItemImpl}; +use crate::exports::{FieldGetter, MutFieldGetter, WithProvider}; use crate::functions::parse_internal; use crate::types::cgp_getter::{GetterField, ItemCgpGetter, ReceiverMode}; use crate::types::getter::{ContextArg, FieldMode, derive_getter_method}; @@ -81,16 +82,16 @@ impl ItemCgpGetter { let provider_constraint = if field.receiver_mut.is_none() { if let FieldMode::Slice = field.field_mode { quote! { - FieldGetter< #receiver_type, #component_name, Value: AsRef< [ #field_type ] > + 'static > + #FieldGetter< #receiver_type, #component_name, Value: AsRef< [ #field_type ] > + 'static > } } else { quote! { - FieldGetter< #receiver_type, #component_name , Value = #field_type > + #FieldGetter< #receiver_type, #component_name , Value = #field_type > } } } else { quote! { - MutFieldGetter< #receiver_type, #component_name, Value = #field_type > + #MutFieldGetter< #receiver_type, #component_name, Value = #field_type > } }; @@ -118,7 +119,7 @@ impl ItemCgpGetter { }; let out = parse_internal! { - impl #impl_generics #provider_name #type_generics for WithProvider< #provider_ident > + impl #impl_generics #provider_name #type_generics for #WithProvider< #provider_ident > #where_clause { #( #items )* diff --git a/crates/macros/cgp-macro-core/src/types/cgp_type/item.rs b/crates/macros/cgp-macro-core/src/types/cgp_type/item.rs new file mode 100644 index 00000000..d13522bc --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/cgp_type/item.rs @@ -0,0 +1,127 @@ +use syn::spanned::Spanned; +use syn::{Error, Item, ItemImpl, ItemTrait, TraitItem, TraitItemType}; + +use crate::exports::{TypeProvider, UseType, WithProvider}; +use crate::parse_internal; +use crate::types::cgp_component::EvaluatedCgpComponent; +use crate::types::provider_impl::{ItemProviderImpl, ItemProviderImpls}; +use crate::visitors::get_bounds_and_replace_self_assoc_type; + +pub struct ItemCgpType { + pub item_component: EvaluatedCgpComponent, +} + +impl ItemCgpType { + pub fn to_items(&self) -> syn::Result> { + let mut items = self.item_component.to_items()?; + + let item_impls = self.to_item_provider_impls()?.to_item_impls()?; + + items.extend(item_impls.into_iter().map(Item::from)); + + Ok(items) + } + + pub fn to_trait_item_type(&self) -> syn::Result { + extract_item_type_from_trait(&self.item_component.consumer_trait) + } + + pub fn to_item_provider_impls(&self) -> syn::Result { + let context_name = &self.item_component.args.context_ident; + let component_type = self.item_component.args.component_name.to_type(); + + let provider_trait = &self.item_component.provider_trait; + let provider_trait_name = &provider_trait.ident; + + let item_type = self.to_trait_item_type()?; + + let type_name = &item_type.ident; + + let type_bounds = get_bounds_and_replace_self_assoc_type(&item_type); + + let mut generics = provider_trait.generics.clone(); + generics.params.insert(0, parse_internal!(#type_name)); + + if !type_bounds.is_empty() { + generics + .make_where_clause() + .predicates + .push(parse_internal! { + #type_name: #type_bounds + }); + } + + let (_, type_generics, _) = provider_trait.generics.split_for_impl(); + let (impl_generics, _, where_clause) = generics.split_for_impl(); + + let use_type_impl: ItemImpl = parse_internal! { + impl #impl_generics + #provider_trait_name #type_generics + for #UseType< #type_name > + #where_clause + { + type #type_name = #type_name; + } + }; + + let use_type_provider = ItemProviderImpl { + component_type: component_type.clone(), + item_impl: use_type_impl, + }; + + generics.params.insert(0, parse_internal!(__Provider__)); + generics + .make_where_clause() + .predicates + .push(parse_internal! { + __Provider__: #TypeProvider< #context_name, #component_type, Type = #type_name > + }); + + let (impl_generics, _, where_clause) = generics.split_for_impl(); + + let with_provider_impl: ItemImpl = parse_internal! { + impl #impl_generics + #provider_trait_name #type_generics + for #WithProvider< __Provider__ > + #where_clause + { + type #type_name = #type_name; + } + }; + + let with_provider_provider = ItemProviderImpl { + component_type: component_type.clone(), + item_impl: with_provider_impl, + }; + + Ok(ItemProviderImpls { + items: vec![use_type_provider, with_provider_provider], + }) + } +} + +pub fn extract_item_type_from_trait(consumer_trait: &ItemTrait) -> syn::Result { + if consumer_trait.items.len() != 1 { + return Err(Error::new( + consumer_trait.span(), + "type trait should contain exactly one associated type item", + )); + } + + match consumer_trait.items.first() { + Some(TraitItem::Type(item_type)) => { + if !item_type.generics.params.is_empty() || item_type.generics.where_clause.is_some() { + return Err(Error::new( + consumer_trait.span(), + "generic associated type and where clause are not supported", + )); + } + + Ok(item_type.clone()) + } + _ => Err(Error::new( + consumer_trait.span(), + "type trait should contain exactly one associated type item", + )), + } +} diff --git a/crates/macros/cgp-macro-core/src/types/cgp_type/mod.rs b/crates/macros/cgp-macro-core/src/types/cgp_type/mod.rs new file mode 100644 index 00000000..95e0a691 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/cgp_type/mod.rs @@ -0,0 +1,3 @@ +mod item; + +pub use item::*; diff --git a/crates/macros/cgp-macro-core/src/types/check_components/table.rs b/crates/macros/cgp-macro-core/src/types/check_components/table.rs index 16ea61f8..93fdbf1f 100644 --- a/crates/macros/cgp-macro-core/src/types/check_components/table.rs +++ b/crates/macros/cgp-macro-core/src/types/check_components/table.rs @@ -6,7 +6,7 @@ use syn::spanned::Spanned; use syn::token::{Comma, Lt, Pound, Where}; use syn::{Attribute, Ident, Item, ItemImpl, ItemTrait, Type, WhereClause, braced, parse2}; -use crate::exports::CanUseComponent; +use crate::exports::{CanUseComponent, IsProviderFor}; use crate::functions::merge_generics; use crate::parse_internal; use crate::types::check_components::{CheckEntries, EvaluatedCheckEntry, TypeWithGenerics}; @@ -43,7 +43,7 @@ impl CheckComponentsTable { let item_trait: ItemTrait = if self.check_providers.is_some() { parse_internal! { - trait #trait_name <__Component__, __Params__: ?Sized>: IsProviderFor<__Component__, #context_type, __Params__> {} + trait #trait_name <__Component__, __Params__: ?Sized>: #IsProviderFor<__Component__, #context_type, __Params__> {} } } else { parse_internal! { diff --git a/crates/macros/cgp-macro-core/src/types/field/field_name.rs b/crates/macros/cgp-macro-core/src/types/field/field_name.rs index 5e8ea365..253bc360 100644 --- a/crates/macros/cgp-macro-core/src/types/field/field_name.rs +++ b/crates/macros/cgp-macro-core/src/types/field/field_name.rs @@ -11,7 +11,7 @@ pub enum FieldName { impl From for FieldName { fn from(value: Ident) -> Self { - Self::Ident(Symbol::new(value)) + Self::Ident(Symbol::from_ident(value)) } } diff --git a/crates/macros/cgp-macro-core/src/types/field/symbol.rs b/crates/macros/cgp-macro-core/src/types/field/symbol.rs index e7081e47..667d7365 100644 --- a/crates/macros/cgp-macro-core/src/types/field/symbol.rs +++ b/crates/macros/cgp-macro-core/src/types/field/symbol.rs @@ -1,17 +1,32 @@ -use proc_macro2::{Literal, TokenStream}; +use proc_macro2::{Literal, Span, TokenStream}; use quote::{ToTokens, quote_spanned}; -use syn::{Ident, Type, parse_quote}; +use syn::parse::{Parse, ParseStream}; +use syn::{Ident, LitStr, Type, parse_quote}; use crate::traits::ToType; #[derive(Debug, Clone)] pub struct Symbol { - pub ident: Ident, + pub ident: String, + pub span: Span, } impl Symbol { - pub fn new(ident: Ident) -> Self { - Self { ident } + pub fn from_ident(ident: Ident) -> Self { + Self { + ident: ident.to_string(), + span: ident.span(), + } + } +} + +impl Parse for Symbol { + fn parse(input: ParseStream) -> syn::Result { + let literal: LitStr = input.parse()?; + Ok(Self { + ident: literal.value(), + span: literal.span(), + }) } } @@ -19,7 +34,7 @@ impl ToTokens for Symbol { fn to_tokens(&self, tokens: &mut TokenStream) { use crate::exports::{Chars, Nil, Symbol}; - let span = self.ident.span(); + let span = self.span; let str_value = self.ident.to_string(); let chars = str_value.chars().rev().fold( diff --git a/crates/macros/cgp-macro-core/src/types/mod.rs b/crates/macros/cgp-macro-core/src/types/mod.rs index 024cae30..c2325812 100644 --- a/crates/macros/cgp-macro-core/src/types/mod.rs +++ b/crates/macros/cgp-macro-core/src/types/mod.rs @@ -2,10 +2,12 @@ pub mod attributes; pub mod blanket_trait; pub mod cgp_auto_getter; pub mod cgp_component; +pub mod cgp_data; pub mod cgp_fn; pub mod cgp_getter; pub mod cgp_impl; pub mod cgp_provider; +pub mod cgp_type; pub mod check_components; pub mod delegate_and_check_components; pub mod delegate_component; @@ -19,4 +21,6 @@ pub mod keyword; pub mod keywords; pub mod namespace; pub mod path; +pub mod product; pub mod provider_impl; +pub mod sum; diff --git a/crates/macros/cgp-macro-core/src/types/path/path_element.rs b/crates/macros/cgp-macro-core/src/types/path/path_element.rs index 285ff91d..ea1cdc73 100644 --- a/crates/macros/cgp-macro-core/src/types/path/path_element.rs +++ b/crates/macros/cgp-macro-core/src/types/path/path_element.rs @@ -24,7 +24,7 @@ impl Parse for PathElement { && path_char.is_ascii_lowercase() && !is_primitive_type(&path_str) { - Self::Symbol(Symbol::new(path_ident)) + Self::Symbol(Symbol::from_ident(path_ident)) } else { Self::Type(ty) } diff --git a/crates/macros/cgp-macro-core/src/types/product/mod.rs b/crates/macros/cgp-macro-core/src/types/product/mod.rs new file mode 100644 index 00000000..b19cd7d0 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/product/mod.rs @@ -0,0 +1,5 @@ +mod product_expr; +mod product_type; + +pub use product_expr::*; +pub use product_type::*; diff --git a/crates/macros/cgp-macro-core/src/types/product/product_expr.rs b/crates/macros/cgp-macro-core/src/types/product/product_expr.rs new file mode 100644 index 00000000..a9a96c42 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/product/product_expr.rs @@ -0,0 +1,34 @@ +use quote::quote; +use syn::Type; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::Comma; + +use crate::exports::{Cons, Nil}; +use crate::functions::parse_internal; + +pub struct ProductExpr { + pub types: Punctuated, +} + +impl ProductExpr { + pub fn eval(&self) -> syn::Result { + let mut out = quote!(#Nil); + + for ty in self.types.iter().rev() { + out = quote! { + #Cons(#ty, #out) + }; + } + + parse_internal(out) + } +} + +impl Parse for ProductExpr { + fn parse(input: ParseStream) -> syn::Result { + let types = Punctuated::parse_terminated(input)?; + + Ok(Self { types }) + } +} diff --git a/crates/macros/cgp-macro-core/src/types/product/product_type.rs b/crates/macros/cgp-macro-core/src/types/product/product_type.rs new file mode 100644 index 00000000..95dea299 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/product/product_type.rs @@ -0,0 +1,34 @@ +use quote::quote; +use syn::Type; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::Comma; + +use crate::exports::{Cons, Nil}; +use crate::functions::parse_internal; + +pub struct ProductType { + pub types: Punctuated, +} + +impl ProductType { + pub fn eval(&self) -> syn::Result { + let mut out = quote!(#Nil); + + for ty in self.types.iter().rev() { + out = quote! { + #Cons< #ty, #out > + }; + } + + parse_internal(out) + } +} + +impl Parse for ProductType { + fn parse(input: ParseStream) -> syn::Result { + let types = Punctuated::parse_terminated(input)?; + + Ok(Self { types }) + } +} diff --git a/crates/macros/cgp-macro-core/src/types/sum.rs b/crates/macros/cgp-macro-core/src/types/sum.rs new file mode 100644 index 00000000..b13e8432 --- /dev/null +++ b/crates/macros/cgp-macro-core/src/types/sum.rs @@ -0,0 +1,34 @@ +use quote::quote; +use syn::Type; +use syn::parse::{Parse, ParseStream}; +use syn::punctuated::Punctuated; +use syn::token::Comma; + +use crate::exports::{Either, Void}; +use crate::functions::parse_internal; + +pub struct SumType { + pub types: Punctuated, +} + +impl SumType { + pub fn eval(&self) -> syn::Result { + let mut out = quote!(#Void); + + for ty in self.types.iter().rev() { + out = quote! { + #Either< #ty, #out > + }; + } + + parse_internal(out) + } +} + +impl Parse for SumType { + fn parse(input: ParseStream) -> syn::Result { + let types = Punctuated::parse_terminated(input)?; + + Ok(Self { types }) + } +} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/blanket_trait.rs b/crates/macros/cgp-macro-lib/src/blanket_trait.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/blanket_trait.rs rename to crates/macros/cgp-macro-lib/src/blanket_trait.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_auto_getter.rs b/crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_auto_getter.rs rename to crates/macros/cgp-macro-lib/src/cgp_auto_getter.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_component.rs b/crates/macros/cgp-macro-lib/src/cgp_component.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_component.rs rename to crates/macros/cgp-macro-lib/src/cgp_component.rs diff --git a/crates/macros/cgp-macro-lib/src/cgp_data.rs b/crates/macros/cgp-macro-lib/src/cgp_data.rs new file mode 100644 index 00000000..47a31d44 --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/cgp_data.rs @@ -0,0 +1,14 @@ +use cgp_macro_core::types::cgp_data::ItemCgpData; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse2; + +pub fn derive_cgp_data(body: TokenStream) -> syn::Result { + let data: ItemCgpData = parse2(body)?; + + let items = data.to_items()?; + + Ok(quote! { + #( #items )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_fn.rs b/crates/macros/cgp-macro-lib/src/cgp_fn.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_fn.rs rename to crates/macros/cgp-macro-lib/src/cgp_fn.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_getter.rs b/crates/macros/cgp-macro-lib/src/cgp_getter.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_getter.rs rename to crates/macros/cgp-macro-lib/src/cgp_getter.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_impl.rs b/crates/macros/cgp-macro-lib/src/cgp_impl.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_impl.rs rename to crates/macros/cgp-macro-lib/src/cgp_impl.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_namespace.rs b/crates/macros/cgp-macro-lib/src/cgp_namespace.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_namespace.rs rename to crates/macros/cgp-macro-lib/src/cgp_namespace.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs b/crates/macros/cgp-macro-lib/src/cgp_new_provider.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_new_provider.rs rename to crates/macros/cgp-macro-lib/src/cgp_new_provider.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_provider.rs b/crates/macros/cgp-macro-lib/src/cgp_provider.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_provider.rs rename to crates/macros/cgp-macro-lib/src/cgp_provider.rs diff --git a/crates/macros/cgp-macro-lib/src/cgp_record.rs b/crates/macros/cgp-macro-lib/src/cgp_record.rs new file mode 100644 index 00000000..a1969b36 --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/cgp_record.rs @@ -0,0 +1,14 @@ +use cgp_macro_core::types::cgp_data::ItemCgpRecord; +use proc_macro2::TokenStream; +use quote::quote; +use syn::parse2; + +pub fn derive_cgp_record(body: TokenStream) -> syn::Result { + let record: ItemCgpRecord = parse2(body)?; + + let items = record.to_items()?; + + Ok(quote! { + #( #items )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_type.rs b/crates/macros/cgp-macro-lib/src/cgp_type.rs similarity index 73% rename from crates/macros/cgp-macro-lib/src/entrypoints/cgp_type.rs rename to crates/macros/cgp-macro-lib/src/cgp_type.rs index fa92f47a..cef60003 100644 --- a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_type.rs +++ b/crates/macros/cgp-macro-lib/src/cgp_type.rs @@ -1,12 +1,9 @@ -use alloc::format; - use cgp_macro_core::types::cgp_component::{CgpComponentRawArgs, ItemCgpComponent}; +use cgp_macro_core::types::cgp_type::{ItemCgpType, extract_item_type_from_trait}; use proc_macro2::TokenStream; use quote::quote; use syn::{Ident, ItemTrait, parse2}; -use crate::type_component::{derive_type_providers, extract_item_type_from_trait}; - pub fn cgp_type(attrs: TokenStream, body: TokenStream) -> syn::Result { let mut raw_args: CgpComponentRawArgs = parse2(attrs.clone())?; @@ -28,16 +25,13 @@ pub fn cgp_type(attrs: TokenStream, body: TokenStream) -> syn::Result syn::Result { + let variant: ItemCgpVariant = parse2(body)?; + + let items = variant.to_items()?; + + Ok(quote! { + #( #items )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/check_components.rs b/crates/macros/cgp-macro-lib/src/check_components.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/check_components.rs rename to crates/macros/cgp-macro-lib/src/check_components.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/delegate_and_check_components.rs b/crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/delegate_and_check_components.rs rename to crates/macros/cgp-macro-lib/src/delegate_and_check_components.rs diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/delegate_components.rs b/crates/macros/cgp-macro-lib/src/delegate_components.rs similarity index 100% rename from crates/macros/cgp-macro-lib/src/entrypoints/delegate_components.rs rename to crates/macros/cgp-macro-lib/src/delegate_components.rs diff --git a/crates/macros/cgp-macro-lib/src/derive_build_field.rs b/crates/macros/cgp-macro-lib/src/derive_build_field.rs new file mode 100644 index 00000000..cc0ee473 --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/derive_build_field.rs @@ -0,0 +1,16 @@ +use cgp_macro_core::types::cgp_data::ItemCgpRecord; +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ItemStruct, parse2}; + +pub fn derive_build_field(body: TokenStream) -> syn::Result { + let item_struct: ItemStruct = parse2(body)?; + + let record = ItemCgpRecord { item_struct }; + + let items = record.to_build_field_items()?; + + Ok(quote! { + #( #items )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/derive_extract_field.rs b/crates/macros/cgp-macro-lib/src/derive_extract_field.rs new file mode 100644 index 00000000..fc74fe9c --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/derive_extract_field.rs @@ -0,0 +1,16 @@ +use cgp_macro_core::types::cgp_data::ItemCgpVariant; +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ItemEnum, parse2}; + +pub fn derive_extract_field(body: TokenStream) -> syn::Result { + let item_enum: ItemEnum = parse2(body)?; + + let variant = ItemCgpVariant { item_enum }; + + let items = variant.to_extract_field_items()?; + + Ok(quote! { + #( #items )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/derive_from_variant.rs b/crates/macros/cgp-macro-lib/src/derive_from_variant.rs new file mode 100644 index 00000000..46ac7d48 --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/derive_from_variant.rs @@ -0,0 +1,16 @@ +use cgp_macro_core::types::cgp_data::ItemCgpVariant; +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ItemEnum, parse2}; + +pub fn derive_from_variant(body: TokenStream) -> syn::Result { + let item_enum: ItemEnum = parse2(body)?; + + let variant = ItemCgpVariant { item_enum }; + + let item_impls = variant.to_from_variant_impls()?; + + Ok(quote! { + #( #item_impls )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/derive_has_field.rs b/crates/macros/cgp-macro-lib/src/derive_has_field.rs new file mode 100644 index 00000000..72116fbc --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/derive_has_field.rs @@ -0,0 +1,16 @@ +use cgp_macro_core::types::cgp_data::ItemCgpRecord; +use proc_macro2::TokenStream; +use quote::quote; +use syn::ItemStruct; + +pub fn derive_has_field(input: TokenStream) -> syn::Result { + let item_struct: ItemStruct = syn::parse2(input)?; + + let record = ItemCgpRecord { item_struct }; + + let item_impls = record.to_has_field_impls()?; + + Ok(quote! { + #( #item_impls )* + }) +} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/derive_has_fields.rs b/crates/macros/cgp-macro-lib/src/derive_has_fields.rs similarity index 68% rename from crates/macros/cgp-macro-lib/src/entrypoints/derive_has_fields.rs rename to crates/macros/cgp-macro-lib/src/derive_has_fields.rs index 538178ce..46f62186 100644 --- a/crates/macros/cgp-macro-lib/src/entrypoints/derive_has_fields.rs +++ b/crates/macros/cgp-macro-lib/src/derive_has_fields.rs @@ -1,16 +1,17 @@ +use cgp_macro_core::types::cgp_data::{ItemCgpRecord, derive_has_fields_impls_from_enum}; use proc_macro2::TokenStream; use quote::quote; use syn::{Error, Item, parse2}; -use crate::derive_has_fields::{ - derive_has_fields_impls_from_enum, derive_has_fields_impls_from_struct, -}; - pub fn derive_has_fields(body: TokenStream) -> syn::Result { let item: Item = parse2(body)?; let impls = match item { - Item::Struct(item_struct) => derive_has_fields_impls_from_struct(&item_struct)?, + Item::Struct(item_struct) => { + let record = ItemCgpRecord { item_struct }; + + record.to_has_fields_impls()? + } Item::Enum(item_enum) => derive_has_fields_impls_from_enum(&item_enum)?, _ => { return Err(Error::new_spanned( diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_data.rs b/crates/macros/cgp-macro-lib/src/entrypoints/cgp_data.rs deleted file mode 100644 index 66a2b80f..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_data.rs +++ /dev/null @@ -1,17 +0,0 @@ -use proc_macro2::TokenStream; -use syn::{Error, Item, parse2}; - -use crate::{derive_cgp_record_from_struct, derive_cgp_variant_from_enum}; - -pub fn derive_cgp_data(body: TokenStream) -> syn::Result { - let item: Item = parse2(body)?; - - match item { - Item::Struct(item_struct) => derive_cgp_record_from_struct(&item_struct), - Item::Enum(item_enum) => derive_cgp_variant_from_enum(&item_enum), - _ => Err(Error::new_spanned( - item, - "expect body to be either a struct or enum", - )), - } -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_inherit.rs b/crates/macros/cgp-macro-lib/src/entrypoints/cgp_inherit.rs deleted file mode 100644 index 4d375d6f..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_inherit.rs +++ /dev/null @@ -1,76 +0,0 @@ -use cgp_macro_core::types::generics::TypeGenerics; -use cgp_macro_core::types::ident::IdentWithTypeArgs; -use proc_macro2::TokenStream; -use quote::quote; -use syn::{Ident, ItemImpl, ItemStruct, parse_quote, parse2}; - -pub fn cgp_inherit(attr: TokenStream, body: TokenStream) -> syn::Result { - let context_struct: ItemStruct = parse2(body)?; - - let preset: IdentWithTypeArgs = parse2(attr)?; - - let type_generics = TypeGenerics::try_from(&context_struct.generics)?; - - let (delegate_impl, is_provider_impl) = - derive_delegate_preset(&context_struct.ident, &Some(type_generics), &preset)?; - - Ok(quote! { - #context_struct - - #delegate_impl - - #is_provider_impl - }) -} - -pub fn derive_delegate_preset( - provider_name: &Ident, - provider_generics: &Option, - preset: &IdentWithTypeArgs, -) -> syn::Result<(ItemImpl, ItemImpl)> { - let preset_name = &preset.ident; - let preset_generics = &preset.type_args; - - let provider_params = match provider_generics { - Some(generics) => { - let params = &generics.generics.params; - quote! { - , #params - } - } - None => quote! {}, - }; - - let preset_trait_name = quote! { - #preset_name :: IsPreset - }; - - let preset_provider_name = quote! { - #preset_name :: Components #preset_generics - }; - - let delegate_impl: ItemImpl = parse_quote! { - impl< __Name__ #provider_params > - DelegateComponent<__Name__> - for #provider_name #provider_generics - where - Self: #preset_trait_name < __Name__ >, - #preset_provider_name: DelegateComponent<__Name__>, - { - type Delegate = <#preset_provider_name as DelegateComponent<__Name__>>::Delegate; - } - }; - - let is_provider_impl: ItemImpl = parse_quote! { - impl<__Name__, __Context__, __Params__ #provider_params > - IsProviderFor<__Name__, __Context__, __Params__> - for #provider_name #provider_generics - where - Self: #preset_trait_name < __Name__ >, - #preset_provider_name: IsProviderFor<__Name__, __Context__, __Params__>, - { - } - }; - - Ok((delegate_impl, is_provider_impl)) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_preset.rs b/crates/macros/cgp-macro-lib/src/entrypoints/cgp_preset.rs deleted file mode 100644 index 089f78e5..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_preset.rs +++ /dev/null @@ -1,271 +0,0 @@ -use std::collections::HashSet; - -use cgp_macro_core::functions::to_snake_case_str; -use cgp_macro_core::types::empty_struct::EmptyStruct; -use cgp_macro_core::types::generics::ImplGenerics; -use cgp_macro_core::types::ident::IdentWithTypeArgs; -use proc_macro2::{Span, TokenStream}; -use quote::{ToTokens, TokenStreamExt, quote}; -use syn::punctuated::Punctuated; -use syn::token::{At, Comma}; -use syn::{GenericParam, Ident, ItemTrait, TypeParamBound, parse_quote, parse2}; - -use crate::delegate_components::impl_delegate_components; -use crate::parse::{DefinePreset, DelegateEntry}; -use crate::preset::{define_substitution_macro, impl_components_is_preset}; - -pub fn define_preset(body: TokenStream) -> syn::Result { - let ast: DefinePreset = syn::parse2(body)?; - - let delegate_entries: Punctuated, Comma> = ast - .delegate_entries - .iter() - .map(|entry| entry.entry.clone()) - .collect(); - - let mut parent_presets = ast.parent_presets.clone(); - - let mut remaining_parents = parent_presets - .iter_mut() - .filter(|parent| parent.has_expanded.is_none()); - - let m_parent = if let Some(parent_preset) = remaining_parents.next() { - parent_preset.has_expanded = Some(At(Span::call_site())); - Some(parent_preset.parent_type.clone()) - } else { - None - }; - - if let Some(parent) = m_parent { - let parent_ident = &parent.ident; - let parent_generics = &parent.type_args; - - let parent_components_ident = Ident::new( - &format!("__{parent_ident}Components__"), - parent_ident.span(), - ); - - let wrapper_attribute = match ast.provider_wrapper { - Some(wrapper) => quote! { - #[wrap_provider( #wrapper )] - }, - None => TokenStream::new(), - }; - - let preset_type_spec = &ast.preset; - - let mut overrides: Punctuated<&Ident, Comma> = Punctuated::default(); - - for entry in ast.delegate_entries.iter() { - if entry.is_override.is_some() { - for component in entry.entry.keys.iter() { - overrides.push(&component.ty.ident); - } - } - } - - let filter = if !overrides.is_empty() { - quote! { - [ #overrides ], - } - } else { - TokenStream::new() - }; - - let preset_entries = &ast.delegate_entries; - - let output = quote! { - use #parent_ident ::components::*; - - #parent_ident :: with_components! { - #filter - | #parent_components_ident | { - cgp_preset! { - #wrapper_attribute - #preset_type_spec: #parent_presets { - #parent_components_ident -> #parent_ident :: Components #parent_generics, - #preset_entries - } - } - } - } - }; - - return Ok(output); - } - - let provider_struct_name = Ident::new("Components", Span::call_site()); - - let preset_module_name = &ast.preset.name; - - let preset_generic_args = &ast.preset.generics; - - let preset_generics: ImplGenerics = syn::parse2(quote!( #preset_generic_args ))?; - - let provider_type = { - let type_generics = preset_generics.split_for_impl().1; - parse2(quote! { #provider_struct_name #type_generics })? - }; - - let preset_trait_name = Ident::new("IsPreset", Span::call_site()); - - let preset_trait: ItemTrait = parse_quote! { - #[doc(hidden)] - pub trait #preset_trait_name {} - }; - - let impl_delegate_items = { - let namespaces_preset_type = parse2(quote! { - #preset_module_name :: #provider_type - })?; - - let items = - impl_delegate_components(&namespaces_preset_type, &preset_generics, &delegate_entries)?; - - let mut stream = TokenStream::new(); - stream.append_all(items); - - stream - }; - - let impl_is_preset_items = impl_components_is_preset( - &preset_trait_name, - &provider_type, - &preset_generics, - &delegate_entries, - ); - - let provider_struct = EmptyStruct { - ident: provider_struct_name.clone(), - generics: preset_generics.generics.clone(), - }; - - let export_provider = match ast.provider_wrapper { - Some(wrapper) => { - let (impl_generics, type_generics, _) = preset_generics.generics.split_for_impl(); - - quote! { - pub type Provider #impl_generics = #wrapper < #provider_struct_name #type_generics >; - } - } - None => { - quote! { - pub use #provider_struct_name as Provider; - } - } - }; - - let mut mod_output = quote! { - #provider_struct - - #export_provider - - #preset_trait - }; - - mod_output.append_all(impl_is_preset_items); - - { - let with_components_macro_name = Ident::new( - &format!( - "with_{}", - to_snake_case_str(&preset_module_name.to_string()) - ), - Span::call_site(), - ); - - let all_components: Punctuated<_, Comma> = delegate_entries - .iter() - .flat_map(|entry| entry.keys.clone().into_iter()) - .collect(); - - let with_components_macro = define_substitution_macro( - &with_components_macro_name, - &all_components.to_token_stream(), - ); - - mod_output.extend(with_components_macro); - mod_output.extend(quote! { - pub use #with_components_macro_name as with_components; - }) - } - - let re_exports_mod = { - let mut parent_exports = TokenStream::new(); - - for parent in parent_presets.iter() { - let parent_ident = &parent.parent_type.ident; - parent_exports.append_all(quote! { - #[doc(hidden)] - #[doc(no_inline)] - pub use super:: #parent_ident ::components::*; - }); - } - - quote! { - #[doc(hidden)] - #[allow(unused_imports)] - mod re_exports { - #[doc(hidden)] - #[doc(no_inline)] - pub use super::super::super::re_exports::*; - - #[doc(hidden)] - #[doc(no_inline)] - pub use super::super::*; - - #parent_exports - } - } - }; - - let components_mod = { - let mut components: HashSet = HashSet::default(); - - for entry in delegate_entries.iter() { - for component in entry.keys.iter() { - let component_name = &component.ty.ident; - components.insert(component_name.clone()); - - for param in component.generics.generics.params.iter() { - if let GenericParam::Type(param) = param { - for bound in param.bounds.iter() { - if let TypeParamBound::Trait(bound) = bound - && let Some(segment) = bound.path.segments.first() - { - components.insert(segment.ident.clone()); - } - } - } - } - } - } - - let components_list: Punctuated = Punctuated::from_iter(components); - - quote! { - #[doc(hidden)] - pub mod components { - #[doc(hidden)] - #[doc(no_inline)] - pub use super::re_exports::{ #components_list }; - } - } - }; - - mod_output.append_all(re_exports_mod); - mod_output.append_all(components_mod); - - let output = quote! { - #impl_delegate_items - - #[allow(non_snake_case)] - pub mod #preset_module_name { - use super::*; - - #mod_output - } - }; - - Ok(output) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_record.rs b/crates/macros/cgp-macro-lib/src/entrypoints/cgp_record.rs deleted file mode 100644 index a1bb5c27..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_record.rs +++ /dev/null @@ -1,24 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{ItemStruct, parse2}; - -use crate::derive_build_field_from_struct; -use crate::derive_has_fields::derive_has_fields_impls_from_struct; -use crate::field::derive_has_field_impls_from_struct; - -pub fn derive_cgp_record(body: TokenStream) -> syn::Result { - let item_struct = parse2(body)?; - derive_cgp_record_from_struct(&item_struct) -} - -pub fn derive_cgp_record_from_struct(item_struct: &ItemStruct) -> syn::Result { - let has_field_impls = derive_has_field_impls_from_struct(item_struct)?; - let has_fields_impls = derive_has_fields_impls_from_struct(item_struct)?; - let build_field_impls = derive_build_field_from_struct(item_struct)?; - - Ok(quote! { - #( #has_field_impls )* - #( #has_fields_impls )* - #build_field_impls - }) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_variant.rs b/crates/macros/cgp-macro-lib/src/entrypoints/cgp_variant.rs deleted file mode 100644 index 9f578253..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/cgp_variant.rs +++ /dev/null @@ -1,23 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{ItemEnum, parse2}; - -use crate::derive_has_fields::derive_has_fields_impls_from_enum; -use crate::{derive_extract_field_from_enum, derive_from_variant_from_enum}; - -pub fn derive_cgp_variant(body: TokenStream) -> syn::Result { - let item_enum = parse2(body)?; - derive_cgp_variant_from_enum(&item_enum) -} - -pub fn derive_cgp_variant_from_enum(item_enum: &ItemEnum) -> syn::Result { - let has_fields = derive_has_fields_impls_from_enum(item_enum)?; - let extract_field = derive_extract_field_from_enum(item_enum)?; - let from_variant = derive_from_variant_from_enum(item_enum)?; - - Ok(quote! { - #( #has_fields )* - #extract_field - #from_variant - }) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/derive_build_field.rs b/crates/macros/cgp-macro-lib/src/entrypoints/derive_build_field.rs deleted file mode 100644 index 634f860a..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/derive_build_field.rs +++ /dev/null @@ -1,51 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{Ident, ItemStruct, parse2}; - -use crate::derive_builder::{ - derive_builder_struct, derive_finalize_build_impl, derive_has_builder_impl, - derive_has_field_impls, derive_into_builder_impl, derive_partial_data_impl, - derive_update_field_impls, -}; - -pub fn derive_build_field(body: TokenStream) -> syn::Result { - let context_struct: ItemStruct = parse2(body)?; - derive_build_field_from_struct(&context_struct) -} - -pub fn derive_build_field_from_struct(context_struct: &ItemStruct) -> syn::Result { - let context_ident = &context_struct.ident; - let builder_ident = Ident::new(&format!("__Partial{context_ident}"), context_ident.span()); - - let builder_struct = derive_builder_struct(context_struct, &builder_ident)?; - - let has_builder_impl = derive_has_builder_impl(context_struct, &builder_ident)?; - - let into_builder_impl = derive_into_builder_impl(context_struct, &builder_ident)?; - - let partial_data_impl = derive_partial_data_impl(context_struct, &builder_ident)?; - - let update_field_impls = derive_update_field_impls(context_struct, &builder_ident)?; - - let has_field_impls = derive_has_field_impls(context_struct, &builder_ident)?; - - let finalize_build_impl = derive_finalize_build_impl(context_struct, &builder_ident)?; - - let out = quote! { - #builder_struct - - #has_builder_impl - - #into_builder_impl - - #partial_data_impl - - #(#update_field_impls)* - - #(#has_field_impls)* - - #finalize_build_impl - }; - - Ok(out) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/derive_extract_field.rs b/crates/macros/cgp-macro-lib/src/entrypoints/derive_extract_field.rs deleted file mode 100644 index 18fdf711..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/derive_extract_field.rs +++ /dev/null @@ -1,65 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::{Ident, ItemEnum, parse2}; - -use crate::derive_extractor::{ - derive_extract_field_impls, derive_extractor_enum, derive_extractor_enum_ref, - derive_finalize_extract_impl, derive_has_extractor_impl, derive_has_extractor_mut_impl, - derive_has_extractor_ref_impl, derive_partial_data_impl, -}; - -pub fn derive_extract_field(body: TokenStream) -> syn::Result { - let context_enum: ItemEnum = parse2(body)?; - derive_extract_field_from_enum(&context_enum) -} - -pub fn derive_extract_field_from_enum(context_enum: &ItemEnum) -> syn::Result { - let context_ident = &context_enum.ident; - - let extractor_ident = Ident::new(&format!("__Partial{context_ident}"), context_ident.span()); - let extractor_enum = derive_extractor_enum(context_enum, &extractor_ident)?; - - let extractor_ref_ident = Ident::new( - &format!("__PartialRef{context_ident}"), - context_ident.span(), - ); - let extractor_ref_enum = derive_extractor_enum_ref(context_enum, &extractor_ref_ident)?; - - let has_extractor_impl = derive_has_extractor_impl(context_enum, &extractor_ident)?; - - let has_extractor_ref_impl = derive_has_extractor_ref_impl(context_enum, &extractor_ref_ident)?; - - let has_extractor_mut_impl = derive_has_extractor_mut_impl(context_enum, &extractor_ref_ident)?; - - let finalize_extract_impl = - derive_finalize_extract_impl(context_enum, &extractor_ident, false)?; - - let finalize_extract_ref_impl = - derive_finalize_extract_impl(context_enum, &extractor_ref_ident, true)?; - - let partial_data_impl = derive_partial_data_impl(context_enum, &extractor_ident, false)?; - let partial_ref_data_impl = derive_partial_data_impl(context_enum, &extractor_ref_ident, true)?; - - let extractor_impls = derive_extract_field_impls(context_enum, &extractor_ident, false)?; - let extractor_ref_impls = derive_extract_field_impls(context_enum, &extractor_ref_ident, true)?; - - let out = quote! { - #extractor_enum - #extractor_ref_enum - - #partial_data_impl - #partial_ref_data_impl - - #has_extractor_impl - #has_extractor_ref_impl - #has_extractor_mut_impl - - #finalize_extract_impl - #finalize_extract_ref_impl - - #(#extractor_impls)* - #(#extractor_ref_impls)* - }; - - Ok(out) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/mod.rs b/crates/macros/cgp-macro-lib/src/entrypoints/mod.rs deleted file mode 100644 index 18100ecc..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -mod blanket_trait; -mod cgp_auto_getter; -mod cgp_component; -mod cgp_data; -mod cgp_fn; -mod cgp_getter; -mod cgp_impl; -mod cgp_namespace; -mod cgp_new_provider; -mod cgp_provider; -mod cgp_record; -mod cgp_type; -mod cgp_variant; -mod check_components; -mod delegate_and_check_components; -mod delegate_components; -mod derive_build_field; -mod derive_extract_field; -mod derive_from_variant; -mod derive_has_fields; -mod path; - -pub use blanket_trait::*; -pub use cgp_auto_getter::*; -pub use cgp_component::*; -pub use cgp_data::*; -pub use cgp_fn::*; -pub use cgp_getter::*; -pub use cgp_impl::*; -pub use cgp_namespace::*; -pub use cgp_new_provider::*; -pub use cgp_provider::*; -pub use cgp_record::*; -pub use cgp_type::*; -pub use cgp_variant::*; -pub use check_components::*; -pub use delegate_and_check_components::*; -pub use delegate_components::*; -pub use derive_build_field::*; -pub use derive_extract_field::*; -pub use derive_from_variant::*; -pub use derive_has_fields::*; -pub use path::*; diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/re_export_imports.rs b/crates/macros/cgp-macro-lib/src/entrypoints/re_export_imports.rs deleted file mode 100644 index f6ede771..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/re_export_imports.rs +++ /dev/null @@ -1,56 +0,0 @@ -use proc_macro2::{Span, TokenStream}; -use quote::{TokenStreamExt, quote}; -use syn::token::Pub; -use syn::{Attribute, Ident, Item, ItemMod, ItemUse, Visibility, parse_quote, parse2}; - -pub fn re_export_imports(attrs: TokenStream, body: TokenStream) -> syn::Result { - let export_mod_name: Ident = if !attrs.is_empty() { - parse2(attrs)? - } else { - Ident::new("re_exports", Span::call_site()) - }; - - let mut re_exports: Vec = Vec::new(); - - let item_mod: ItemMod = parse2(body)?; - - let mod_name = &item_mod.ident; - - let doc_hidden: Attribute = parse_quote! { #[doc(hidden)] }; - let doc_no_inline: Attribute = parse_quote! { #[doc(no_inline)] }; - - if let Some(content) = &item_mod.content { - for item in content.1.iter() { - if let Item::Use(use_item) = item { - let mut re_export = use_item.clone(); - - re_export.vis = Visibility::Public(Pub(Span::call_site())); - re_export.attrs.push(doc_hidden.clone()); - re_export.attrs.push(doc_no_inline.clone()); - - re_exports.push(re_export); - } - } - } - - let mut mod_body = TokenStream::new(); - mod_body.append_all(re_exports); - - let export_mod: ItemMod = parse2(quote! { - #[doc(hidden)] - #[allow(unused_imports)] - mod #export_mod_name { - #mod_body - } - })?; - - let out = quote! { - #item_mod - - #export_mod - - pub use #mod_name ::*; - }; - - Ok(out) -} diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/replace_with.rs b/crates/macros/cgp-macro-lib/src/entrypoints/replace_with.rs deleted file mode 100644 index bf8d42b9..00000000 --- a/crates/macros/cgp-macro-lib/src/entrypoints/replace_with.rs +++ /dev/null @@ -1,16 +0,0 @@ -use proc_macro2::TokenStream; -use quote::quote; -use syn::punctuated::Punctuated; -use syn::token::Comma; - -use crate::for_each_replace::{ReplaceSpecs, replace_stream}; - -pub fn replace_with(tokens: TokenStream) -> syn::Result { - let specs: ReplaceSpecs = syn::parse2(tokens)?; - - let items: Punctuated = specs.replacements.into_iter().collect(); - - let tokens = quote! { [ #items ] }; - - Ok(replace_stream(&specs.target_ident, &tokens, specs.body)) -} diff --git a/crates/macros/cgp-macro-lib/src/lib.rs b/crates/macros/cgp-macro-lib/src/lib.rs index e709d0fe..c627dc19 100644 --- a/crates/macros/cgp-macro-lib/src/lib.rs +++ b/crates/macros/cgp-macro-lib/src/lib.rs @@ -1,24 +1,51 @@ -/*! - This is an internal crate used by the `cgp-macro` crate. We implement the - proc macros for `cgp-component` as a library, so that it can be more easily tested. - The constructs are then re-exported as proc macros in the `cgp-macro` crate, - which is defined as a proc macro crate. -*/ +mod blanket_trait; +mod cgp_auto_getter; +mod cgp_component; +mod cgp_data; +mod cgp_fn; +mod cgp_getter; +mod cgp_impl; +mod cgp_namespace; +mod cgp_new_provider; +mod cgp_provider; +mod cgp_record; +mod cgp_type; +mod cgp_variant; +mod check_components; +mod delegate_and_check_components; +mod delegate_components; +mod derive_build_field; +mod derive_extract_field; +mod derive_from_variant; +mod derive_has_field; +mod derive_has_fields; +mod path; +mod product; +mod sum; +mod symbol; -extern crate alloc; - -pub(crate) mod derive_builder; -pub(crate) mod derive_extractor; -pub(crate) mod derive_has_fields; -pub(crate) mod field; -pub(crate) mod product; -pub(crate) mod symbol; -pub(crate) mod type_component; - -mod entrypoints; - -pub use field::derive_has_field; -pub use product::{make_product_expr, make_product_type, make_sum_type}; -pub use symbol::make_symbol; - -pub use crate::entrypoints::*; +pub use blanket_trait::*; +pub use cgp_auto_getter::*; +pub use cgp_component::*; +pub use cgp_data::*; +pub use cgp_fn::*; +pub use cgp_getter::*; +pub use cgp_impl::*; +pub use cgp_namespace::*; +pub use cgp_new_provider::*; +pub use cgp_provider::*; +pub use cgp_record::*; +pub use cgp_type::*; +pub use cgp_variant::*; +pub use check_components::*; +pub use delegate_and_check_components::*; +pub use delegate_components::*; +pub use derive_build_field::*; +pub use derive_extract_field::*; +pub use derive_from_variant::*; +pub use derive_has_field::*; +pub use derive_has_fields::*; +pub use path::*; +pub use product::*; +pub use sum::*; +pub use symbol::*; diff --git a/crates/macros/cgp-macro-lib/src/entrypoints/path.rs b/crates/macros/cgp-macro-lib/src/path.rs similarity index 68% rename from crates/macros/cgp-macro-lib/src/entrypoints/path.rs rename to crates/macros/cgp-macro-lib/src/path.rs index c69a3272..b040e5b6 100644 --- a/crates/macros/cgp-macro-lib/src/entrypoints/path.rs +++ b/crates/macros/cgp-macro-lib/src/path.rs @@ -3,7 +3,8 @@ use proc_macro2::TokenStream; use quote::ToTokens; use syn::parse2; -pub fn path(body: TokenStream) -> syn::Result { +#[allow(non_snake_case)] +pub fn Path(body: TokenStream) -> syn::Result { let unipath: UniPath = parse2(body)?; Ok(unipath.to_token_stream()) } diff --git a/crates/macros/cgp-macro-lib/src/product.rs b/crates/macros/cgp-macro-lib/src/product.rs index c771b2f2..54a2ba83 100644 --- a/crates/macros/cgp-macro-lib/src/product.rs +++ b/crates/macros/cgp-macro-lib/src/product.rs @@ -1,45 +1,21 @@ +use cgp_macro_core::types::product::{ProductExpr, ProductType}; use proc_macro2::TokenStream; -use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::punctuated::Punctuated; -use syn::token::Comma; -use syn::{Expr, Type}; +use quote::ToTokens; +use syn::parse2; -pub struct ParsePunctuated(pub Punctuated); +#[allow(non_snake_case)] +pub fn Product(body: TokenStream) -> syn::Result { + let product_type: ProductType = parse2(body)?; -impl Parse for ParsePunctuated { - fn parse(input: ParseStream) -> syn::Result { - let types = Punctuated::parse_terminated(input)?; - Ok(ParsePunctuated(types)) - } -} - -pub fn make_product_type(input: TokenStream) -> TokenStream { - let types: ParsePunctuated = syn::parse2(input).unwrap(); + let evaluated = product_type.eval()?; - types.0.iter().rfold(quote! { ε }, |res, item| { - quote! { - π< #item , #res > - } - }) + Ok(evaluated.to_token_stream()) } -pub fn make_sum_type(input: TokenStream) -> TokenStream { - let types: ParsePunctuated = syn::parse2(input).unwrap(); - - types.0.iter().rfold(quote! { θ }, |res, item| { - quote! { - σ< #item , #res > - } - }) -} +pub fn product(body: TokenStream) -> syn::Result { + let product_expr: ProductExpr = parse2(body)?; -pub fn make_product_expr(input: TokenStream) -> TokenStream { - let types: ParsePunctuated = syn::parse2(input).unwrap(); + let evaluated = product_expr.eval()?; - types.0.iter().rfold(quote! { ε }, |res, item| { - quote! { - π( #item , #res ) - } - }) + Ok(evaluated.to_token_stream()) } diff --git a/crates/macros/cgp-macro-lib/src/sum.rs b/crates/macros/cgp-macro-lib/src/sum.rs new file mode 100644 index 00000000..b8ca75ec --- /dev/null +++ b/crates/macros/cgp-macro-lib/src/sum.rs @@ -0,0 +1,13 @@ +use cgp_macro_core::types::sum::SumType; +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::parse2; + +#[allow(non_snake_case)] +pub fn Sum(body: TokenStream) -> syn::Result { + let sum_type: SumType = parse2(body)?; + + let evaluated = sum_type.eval()?; + + Ok(evaluated.to_token_stream()) +} diff --git a/crates/macros/cgp-macro-lib/src/symbol.rs b/crates/macros/cgp-macro-lib/src/symbol.rs index c7b9ff51..ef86bf9c 100644 --- a/crates/macros/cgp-macro-lib/src/symbol.rs +++ b/crates/macros/cgp-macro-lib/src/symbol.rs @@ -1,27 +1,11 @@ -use proc_macro2::{Literal, Span, TokenStream}; -use quote::quote_spanned; -use syn::{LitStr, Type, parse2}; +use cgp_macro_core::types::field::Symbol; +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::parse2; -pub fn symbol_from_string(value: &str) -> syn::Result { - parse2(symbol_from_string_spanned(Span::call_site(), value)) -} - -pub fn symbol_from_string_spanned(span: Span, value: &str) -> TokenStream { - let mut chars = quote_spanned! { span => ε }; - - for c in value.chars().rev() { - chars = quote_spanned! { span => ζ< #c, #chars > }; - } - - let len = Literal::usize_unsuffixed(value.len()); - - quote_spanned! { span => ψ< #len, #chars > } -} - -pub fn make_symbol(input: TokenStream) -> syn::Result { - let literal: LitStr = syn::parse2(input)?; - - let symbol = symbol_from_string_spanned(literal.span(), &literal.value()); +#[allow(non_snake_case)] +pub fn Symbol(body: TokenStream) -> syn::Result { + let symbol: Symbol = parse2(body)?; - Ok(symbol) + Ok(symbol.to_token_stream()) } diff --git a/crates/macros/cgp-macro-lib/src/type_component/derive.rs b/crates/macros/cgp-macro-lib/src/type_component/derive.rs deleted file mode 100644 index 93eda744..00000000 --- a/crates/macros/cgp-macro-lib/src/type_component/derive.rs +++ /dev/null @@ -1,95 +0,0 @@ -use alloc::vec::Vec; - -use cgp_macro_core::types::cgp_component::CgpComponentArgs; -use cgp_macro_core::types::provider_impl::derive_is_provider_for; -use cgp_macro_core::visitors::get_bounds_and_replace_self_assoc_type; -use quote::{ToTokens, quote}; -use syn::spanned::Spanned; -use syn::{Error, Generics, ItemImpl, ItemTrait, TraitItem, TraitItemType, Type, parse2}; - -pub fn extract_item_type_from_trait(consumer_trait: &ItemTrait) -> syn::Result<&TraitItemType> { - if consumer_trait.items.len() != 1 { - return Err(Error::new( - consumer_trait.span(), - "type trait should contain exactly one associated type item", - )); - } - - match consumer_trait.items.first() { - Some(TraitItem::Type(item_type)) => { - if !item_type.generics.params.is_empty() || item_type.generics.where_clause.is_some() { - return Err(Error::new( - consumer_trait.span(), - "generic associated type and where clause are not supported", - )); - } - - Ok(item_type) - } - _ => Err(Error::new( - consumer_trait.span(), - "type trait should contain exactly one associated type item", - )), - } -} - -pub fn derive_type_providers( - spec: &CgpComponentArgs, - provider_trait: &ItemTrait, - item_type: &TraitItemType, -) -> syn::Result> { - let context_name = &spec.context_ident; - - let component_name: Type = { parse2(spec.component_name.to_token_stream())? }; - - let provider_trait_name = &provider_trait.ident; - - let (impl_generics, type_generics, where_clause) = provider_trait.generics.split_for_impl(); - - let impl_generics_params = parse2::(impl_generics.to_token_stream())?.params; - - let predicates = where_clause - .map(|c| c.predicates.clone()) - .unwrap_or_default(); - - let type_name = &item_type.ident; - - let type_bounds = get_bounds_and_replace_self_assoc_type(item_type); - - let use_type_impl: ItemImpl = parse2(quote! { - impl< #type_name, #impl_generics_params > - #provider_trait_name #type_generics - for UseType< #type_name > - where - #type_name: #type_bounds, - #predicates - { - type #type_name = #type_name; - } - })?; - - let use_type_is_provider_impl = derive_is_provider_for(&component_name, &use_type_impl)?; - - let with_provider_impl: ItemImpl = parse2(quote! { - impl< __Provider__, #type_name, #impl_generics_params > - #provider_trait_name #type_generics - for WithProvider< __Provider__ > - where - __Provider__: TypeProvider< #context_name, #component_name, Type = #type_name >, - #type_name: #type_bounds, - #predicates - { - type #type_name = #type_name; - } - })?; - - let with_provider_is_provider_impl = - derive_is_provider_for(&component_name, &with_provider_impl)?; - - Ok(vec![ - use_type_impl, - use_type_is_provider_impl, - with_provider_impl, - with_provider_is_provider_impl, - ]) -} diff --git a/crates/macros/cgp-macro-lib/src/type_component/mod.rs b/crates/macros/cgp-macro-lib/src/type_component/mod.rs deleted file mode 100644 index 61eca8a7..00000000 --- a/crates/macros/cgp-macro-lib/src/type_component/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod derive; - -pub use derive::*; diff --git a/crates/macros/cgp-macro-test-util-lib/src/entrypoints/mod.rs b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/mod.rs index 3ca8cda5..ac64fa9b 100644 --- a/crates/macros/cgp-macro-test-util-lib/src/entrypoints/mod.rs +++ b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/mod.rs @@ -11,6 +11,9 @@ mod snapshot_cgp_type; mod snapshot_check_components; mod snapshot_delegate_and_check_components; mod snapshot_delegate_components; +mod snapshot_derive_cgp_data; +mod snapshot_derive_has_field; +mod snapshot_derive_has_fields; pub use snapshot_blanket_trait::*; pub use snapshot_cgp_auto_getter::*; @@ -25,3 +28,6 @@ pub use snapshot_cgp_type::*; pub use snapshot_check_components::*; pub use snapshot_delegate_and_check_components::*; pub use snapshot_delegate_components::*; +pub use snapshot_derive_cgp_data::*; +pub use snapshot_derive_has_field::*; +pub use snapshot_derive_has_fields::*; diff --git a/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_cgp_data.rs b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_cgp_data.rs new file mode 100644 index 00000000..71f2881c --- /dev/null +++ b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_cgp_data.rs @@ -0,0 +1,25 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{Item, parse2}; + +use crate::keywords::CgpData; +use crate::types::DeriveMacroSnapshot; + +pub fn snapshot_derive_cgp_data(body: TokenStream) -> syn::Result { + let item: DeriveMacroSnapshot = parse2(body)?; + + let body = &item.body; + + let output = cgp_macro_lib::derive_cgp_data(quote! { + #[derive(CgpData)] + #body + })?; + + let wrapped = item.snapshot.wrap_output(output)?; + + Ok(quote! { + #body + + #wrapped + }) +} diff --git a/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_has_field.rs b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_has_field.rs new file mode 100644 index 00000000..6b7938f9 --- /dev/null +++ b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_has_field.rs @@ -0,0 +1,25 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{ItemStruct, parse2}; + +use crate::keywords::HasField; +use crate::types::DeriveMacroSnapshot; + +pub fn snapshot_derive_has_field(body: TokenStream) -> syn::Result { + let item: DeriveMacroSnapshot = parse2(body)?; + + let body = &item.body; + + let output = cgp_macro_lib::derive_has_field(quote! { + #[derive(HasField)] + #body + })?; + + let wrapped = item.snapshot.wrap_output(output)?; + + Ok(quote! { + #body + + #wrapped + }) +} diff --git a/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_has_fields.rs b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_has_fields.rs new file mode 100644 index 00000000..388a6290 --- /dev/null +++ b/crates/macros/cgp-macro-test-util-lib/src/entrypoints/snapshot_derive_has_fields.rs @@ -0,0 +1,25 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::{Item, parse2}; + +use crate::keywords::HasFields; +use crate::types::DeriveMacroSnapshot; + +pub fn snapshot_derive_has_fields(body: TokenStream) -> syn::Result { + let item: DeriveMacroSnapshot = parse2(body)?; + + let body = &item.body; + + let output = cgp_macro_lib::derive_has_fields(quote! { + #[derive(HasFields)] + #body + })?; + + let wrapped = item.snapshot.wrap_output(output)?; + + Ok(quote! { + #body + + #wrapped + }) +} diff --git a/crates/macros/cgp-macro-test-util-lib/src/keywords.rs b/crates/macros/cgp-macro-test-util-lib/src/keywords.rs index 54e1b3ef..6ae0ed20 100644 --- a/crates/macros/cgp-macro-test-util-lib/src/keywords.rs +++ b/crates/macros/cgp-macro-test-util-lib/src/keywords.rs @@ -1,5 +1,7 @@ use cgp_macro_core::define_keyword; +define_keyword!(Derive, "derive"); + define_keyword!(CgpComponent, "cgp_component"); define_keyword!(CgpAutoGetter, "cgp_auto_getter"); @@ -25,3 +27,9 @@ define_keyword!(CheckComponents, "check_components"); define_keyword!(DelegateAndCheckComponents, "delegate_and_check_components"); define_keyword!(BlanketTrait, "blanket_trait"); + +define_keyword!(HasField, "HasField"); + +define_keyword!(HasFields, "HasFields"); + +define_keyword!(CgpData, "CgpData"); diff --git a/crates/macros/cgp-macro-test-util-lib/src/types/derive_snapshot.rs b/crates/macros/cgp-macro-test-util-lib/src/types/derive_snapshot.rs new file mode 100644 index 00000000..0d190b9b --- /dev/null +++ b/crates/macros/cgp-macro-test-util-lib/src/types/derive_snapshot.rs @@ -0,0 +1,37 @@ +use core::marker::PhantomData; + +use cgp_macro_core::traits::IsKeyword; +use cgp_macro_core::types::keyword::Keyword; +use syn::parse::{Parse, ParseStream}; +use syn::parse2; +use syn::token::Pound; + +use crate::functions::parse_attribute_with_keyword; +use crate::keywords::Derive; +use crate::types::MacroSnapshot; + +pub struct DeriveMacroSnapshot { + pub body: Item, + pub snapshot: MacroSnapshot, + pub phantom: PhantomData, +} + +impl Parse for DeriveMacroSnapshot { + fn parse(input: ParseStream) -> syn::Result { + let _: Pound = input.parse()?; + + let attr = parse_attribute_with_keyword::(input)?; + + let _keyword: Keyword = parse2(attr)?; + + let body = input.parse()?; + + let snapshot = input.parse()?; + + Ok(Self { + body, + snapshot, + phantom: PhantomData, + }) + } +} diff --git a/crates/macros/cgp-macro-test-util-lib/src/types/mod.rs b/crates/macros/cgp-macro-test-util-lib/src/types/mod.rs index ffef9d53..ecdc00c4 100644 --- a/crates/macros/cgp-macro-test-util-lib/src/types/mod.rs +++ b/crates/macros/cgp-macro-test-util-lib/src/types/mod.rs @@ -1,7 +1,9 @@ mod attribute_snapshot; +mod derive_snapshot; mod macro_snapshot; mod statement_snapshot; pub use attribute_snapshot::*; +pub use derive_snapshot::*; pub use macro_snapshot::*; pub use statement_snapshot::*; diff --git a/crates/macros/cgp-macro-test-util/README.md b/crates/macros/cgp-macro-test-util/README.md index d007527a..3ecbf08f 100644 --- a/crates/macros/cgp-macro-test-util/README.md +++ b/crates/macros/cgp-macro-test-util/README.md @@ -5,7 +5,8 @@ Snapshot-testing macros for the CGP procedural macros. This crate exposes a family of `snapshot_*!` procedural macros that make it easy to write **golden / snapshot tests** for the code generated by the core CGP macros such as `#[cgp_component]`, `#[cgp_impl]`, `#[cgp_auto_getter]`, -`#[cgp_getter]`, `#[cgp_fn]`, and `delegate_components!`. +`#[cgp_getter]`, `#[cgp_fn]`, `#[derive(HasField)]`, and +`delegate_components!`. The snapshots are asserted using the [`insta`](https://insta.rs) crate. @@ -65,6 +66,9 @@ snapshot output is guaranteed to match what the production macros generate. | `snapshot_cgp_getter!` | `#[cgp_getter]` | | `snapshot_cgp_fn!` | `#[cgp_fn]` | | `snapshot_cgp_type!` | `#[cgp_type]` | +| `snapshot_derive_has_field!`| `#[derive(HasField)]` | +| `snapshot_derive_has_fields!`| `#[derive(HasFields)]` | +| `snapshot_derive_cgp_data!` | `#[derive(CgpData)]` | | `snapshot_delegate_components!` | `delegate_components!` | | `snapshot_check_components!` | `check_components!` | | `snapshot_delegate_and_check_components!` | `delegate_and_check_components!` | @@ -290,6 +294,141 @@ real macro. In addition to the usual `#[cgp_component]` output, the snapshot captures the extra `UseType` / `WithProvider` providers that `#[cgp_type]` generates. +### `snapshot_derive_has_field!` + +Wraps the `#[derive(HasField)]` derive macro. The item under test is the +`struct` definition written exactly as you would normally write it under +`#[derive(HasField)]`: + +```rust +snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Inner { + pub name: String, + } + + expand_inner(output) { + assert_snapshot!(output, @"...") + } +} +``` + +Unlike the attribute-based snapshot macros, the derive is re-emitted verbatim +above the struct (so the real `HasField` / `HasFieldMut` impls are still +generated by the compiler), while the snapshot captures the *derived* impls, +i.e. the `HasField` and `HasFieldMut` impls that `#[derive(HasField)]` produces +for each field. + +All struct shapes accepted by `#[derive(HasField)]` are accepted, since the body +is forwarded to the real derive verbatim: + +- **named-field structs**, keyed by `Symbol!("...")` field-name tags; +- **tuple structs**, keyed by `Index` positional tags; +- **structs with lifetime parameters**, whose lifetimes are propagated to the + generated impls. + +Because the snapshot macro emits a `#[test]` function, a `#[derive(HasField)]` +struct that currently lives *inside* a test function must be lifted out before it +can be wrapped — see [Migrating existing tests](#migrating-existing-tests). The +usual pattern is to move the struct into an inner `mod` alongside the snapshot +macro, and keep the original `#[test]` in that same module so its runtime +assertions are preserved. + +### `snapshot_derive_has_fields!` + +Wraps the `#[derive(HasFields)]` derive macro. The item under test is the type +definition written exactly as you would normally write it under +`#[derive(HasFields)]`, with any other derives kept alongside it: + +```rust +snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person { + pub name: String, + } + + expand_person(output) { + assert_snapshot!(output, @"...") + } +} +``` + +Like the other derive snapshot macros, the type is re-emitted verbatim with its +derives (so the compiler still generates the real impls), while the snapshot +captures the `HasFields` / `HasFieldsRef` / `FromFields` / `ToFields` / +`ToFieldsRef` impls that `#[derive(HasFields)]` produces. + +Both **`struct`s** and **`enum`s** are accepted: + +- For a **`struct`** (a *record*), the field list is a product type + (`Cons` / `Nil`), and the conversions destructure/build the struct fields. +- For an **`enum`** (a *variant*), the field list is a sum type + (`Either` / `Void`), and the conversions `match` over the variants. + +Generic type parameters and lifetimes are propagated to the generated impls. +As with the other derive snapshot macros, a `#[derive(HasFields)]` type that +currently lives *inside* a test function must be lifted out before it can be +wrapped — see [Migrating existing tests](#migrating-existing-tests). The usual +pattern is to move each type into its own inner `mod` alongside the snapshot +macro, and keep the original `#[test]` in that same module so its runtime +assertions are preserved. + +### `snapshot_derive_cgp_data!` + +Wraps the `#[derive(CgpData)]` derive macro. `CgpData` is the umbrella derive for +extensible data types: rather than a single trait, it generates the *entire* +field/variant toolkit for a `struct` or `enum`. The item under test is the type +definition written exactly as you would normally write it under +`#[derive(CgpData)]`, with any other derives kept alongside it: + +```rust +snapshot_derive_cgp_data! { + #[derive(CgpData)] + #[derive(Debug, Eq, PartialEq)] + pub struct FooBarBaz { + pub foo: u64, + pub bar: String, + pub baz: bool, + } + + expand_foo_bar_baz(output) { + assert_snapshot!(output, @"...") + } +} +``` + +Like `snapshot_derive_has_field!`, the type is re-emitted verbatim with its +derives (so the compiler still generates the real impls), while the snapshot +captures the *derived* impls that `#[derive(CgpData)]` produces. Because +`CgpData` generates a large amount of code, these snapshots are correspondingly +large — but that is precisely what makes them valuable as golden tests. + +What gets captured depends on whether the item is a `struct` (a *record*) or an +`enum` (a *variant*): + +- For a **record `struct`**, the snapshot covers the per-field `HasField` / + `HasFieldMut` impls, the `HasFields` / `HasFieldsRef` field-list impls, the + `FromFields` / `ToFields` / `ToFieldsRef` conversions, and the generated + `__Partial*` builder struct together with its `HasBuilder` / `IntoBuilder` / + `PartialData` / `FinalizeBuild` / `UpdateField` impls. +- For a **variant `enum`**, the snapshot covers the `HasFields` / + `HasFieldsRef` impls, the `FromFields` / `ToFields` / `ToFieldsRef` + conversions, the per-variant `FromVariant` impls, the generated `__Partial*` + / `__PartialRef*` enums, and the `HasExtractor` / `HasExtractorRef` / + `HasExtractorMut` / `FinalizeExtract` / `ExtractField` extractor impls. + +All shapes accepted by `#[derive(CgpData)]` are accepted, since the body is +forwarded to the real derive verbatim — including generic type parameters (with +`where` clauses), tuple structs keyed by `Index`, and generic enums. + +As with the other derive snapshot macros, a `#[derive(CgpData)]` type that +currently lives *inside* a test function must be lifted out before it can be +wrapped — see [Migrating existing tests](#migrating-existing-tests). When several +auxiliary types share a file, the usual convention is to wrap only the primary +type under test in `snapshot_derive_cgp_data!`, and leave the auxiliary fixture +types as plain `#[derive(CgpData)]` definitions. + ### `snapshot_delegate_components!` Here the *whole* `delegate_components! { ... }` invocation is written verbatim, @@ -424,9 +563,10 @@ showing a diff you can re-accept once you've confirmed the change is intended. When migrating an existing macro test, two situations come up: - **Module-level macro use** — wrap the existing `#[cgp_component]` / `#[cgp_impl]` - / `#[cgp_getter]` / `#[cgp_auto_getter]` / `delegate_components!` in the matching - `snapshot_*!` macro and append a test block. Nothing else needs to change, - since the snapshot macro re-emits the same code. + / `#[cgp_getter]` / `#[cgp_auto_getter]` / `#[derive(HasField)]` / + `delegate_components!` in the matching `snapshot_*!` macro and append a test + block. Nothing else needs to change, since the snapshot macro re-emits the same + code. - **CGP components defined *inside* a test function** — the snapshot macro generates a `#[test]` function, which cannot be nested inside another function. @@ -442,8 +582,6 @@ When migrating an existing macro test, two situations come up: ## Notes / limitations -- Snapshot macros exist only for the macros listed above. Other CGP macros - (`#[cgp_preset]`, …) are not (yet) snapshot-wrapped and are left as-is. - The pretty-printing is done with [`prettyplease`](https://crates.io/crates/prettyplease), and any macro-prelude noise is stripped beforehand diff --git a/crates/macros/cgp-macro-test-util/src/lib.rs b/crates/macros/cgp-macro-test-util/src/lib.rs index 1fa6ca61..99dc5b79 100644 --- a/crates/macros/cgp-macro-test-util/src/lib.rs +++ b/crates/macros/cgp-macro-test-util/src/lib.rs @@ -91,3 +91,24 @@ pub fn snapshot_blanket_trait(body: TokenStream) -> TokenStream { .unwrap_or_else(syn::Error::into_compile_error) .into() } + +#[proc_macro] +pub fn snapshot_derive_has_field(body: TokenStream) -> TokenStream { + entrypoints::snapshot_derive_has_field(body.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro] +pub fn snapshot_derive_has_fields(body: TokenStream) -> TokenStream { + entrypoints::snapshot_derive_has_fields(body.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro] +pub fn snapshot_derive_cgp_data(body: TokenStream) -> TokenStream { + entrypoints::snapshot_derive_cgp_data(body.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} diff --git a/crates/macros/cgp-macro/src/lib.rs b/crates/macros/cgp-macro/src/lib.rs index d85df306..aef7ae3a 100644 --- a/crates/macros/cgp-macro/src/lib.rs +++ b/crates/macros/cgp-macro/src/lib.rs @@ -751,17 +751,11 @@ pub fn blanket_trait(attr: TokenStream, item: TokenStream) -> TokenStream { ```rust,ignore type Hello = Char<'h', Char<'e', Char<'l', Char<'l', Char<'o', Nil>>>>>; ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - type Hello = ζ<'h', ζ<'e', ζ<'l', ζ<'l', ζ<'o', ε>>>>>; - ``` */ #[proc_macro] #[allow(non_snake_case)] pub fn Symbol(body: TokenStream) -> TokenStream { - cgp_macro_lib::make_symbol(body.into()) + cgp_macro_lib::Symbol(body.into()) .unwrap_or_else(syn::Error::into_compile_error) .into() } @@ -787,17 +781,20 @@ pub fn Symbol(body: TokenStream) -> TokenStream { ```rust,ignore type MyTypes = Cons>>; ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - type MyTypes = π>>; - ``` */ #[proc_macro] #[allow(non_snake_case)] pub fn Product(body: TokenStream) -> TokenStream { - cgp_macro_lib::make_product_type(body.into()).into() + cgp_macro_lib::Product(body.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() +} + +#[proc_macro] +pub fn product(body: TokenStream) -> TokenStream { + cgp_macro_lib::product(body.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } /** @@ -822,32 +819,23 @@ pub fn Product(body: TokenStream) -> TokenStream { ```rust,ignore type MyUnion = Either>>; ``` - - which would be shown with the shortened representation as: - - ```rust,ignore - type MyUnion = σ>>; - ``` */ #[proc_macro] #[allow(non_snake_case)] pub fn Sum(body: TokenStream) -> TokenStream { - cgp_macro_lib::make_sum_type(body.into()).into() + cgp_macro_lib::Sum(body.into()) + .unwrap_or_else(syn::Error::into_compile_error) + .into() } #[proc_macro] #[allow(non_snake_case)] pub fn Path(body: TokenStream) -> TokenStream { - cgp_macro_lib::path(body.into()) + cgp_macro_lib::Path(body.into()) .unwrap_or_else(syn::Error::into_compile_error) .into() } -#[proc_macro] -pub fn product(body: TokenStream) -> TokenStream { - cgp_macro_lib::make_product_expr(body.into()).into() -} - #[proc_macro_derive(HasField)] pub fn derive_fields(item: TokenStream) -> TokenStream { cgp_macro_lib::derive_has_field(item.into()) diff --git a/crates/main/cgp-base-extra/Cargo.toml b/crates/main/cgp-base-extra/Cargo.toml new file mode 100644 index 00000000..d382fb09 --- /dev/null +++ b/crates/main/cgp-base-extra/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "cgp-base-extra" +version = "0.7.0" +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } +authors = { workspace = true } +rust-version = { workspace = true } +keywords = { workspace = true } + +[dependencies] +cgp-base = { workspace = true } +cgp-type = { workspace = true } diff --git a/crates/main/cgp-base-extra/src/lib.rs b/crates/main/cgp-base-extra/src/lib.rs new file mode 100644 index 00000000..0683d3ad --- /dev/null +++ b/crates/main/cgp-base-extra/src/lib.rs @@ -0,0 +1,6 @@ +#![no_std] + +pub mod macro_prelude; + +pub use cgp_base::{base_types, component}; +pub use cgp_type as types; diff --git a/crates/main/cgp-base-extra/src/macro_prelude.rs b/crates/main/cgp-base-extra/src/macro_prelude.rs new file mode 100644 index 00000000..00048498 --- /dev/null +++ b/crates/main/cgp-base-extra/src/macro_prelude.rs @@ -0,0 +1,5 @@ +pub use cgp_base::macro_prelude::*; +pub use cgp_type::{ + HasType, TypeOf, TypeProvider, TypeProviderComponent, UseDelegatedType, UseType, + WithDelegatedType, WithType, +}; diff --git a/crates/main/cgp-base/src/lib.rs b/crates/main/cgp-base/src/lib.rs index 52669be9..b33a4759 100644 --- a/crates/main/cgp-base/src/lib.rs +++ b/crates/main/cgp-base/src/lib.rs @@ -1 +1,4 @@ pub mod macro_prelude; + +pub use cgp_base_types as base_types; +pub use cgp_component as component; diff --git a/crates/main/cgp-core/src/prelude.rs b/crates/main/cgp-core/src/prelude.rs index 59101d49..3f779db3 100644 --- a/crates/main/cgp-core/src/prelude.rs +++ b/crates/main/cgp-core/src/prelude.rs @@ -14,9 +14,7 @@ pub use cgp_field::traits::{ HasFieldsRef, IntoBuilder, MapType, MapTypeRef, MutFieldGetter, PartialData, ToFields, ToFieldsRef, UpdateField, }; -pub use cgp_field::types::{ - Chars, Cons, Either, Field, Index, Life, Nil, Symbol, Void, δ, ε, ζ, θ, π, σ, ψ, ω, -}; +pub use cgp_field::types::{Chars, Cons, Either, Field, Index, Life, Nil, Symbol, Void}; 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, diff --git a/crates/tests/cgp-tests/src/tests/async/spawn.rs b/crates/tests/cgp-tests/src/tests/async/spawn.rs index 5490700f..9921b3ba 100644 --- a/crates/tests/cgp-tests/src/tests/async/spawn.rs +++ b/crates/tests/cgp-tests/src/tests/async/spawn.rs @@ -104,22 +104,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + FooTypeProvider<__Context__>, {} - impl FooTypeProvider<__Context__> for UseType - where - Foo:, - { + impl FooTypeProvider<__Context__> for UseType { type Foo = Foo; } impl IsProviderFor - for UseType - where - Foo:, - {} + for UseType {} impl<__Provider__, Foo, __Context__> FooTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -130,7 +123,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, {} ") } @@ -206,22 +198,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + BarTypeProvider<__Context__>, {} - impl BarTypeProvider<__Context__> for UseType - where - Bar:, - { + impl BarTypeProvider<__Context__> for UseType { type Bar = Bar; } impl IsProviderFor - for UseType - where - Bar:, - {} + for UseType {} impl<__Provider__, Bar, __Context__> BarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, { type Bar = Bar; } @@ -232,7 +217,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, {} ") } diff --git a/crates/tests/cgp-tests/src/tests/check_components.rs b/crates/tests/cgp-tests/src/tests/check_components.rs index d4841431..ca8a84d6 100644 --- a/crates/tests/cgp-tests/src/tests/check_components.rs +++ b/crates/tests/cgp-tests/src/tests/check_components.rs @@ -79,22 +79,15 @@ mod basic_check_components { >>::Delegate: IsProviderFor + FooTypeProvider<__Context__>, {} - impl FooTypeProvider<__Context__> for UseType - where - Foo:, - { + impl FooTypeProvider<__Context__> for UseType { type Foo = Foo; } impl IsProviderFor - for UseType - where - Foo:, - {} + for UseType {} impl<__Provider__, Foo, __Context__> FooTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -105,7 +98,6 @@ mod basic_check_components { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, {} ") } @@ -181,22 +173,15 @@ mod basic_check_components { >>::Delegate: IsProviderFor + BarTypeProvider<__Context__>, {} - impl BarTypeProvider<__Context__> for UseType - where - Bar:, - { + impl BarTypeProvider<__Context__> for UseType { type Bar = Bar; } impl IsProviderFor - for UseType - where - Bar:, - {} + for UseType {} impl<__Provider__, Bar, __Context__> BarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, { type Bar = Bar; } @@ -207,7 +192,6 @@ mod basic_check_components { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, {} ") } @@ -872,22 +856,15 @@ mod generic_check_components { >>::Delegate: IsProviderFor + FooTypeProvider<__Context__>, {} - impl FooTypeProvider<__Context__> for UseType - where - Foo:, - { + impl FooTypeProvider<__Context__> for UseType { type Foo = Foo; } impl IsProviderFor - for UseType - where - Foo:, - {} + for UseType {} impl<__Provider__, Foo, __Context__> FooTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -898,7 +875,6 @@ mod generic_check_components { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, {} ") } @@ -974,22 +950,15 @@ mod generic_check_components { >>::Delegate: IsProviderFor + BarTypeProvider<__Context__>, {} - impl BarTypeProvider<__Context__> for UseType - where - Bar:, - { + impl BarTypeProvider<__Context__> for UseType { type Bar = Bar; } impl IsProviderFor - for UseType - where - Bar:, - {} + for UseType {} impl<__Provider__, Bar, __Context__> BarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, { type Bar = Bar; } @@ -1000,7 +969,6 @@ mod generic_check_components { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, {} ") } diff --git a/crates/tests/cgp-tests/src/tests/delegate_and_check_components.rs b/crates/tests/cgp-tests/src/tests/delegate_and_check_components.rs index 956e1967..30cb57f3 100644 --- a/crates/tests/cgp-tests/src/tests/delegate_and_check_components.rs +++ b/crates/tests/cgp-tests/src/tests/delegate_and_check_components.rs @@ -77,22 +77,15 @@ mod basic_delegate_and_check_components { >>::Delegate: IsProviderFor + NameTypeProvider<__Context__>, {} - impl NameTypeProvider<__Context__> for UseType - where - Name:, - { + impl NameTypeProvider<__Context__> for UseType { type Name = Name; } impl IsProviderFor - for UseType - where - Name:, - {} + for UseType {} impl<__Provider__, Name, __Context__> NameTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, { type Name = Name; } @@ -104,7 +97,6 @@ mod basic_delegate_and_check_components { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, {} ") } @@ -385,22 +377,15 @@ mod generic_delegate_and_check_components { >>::Delegate: IsProviderFor + NameTypeProvider<__Context__>, {} - impl NameTypeProvider<__Context__> for UseType - where - Name:, - { + impl NameTypeProvider<__Context__> for UseType { type Name = Name; } impl IsProviderFor - for UseType - where - Name:, - {} + for UseType {} impl<__Provider__, Name, __Context__> NameTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, { type Name = Name; } @@ -412,7 +397,6 @@ mod generic_delegate_and_check_components { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, {} ") } diff --git a/crates/tests/cgp-tests/src/tests/has_field/chain.rs b/crates/tests/cgp-tests/src/tests/has_field/chain.rs deleted file mode 100644 index c606a256..00000000 --- a/crates/tests/cgp-tests/src/tests/has_field/chain.rs +++ /dev/null @@ -1,302 +0,0 @@ -use core::marker::PhantomData; - -use cgp::core::field::impls::ChainGetters; -use cgp::prelude::*; - -#[test] -fn test_chained_getter() { - #[derive(HasField)] - pub struct Outer { - pub inner: Inner, - } - - #[derive(HasField)] - pub struct Inner { - pub name: String, - } - - let context = Outer { - inner: Inner { - name: "test".to_owned(), - }, - }; - - let name: &String = , UseField], - >>::get_field(&context, PhantomData::<()>); - assert_eq!(name, "test"); -} - -#[test] -fn test_chained_getter_with_outer_life() { - #[derive(HasField)] - pub struct Outer<'a> { - pub inner: &'a Inner, - } - - #[derive(HasField)] - pub struct Inner { - pub name: String, - } - - let context = Outer { - inner: &Inner { - name: "test".to_owned(), - }, - }; - - let name: &String = , UseField], - >>::get_field(&context, PhantomData::<()>); - assert_eq!(name, "test"); -} - -#[test] -fn test_chained_getter_with_inner_life() { - #[derive(HasField)] - pub struct Outer<'a> { - pub inner: Inner<'a>, - } - - #[derive(HasField)] - pub struct Inner<'a> { - pub name: &'a String, - } - - let context = Outer { - inner: Inner { - name: &"test".to_owned(), - }, - }; - - let name: &String = , UseField], - >>::get_field(&context, PhantomData::<()>); - - assert_eq!(name, "test"); -} - -mod deeply_nested_getter { - use cgp::core::field::impls::ChainGetters; - use cgp::prelude::*; - use cgp_macro_test_util::{snapshot_cgp_getter, snapshot_delegate_and_check_components}; - - #[derive(HasField)] - pub struct A { - pub b: B, - } - - #[derive(HasField)] - pub struct B { - pub c: C, - } - - #[derive(HasField)] - pub struct C { - pub d: D, - } - - #[derive(HasField)] - pub struct D { - pub name: String, - } - - #[derive(HasField)] - pub struct MyContext { - pub a: A, - } - - snapshot_cgp_getter! { - #[cgp_getter] - pub trait HasName { - fn name(&self) -> &str; - } - - expand_has_name(output) { - insta::assert_snapshot!(output, @" - pub trait HasName { - fn name(&self) -> &str; - } - impl<__Context__> HasName for __Context__ - where - __Context__: NameGetter<__Context__>, - { - fn name(&self) -> &str { - __Context__::name(self) - } - } - pub trait NameGetter<__Context__>: IsProviderFor { - fn name(__context__: &__Context__) -> &str; - } - impl<__Provider__, __Context__> NameGetter<__Context__> for __Provider__ - where - __Provider__: DelegateComponent - + IsProviderFor, - <__Provider__ as DelegateComponent< - NameGetterComponent, - >>::Delegate: NameGetter<__Context__>, - { - fn name(__context__: &__Context__) -> &str { - <__Provider__ as DelegateComponent< - NameGetterComponent, - >>::Delegate::name(__context__) - } - } - pub struct NameGetterComponent; - impl<__Context__> NameGetter<__Context__> for UseContext - where - __Context__: HasName, - { - fn name(__context__: &__Context__) -> &str { - __Context__::name(__context__) - } - } - impl<__Context__> IsProviderFor for UseContext - where - __Context__: HasName, - {} - impl<__Context__, __Components__, __Path__> NameGetter<__Context__> - for RedirectLookup<__Components__, __Path__> - where - __Components__: DelegateComponent<__Path__>, - <__Components__ as DelegateComponent<__Path__>>::Delegate: NameGetter<__Context__>, - { - fn name(__context__: &__Context__) -> &str { - <__Components__ as DelegateComponent<__Path__>>::Delegate::name(__context__) - } - } - impl< - __Context__, - __Components__, - __Path__, - > IsProviderFor - for RedirectLookup<__Components__, __Path__> - where - __Components__: DelegateComponent<__Path__>, - <__Components__ as DelegateComponent< - __Path__, - >>::Delegate: IsProviderFor - + NameGetter<__Context__>, - {} - impl<__Context__> NameGetter<__Context__> for UseFields - where - __Context__: HasField< - Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, - Value = String, - >, - { - fn name(__context__: &__Context__) -> &str { - __context__ - .get_field( - ::core::marker::PhantomData::< - Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, - >, - ) - .as_str() - } - } - impl<__Context__> IsProviderFor for UseFields - where - __Context__: HasField< - Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, - Value = String, - >, - {} - impl<__Context__, __Tag__> NameGetter<__Context__> for UseField<__Tag__> - where - __Context__: HasField<__Tag__, Value = String>, - { - fn name(__context__: &__Context__) -> &str { - __context__.get_field(::core::marker::PhantomData::<__Tag__>).as_str() - } - } - impl<__Context__, __Tag__> IsProviderFor - for UseField<__Tag__> - where - __Context__: HasField<__Tag__, Value = String>, - {} - impl<__Context__, __Provider__> NameGetter<__Context__> for WithProvider<__Provider__> - where - __Provider__: FieldGetter<__Context__, NameGetterComponent, Value = String>, - { - fn name(__context__: &__Context__) -> &str { - __Provider__::get_field( - __context__, - ::core::marker::PhantomData::, - ) - .as_str() - } - } - impl<__Context__, __Provider__> IsProviderFor - for WithProvider<__Provider__> - where - __Provider__: FieldGetter<__Context__, NameGetterComponent, Value = String>, - {} - ") - } - } - - snapshot_delegate_and_check_components! { - delegate_and_check_components! { - MyContext { - NameGetterComponent: WithProvider< - ChainGetters, - UseField, - UseField, - UseField, - UseField - ]>> - } - } - - expand_my_context(output) { - insta::assert_snapshot!(output, @r#" - impl DelegateComponent for MyContext { - type Delegate = WithProvider< - ChainGetters< - Product![ - UseField < Symbol!("a") >, UseField < Symbol!("b") >, UseField < - Symbol!("c") >, UseField < Symbol!("d") >, UseField < Symbol!("name") > - ], - >, - >; - } - impl<__Context__, __Params__> IsProviderFor - for MyContext - where - WithProvider< - ChainGetters< - Product![ - UseField < Symbol!("a") >, UseField < Symbol!("b") >, UseField < - Symbol!("c") >, UseField < Symbol!("d") >, UseField < Symbol!("name") > - ], - >, - >: IsProviderFor, - {} - trait __CanUseMyContext< - __Component__, - __Params__: ?Sized, - >: CanUseComponent<__Component__, __Params__> {} - impl __CanUseMyContext for MyContext {} - "#) - } - } - - #[test] - fn test_deeply_nested_getter() { - let context = MyContext { - a: A { - b: B { - c: C { - d: D { - name: "test".to_owned(), - }, - }, - }, - }, - }; - - assert_eq!(context.name(), "test"); - } -} diff --git a/crates/tests/cgp-tests/src/tests/has_field/index.rs b/crates/tests/cgp-tests/src/tests/has_field/index.rs deleted file mode 100644 index 9c5d58e9..00000000 --- a/crates/tests/cgp-tests/src/tests/has_field/index.rs +++ /dev/null @@ -1,18 +0,0 @@ -use cgp::prelude::*; - -#[derive(HasField)] -pub struct Context(pub String, pub u64); - -pub trait CheckHasFieldImpls: - HasField, Value = String> + HasField, Value = u64> -{ -} - -impl CheckHasFieldImpls for Context {} - -#[test] -fn test_has_field_index() { - let context = Context("test".to_owned(), 1); - assert_eq!(context.get_field(PhantomData::>), &"test"); - assert_eq!(context.get_field(PhantomData::>), &1); -} diff --git a/crates/tests/cgp-tests/src/tests/has_field/life.rs b/crates/tests/cgp-tests/src/tests/has_field/life.rs deleted file mode 100644 index 80bb2657..00000000 --- a/crates/tests/cgp-tests/src/tests/has_field/life.rs +++ /dev/null @@ -1,15 +0,0 @@ -use core::marker::PhantomData; - -use cgp::prelude::*; - -#[test] -fn test_context_with_lifetime_field() { - #[derive(HasField)] - pub struct Context<'a> { - pub name: &'a str, - } - - let context = Context { name: "test" }; - - assert_eq!(context.get_field(PhantomData), &"test"); -} diff --git a/crates/tests/cgp-tests/src/tests/has_fields/enum_fields.rs b/crates/tests/cgp-tests/src/tests/has_fields/enum_fields.rs deleted file mode 100644 index acf01ca0..00000000 --- a/crates/tests/cgp-tests/src/tests/has_fields/enum_fields.rs +++ /dev/null @@ -1,75 +0,0 @@ -use cgp::prelude::*; - -#[test] -fn test_simple_enum() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub enum Person { - Anonymous(u32), - Named(String), - } - - { - let person_a1 = Person::Anonymous(42); - - let person_a2 = person_a1.clone().to_fields(); - assert_eq!(person_a2, Either::Left(42.into())); - - let person_a3 = Person::from_fields(person_a2); - assert_eq!(person_a3, person_a1); - - let person_a4 = person_a1.to_fields_ref(); - assert_eq!(person_a4, Either::Left((&42).into())); - } - - { - let name = "Alice".to_owned(); - - let person_b1 = Person::Named(name.clone()); - - let person_b2 = person_b1.clone().to_fields(); - assert_eq!(person_b2, Either::Right(Either::Left(name.clone().into()))); - - let person_b3 = Person::from_fields(person_b2); - assert_eq!(person_b3, person_b1); - - let person_b4 = person_b1.to_fields_ref(); - assert_eq!(person_b4, Either::Right(Either::Left((&name).into()))); - } -} - -#[test] -fn test_generic_enum() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub enum Person<'a, Name> { - Anonymous(u32), - Named(&'a Name), - } - - { - let person_a1: Person = Person::Anonymous(42); - - let person_a2 = person_a1.clone().to_fields(); - assert_eq!(person_a2, Either::Left(42.into())); - - let person_a3 = Person::from_fields(person_a2); - assert_eq!(person_a3, person_a1); - - let person_a4 = person_a1.to_fields_ref(); - assert_eq!(person_a4, Either::Left((&42).into())); - } - - { - let name = "Alice".to_owned(); - - let person_b1 = Person::Named(&name); - - let person_b2 = person_b1.clone().to_fields(); - assert_eq!(person_b2, Either::Right(Either::Left((&name).into()))); - - let person_b3 = Person::from_fields(person_b2); - assert_eq!(person_b3, person_b1); - - let person_b4 = person_b1.to_fields_ref(); - assert_eq!(person_b4, Either::Right(Either::Left((&&name).into()))); - } -} diff --git a/crates/tests/cgp-tests/src/tests/has_fields/struct_fields.rs b/crates/tests/cgp-tests/src/tests/has_fields/struct_fields.rs deleted file mode 100644 index 14663aac..00000000 --- a/crates/tests/cgp-tests/src/tests/has_fields/struct_fields.rs +++ /dev/null @@ -1,149 +0,0 @@ -use core::fmt::Display; - -use cgp::prelude::*; - -#[test] -fn test_single_named_field() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub struct Person { - pub name: String, - } - - let name = "Alice".to_owned(); - - let person1 = Person { name: name.clone() }; - - let product = person1.clone().to_fields(); - assert_eq!(product, Cons(name.clone().into(), Nil)); - - let product_ref = person1.to_fields_ref(); - assert_eq!(product_ref, Cons((&name).into(), Nil)); - - let person2 = Person::from_fields(product); - - assert_eq!(person1, person2); -} - -#[test] -fn test_two_named_field() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub struct Person { - pub name: String, - pub age: u8, - } - - let name = "Alice".to_owned(); - - let person1 = Person { - name: name.clone(), - age: 32, - }; - - let product = person1.clone().to_fields(); - assert_eq!(product, Cons(name.clone().into(), Cons(32.into(), Nil))); - - let product_ref = person1.to_fields_ref(); - assert_eq!(product_ref, Cons((&name).into(), Cons((&32).into(), Nil))); - - let person2 = Person::from_fields(product); - - assert_eq!(person1, person2); -} - -#[test] -fn test_generic_struct() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub struct Person - where - Name: Display, - { - pub name: Name, - pub age: u8, - } - - let name = "Alice".to_owned(); - - let person1 = Person { - name: name.clone(), - age: 32, - }; - - let product = person1.clone().to_fields(); - assert_eq!(product, Cons(name.clone().into(), Cons(32.into(), Nil))); - - let product_ref = person1.to_fields_ref(); - assert_eq!(product_ref, Cons((&name).into(), Cons((&32).into(), Nil))); - - let person2 = Person::from_fields(product); - - assert_eq!(person1, person2); -} - -#[test] -fn test_generic_lifetime_struct() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub struct Person<'a, Name> - where - Name: Display, - { - pub name: &'a Name, - pub age: &'a u8, - } - - let name = "Alice".to_owned(); - - let person1 = Person { - name: &name, - age: &32, - }; - - let product = person1.clone().to_fields(); - assert_eq!(product, Cons((&name).into(), Cons((&32).into(), Nil))); - - let product_ref = person1.to_fields_ref(); - assert_eq!(product_ref, Cons((&&name).into(), Cons((&&32).into(), Nil))); - - let person2 = Person::from_fields(product); - - assert_eq!(person1, person2); -} - -#[test] -fn test_single_unnamed_field() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub struct Person(String); - - let name = "Alice".to_owned(); - - let person1 = Person(name.clone()); - - let product = person1.clone().to_fields(); - assert_eq!(product, name.clone()); - - let product_ref = person1.to_fields_ref(); - assert_eq!(product_ref, &name); - - let person2 = Person::from_fields(product); - - assert_eq!(person1, person2); -} - -#[test] -fn test_single_unnamed_multi_field() { - #[derive(Clone, Debug, Eq, PartialEq, HasFields)] - pub struct Person(String, u8); - - let name = "Alice".to_owned(); - - let person1 = Person(name.clone(), 32); - - let product = person1.clone().to_fields(); - assert_eq!(product, Cons(name.clone().into(), Cons(32.into(), Nil))); - - let product_ref = person1.to_fields_ref(); - assert_eq!(product_ref, Cons((&name).into(), Cons((&32).into(), Nil))); - - let person2 = Person::from_fields(product); - - assert_eq!(person1, person2); -} diff --git a/crates/tests/cgp-tests/src/tests/mod.rs b/crates/tests/cgp-tests/src/tests/mod.rs index cfb6745f..e9213554 100644 --- a/crates/tests/cgp-tests/src/tests/mod.rs +++ b/crates/tests/cgp-tests/src/tests/mod.rs @@ -3,8 +3,6 @@ pub mod blanket_trait; pub mod check_components; pub mod compose; pub mod delegate_and_check_components; -pub mod has_field; -pub mod has_fields; pub mod monad; pub mod symbol; pub mod use_delegate; diff --git a/crates/tests/cgp-tests/src/tests/use_delegate/getter.rs b/crates/tests/cgp-tests/src/tests/use_delegate/getter.rs index 9a67e143..22568798 100644 --- a/crates/tests/cgp-tests/src/tests/use_delegate/getter.rs +++ b/crates/tests/cgp-tests/src/tests/use_delegate/getter.rs @@ -141,10 +141,7 @@ snapshot_cgp_type! { __Delegate__: IsProviderFor + FooTypeProviderAt<__Context__, I, J>, {} - impl FooTypeProviderAt<__Context__, I, J> for UseType - where - Foo:, - { + impl FooTypeProviderAt<__Context__, I, J> for UseType { type Foo = Foo; } impl< @@ -152,15 +149,11 @@ snapshot_cgp_type! { __Context__, I, J, - > IsProviderFor for UseType - where - Foo:, - {} + > IsProviderFor for UseType {} impl<__Provider__, Foo, __Context__, I, J> FooTypeProviderAt<__Context__, I, J> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderAtComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -174,7 +167,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderAtComponent, Type = Foo>, - Foo:, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/extend.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/extend.rs index 531546c6..abbb729e 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/extend.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/extend.rs @@ -74,22 +74,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -101,7 +94,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type.rs index 91d804fa..0fa7e5d8 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type.rs @@ -74,22 +74,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -101,7 +94,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type_equality.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type_equality.rs index bf76eb08..2b8dde10 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type_equality.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/foreign_type_equality.rs @@ -1,4 +1,3 @@ -use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_fn, snapshot_cgp_type}; snapshot_cgp_type! { @@ -72,22 +71,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -99,7 +91,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } @@ -190,8 +181,8 @@ snapshot_cgp_type! { impl<__Provider__, Types, __Context__> TypesTypeProvider<__Context__> for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, TypesTypeProviderComponent, Type = Types>, Types: HasScalarType, + __Provider__: TypeProvider<__Context__, TypesTypeProviderComponent, Type = Types>, { type Types = Types; } @@ -202,8 +193,8 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, TypesTypeProviderComponent, Type = Types>, Types: HasScalarType, + __Provider__: TypeProvider<__Context__, TypesTypeProviderComponent, Type = Types>, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/nested_foreign_type.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/nested_foreign_type.rs index f9669016..0fc3bb9c 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/nested_foreign_type.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/nested_foreign_type.rs @@ -74,22 +74,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -101,7 +94,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } @@ -178,22 +170,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + TypesTypeProvider<__Context__>, {} - impl TypesTypeProvider<__Context__> for UseType - where - Types:, - { + impl TypesTypeProvider<__Context__> for UseType { type Types = Types; } impl IsProviderFor - for UseType - where - Types:, - {} + for UseType {} impl<__Provider__, Types, __Context__> TypesTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, TypesTypeProviderComponent, Type = Types>, - Types:, { type Types = Types; } @@ -205,7 +190,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, TypesTypeProviderComponent, Type = Types>, - Types:, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/type_equality.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/type_equality.rs index 96cbf81b..0e226cec 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/type_equality.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/type_equality.rs @@ -1,6 +1,5 @@ use std::fmt::Display; -use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_fn, snapshot_cgp_type}; snapshot_cgp_type! { @@ -74,22 +73,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -101,7 +93,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type.rs index 04b4abee..307f7f6b 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type.rs @@ -89,8 +89,8 @@ snapshot_cgp_type! { impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Mul + Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, { type Scalar = Scalar; } @@ -101,8 +101,8 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Mul + Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, {} ") } diff --git a/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type_alias.rs b/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type_alias.rs index 8e85f7c5..b813d18a 100644 --- a/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type_alias.rs +++ b/crates/tests/cgp-tests/tests/cgp_fn_tests/use_type_alias.rs @@ -1,6 +1,5 @@ use std::ops::Mul; -use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_fn, snapshot_cgp_type}; snapshot_cgp_type! { @@ -74,22 +73,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -101,7 +93,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/component_tests/abstract_types/basic.rs b/crates/tests/cgp-tests/tests/component_tests/abstract_types/basic.rs index 3be3ab9c..240c0c73 100644 --- a/crates/tests/cgp-tests/tests/component_tests/abstract_types/basic.rs +++ b/crates/tests/cgp-tests/tests/component_tests/abstract_types/basic.rs @@ -76,22 +76,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -103,7 +96,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/component_tests/abstract_types/extend.rs b/crates/tests/cgp-tests/tests/component_tests/abstract_types/extend.rs index ecd29bd3..d3a65396 100644 --- a/crates/tests/cgp-tests/tests/component_tests/abstract_types/extend.rs +++ b/crates/tests/cgp-tests/tests/component_tests/abstract_types/extend.rs @@ -76,22 +76,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -103,7 +96,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/component_tests/abstract_types/foreign.rs b/crates/tests/cgp-tests/tests/component_tests/abstract_types/foreign.rs index 94c983d1..eb97e401 100644 --- a/crates/tests/cgp-tests/tests/component_tests/abstract_types/foreign.rs +++ b/crates/tests/cgp-tests/tests/component_tests/abstract_types/foreign.rs @@ -76,22 +76,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ScalarTypeProvider<__Context__>, {} - impl ScalarTypeProvider<__Context__> for UseType - where - Scalar:, - { + impl ScalarTypeProvider<__Context__> for UseType { type Scalar = Scalar; } impl IsProviderFor - for UseType - where - Scalar:, - {} + for UseType {} impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, { type Scalar = Scalar; } @@ -103,7 +96,6 @@ snapshot_cgp_type! { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, - Scalar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/component_tests/abstract_types/self_referential.rs b/crates/tests/cgp-tests/tests/component_tests/abstract_types/self_referential.rs index 8c0dba27..a99144ac 100644 --- a/crates/tests/cgp-tests/tests/component_tests/abstract_types/self_referential.rs +++ b/crates/tests/cgp-tests/tests/component_tests/abstract_types/self_referential.rs @@ -88,8 +88,8 @@ snapshot_cgp_type! { impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Mul + Clone, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, { type Scalar = Scalar; } @@ -100,8 +100,8 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Mul + Clone, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, {} ") } diff --git a/crates/tests/cgp-tests/tests/component_tests/cgp_component/constant.rs b/crates/tests/cgp-tests/tests/component_tests/cgp_component/constant.rs index 85d6117a..8e5a3319 100644 --- a/crates/tests/cgp-tests/tests/component_tests/cgp_component/constant.rs +++ b/crates/tests/cgp-tests/tests/component_tests/cgp_component/constant.rs @@ -140,22 +140,15 @@ mod generic_const { >>::Delegate: IsProviderFor + UnitTypeProvider<__Context__>, {} - impl UnitTypeProvider<__Context__> for UseType - where - Unit:, - { + impl UnitTypeProvider<__Context__> for UseType { type Unit = Unit; } impl IsProviderFor - for UseType - where - Unit:, - {} + for UseType {} impl<__Provider__, Unit, __Context__> UnitTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, UnitTypeProviderComponent, Type = Unit>, - Unit:, { type Unit = Unit; } @@ -167,7 +160,6 @@ mod generic_const { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, UnitTypeProviderComponent, Type = Unit>, - Unit:, {} ") } diff --git a/crates/tests/cgp-tests/tests/component_tests/cgp_component/sized.rs b/crates/tests/cgp-tests/tests/component_tests/cgp_component/sized.rs index 7db71c9a..746e1189 100644 --- a/crates/tests/cgp-tests/tests/component_tests/cgp_component/sized.rs +++ b/crates/tests/cgp-tests/tests/component_tests/cgp_component/sized.rs @@ -81,25 +81,18 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + ProvideFooType<__Context__, T>, {} - impl ProvideFooType<__Context__, T> for UseType - where - Foo:, - { + impl ProvideFooType<__Context__, T> for UseType { type Foo = Foo; } impl< Foo, __Context__, T: ?Sized, - > IsProviderFor for UseType - where - Foo:, - {} + > IsProviderFor for UseType {} impl<__Provider__, Foo, __Context__, T: ?Sized> ProvideFooType<__Context__, T> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ProvideFooTypeComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -111,7 +104,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, ProvideFooTypeComponent, Type = Foo>, - Foo:, {} ") } diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/chain.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/chain.rs new file mode 100644 index 00000000..ad150600 --- /dev/null +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/chain.rs @@ -0,0 +1,634 @@ +pub mod chained_getter { + use core::marker::PhantomData; + + use cgp::core::field::impls::ChainGetters; + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_field; + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Inner { + pub name: String, + } + + expand_inner(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>>> for Inner { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &Self::Value { + &self.name + } + } + impl HasFieldMut>>>>> + for Inner { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &mut Self::Value { + &mut self.name + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Outer { + pub inner: Inner, + } + + expand_outer(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>>>> + for Outer { + type Value = Inner; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + >, + ) -> &Self::Value { + &self.inner + } + } + impl HasFieldMut< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + > for Outer { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + >, + ) -> &mut Self::Value { + &mut self.inner + } + } + ") + } + } + + #[test] + fn test_chained_getter() { + let context = Outer { + inner: Inner { + name: "test".to_owned(), + }, + }; + + let name: &String = , UseField], + >>::get_field(&context, PhantomData::<()>); + assert_eq!(name, "test"); + } +} + +mod chained_getter_with_outer_life { + use core::marker::PhantomData; + + use cgp::core::field::impls::ChainGetters; + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_field; + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Outer<'a> { + pub inner: &'a Inner, + } + + expand_outer(output) { + insta::assert_snapshot!(output, @" + impl< + 'a, + > HasField>>>>>> + for Outer<'a> { + type Value = &'a Inner; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + >, + ) -> &Self::Value { + &self.inner + } + } + impl< + 'a, + > HasFieldMut>>>>>> + for Outer<'a> { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + >, + ) -> &mut Self::Value { + &mut self.inner + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Inner { + pub name: String, + } + + expand_inner(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>>> for Inner { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &Self::Value { + &self.name + } + } + impl HasFieldMut>>>>> + for Inner { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &mut Self::Value { + &mut self.name + } + } + ") + } + } + + #[test] + fn test_chained_getter_with_outer_life() { + let context = Outer { + inner: &Inner { + name: "test".to_owned(), + }, + }; + + let name: &String = , UseField], + >>::get_field(&context, PhantomData::<()>); + assert_eq!(name, "test"); + } +} + +mod chained_getter_with_inner_life { + use core::marker::PhantomData; + + use cgp::core::field::impls::ChainGetters; + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_field; + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Outer<'a> { + pub inner: Inner<'a>, + } + + expand_outer(output) { + insta::assert_snapshot!(output, @" + impl< + 'a, + > HasField>>>>>> + for Outer<'a> { + type Value = Inner<'a>; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + >, + ) -> &Self::Value { + &self.inner + } + } + impl< + 'a, + > HasFieldMut>>>>>> + for Outer<'a> { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<5, Chars<'i', Chars<'n', Chars<'n', Chars<'e', Chars<'r', Nil>>>>>>, + >, + ) -> &mut Self::Value { + &mut self.inner + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Inner<'a> { + pub name: &'a String, + } + + expand_inner(output) { + insta::assert_snapshot!(output, @" + impl<'a> HasField>>>>> + for Inner<'a> { + type Value = &'a String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &Self::Value { + &self.name + } + } + impl<'a> HasFieldMut>>>>> + for Inner<'a> { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &mut Self::Value { + &mut self.name + } + } + ") + } + } + + #[test] + fn test_chained_getter_with_inner_life() { + let context = Outer { + inner: Inner { + name: &"test".to_owned(), + }, + }; + + let name: &String = , UseField], + >>::get_field(&context, PhantomData::<()>); + + assert_eq!(name, "test"); + } +} + +mod deeply_nested_getter { + use cgp::core::field::impls::ChainGetters; + use cgp::prelude::*; + use cgp_macro_test_util::{ + snapshot_cgp_getter, snapshot_delegate_and_check_components, snapshot_derive_has_field, + }; + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct A { + pub b: B, + } + + expand_a(output) { + insta::assert_snapshot!(output, @" + impl HasField>> for A { + type Value = B; + fn get_field( + &self, + key: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.b + } + } + impl HasFieldMut>> for A { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>>, + ) -> &mut Self::Value { + &mut self.b + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct B { + pub c: C, + } + + expand_b(output) { + insta::assert_snapshot!(output, @" + impl HasField>> for B { + type Value = C; + fn get_field( + &self, + key: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.c + } + } + impl HasFieldMut>> for B { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>>, + ) -> &mut Self::Value { + &mut self.c + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct C { + pub d: D, + } + + expand_c(output) { + insta::assert_snapshot!(output, @" + impl HasField>> for C { + type Value = D; + fn get_field( + &self, + key: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.d + } + } + impl HasFieldMut>> for C { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>>, + ) -> &mut Self::Value { + &mut self.d + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct D { + pub name: String, + } + + expand_d(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>>> for D { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &Self::Value { + &self.name + } + } + impl HasFieldMut>>>>> for D { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &mut Self::Value { + &mut self.name + } + } + ") + } + } + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct MyContext { + pub a: A, + } + + expand_my_context_struct(output) { + insta::assert_snapshot!(output, @" + impl HasField>> for MyContext { + type Value = A; + fn get_field( + &self, + key: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.a + } + } + impl HasFieldMut>> for MyContext { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>>, + ) -> &mut Self::Value { + &mut self.a + } + } + ") + } + } + + snapshot_cgp_getter! { + #[cgp_getter] + pub trait HasName { + fn name(&self) -> &str; + } + + expand_has_name(output) { + insta::assert_snapshot!(output, @" + pub trait HasName { + fn name(&self) -> &str; + } + impl<__Context__> HasName for __Context__ + where + __Context__: NameGetter<__Context__>, + { + fn name(&self) -> &str { + __Context__::name(self) + } + } + pub trait NameGetter<__Context__>: IsProviderFor { + fn name(__context__: &__Context__) -> &str; + } + impl<__Provider__, __Context__> NameGetter<__Context__> for __Provider__ + where + __Provider__: DelegateComponent + + IsProviderFor, + <__Provider__ as DelegateComponent< + NameGetterComponent, + >>::Delegate: NameGetter<__Context__>, + { + fn name(__context__: &__Context__) -> &str { + <__Provider__ as DelegateComponent< + NameGetterComponent, + >>::Delegate::name(__context__) + } + } + pub struct NameGetterComponent; + impl<__Context__> NameGetter<__Context__> for UseContext + where + __Context__: HasName, + { + fn name(__context__: &__Context__) -> &str { + __Context__::name(__context__) + } + } + impl<__Context__> IsProviderFor for UseContext + where + __Context__: HasName, + {} + impl<__Context__, __Components__, __Path__> NameGetter<__Context__> + for RedirectLookup<__Components__, __Path__> + where + __Components__: DelegateComponent<__Path__>, + <__Components__ as DelegateComponent<__Path__>>::Delegate: NameGetter<__Context__>, + { + fn name(__context__: &__Context__) -> &str { + <__Components__ as DelegateComponent<__Path__>>::Delegate::name(__context__) + } + } + impl< + __Context__, + __Components__, + __Path__, + > IsProviderFor + for RedirectLookup<__Components__, __Path__> + where + __Components__: DelegateComponent<__Path__>, + <__Components__ as DelegateComponent< + __Path__, + >>::Delegate: IsProviderFor + + NameGetter<__Context__>, + {} + impl<__Context__> NameGetter<__Context__> for UseFields + where + __Context__: HasField< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + Value = String, + >, + { + fn name(__context__: &__Context__) -> &str { + __context__ + .get_field( + ::core::marker::PhantomData::< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) + .as_str() + } + } + impl<__Context__> IsProviderFor for UseFields + where + __Context__: HasField< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + Value = String, + >, + {} + impl<__Context__, __Tag__> NameGetter<__Context__> for UseField<__Tag__> + where + __Context__: HasField<__Tag__, Value = String>, + { + fn name(__context__: &__Context__) -> &str { + __context__.get_field(::core::marker::PhantomData::<__Tag__>).as_str() + } + } + impl<__Context__, __Tag__> IsProviderFor + for UseField<__Tag__> + where + __Context__: HasField<__Tag__, Value = String>, + {} + impl<__Context__, __Provider__> NameGetter<__Context__> for WithProvider<__Provider__> + where + __Provider__: FieldGetter<__Context__, NameGetterComponent, Value = String>, + { + fn name(__context__: &__Context__) -> &str { + __Provider__::get_field( + __context__, + ::core::marker::PhantomData::, + ) + .as_str() + } + } + impl<__Context__, __Provider__> IsProviderFor + for WithProvider<__Provider__> + where + __Provider__: FieldGetter<__Context__, NameGetterComponent, Value = String>, + {} + ") + } + } + + snapshot_delegate_and_check_components! { + delegate_and_check_components! { + MyContext { + NameGetterComponent: WithProvider< + ChainGetters, + UseField, + UseField, + UseField, + UseField + ]>> + } + } + + expand_my_context(output) { + insta::assert_snapshot!(output, @r#" + impl DelegateComponent for MyContext { + type Delegate = WithProvider< + ChainGetters< + Product![ + UseField < Symbol!("a") >, UseField < Symbol!("b") >, UseField < + Symbol!("c") >, UseField < Symbol!("d") >, UseField < Symbol!("name") > + ], + >, + >; + } + impl<__Context__, __Params__> IsProviderFor + for MyContext + where + WithProvider< + ChainGetters< + Product![ + UseField < Symbol!("a") >, UseField < Symbol!("b") >, UseField < + Symbol!("c") >, UseField < Symbol!("d") >, UseField < Symbol!("name") > + ], + >, + >: IsProviderFor, + {} + trait __CanUseMyContext< + __Component__, + __Params__: ?Sized, + >: CanUseComponent<__Component__, __Params__> {} + impl __CanUseMyContext for MyContext {} + "#) + } + } + + #[test] + fn test_deeply_nested_getter() { + let context = MyContext { + a: A { + b: B { + c: C { + d: D { + name: "test".to_owned(), + }, + }, + }, + }, + }; + + assert_eq!(context.name(), "test"); + } +} diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/index.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/index.rs new file mode 100644 index 00000000..396dbf71 --- /dev/null +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/index.rs @@ -0,0 +1,54 @@ +use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_has_field; + +snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Context(pub String, pub u64); + + expand_context(output) { + insta::assert_snapshot!(output, @" + impl HasField> for Context { + type Value = String; + fn get_field(&self, key: ::core::marker::PhantomData>) -> &Self::Value { + &self.0 + } + } + impl HasFieldMut> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>, + ) -> &mut Self::Value { + &mut self.0 + } + } + impl HasField> for Context { + type Value = u64; + fn get_field(&self, key: ::core::marker::PhantomData>) -> &Self::Value { + &self.1 + } + } + impl HasFieldMut> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>, + ) -> &mut Self::Value { + &mut self.1 + } + } + ") + } +} + +pub trait CheckHasFieldImpls: + HasField, Value = String> + HasField, Value = u64> +{ +} + +impl CheckHasFieldImpls for Context {} + +#[test] +fn test_has_field_index() { + let context = Context("test".to_owned(), 1); + assert_eq!(context.get_field(PhantomData::>), &"test"); + assert_eq!(context.get_field(PhantomData::>), &1); +} diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/life.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/life.rs new file mode 100644 index 00000000..3dbf25f4 --- /dev/null +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/life.rs @@ -0,0 +1,48 @@ +mod context_with_lifetime_field { + use core::marker::PhantomData; + + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_field; + + snapshot_derive_has_field! { + #[derive(HasField)] + pub struct Context<'a> { + pub name: &'a str, + } + + expand_context(output) { + insta::assert_snapshot!(output, @" + impl<'a> HasField>>>>> + for Context<'a> { + type Value = &'a str; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &Self::Value { + &self.name + } + } + impl<'a> HasFieldMut>>>>> + for Context<'a> { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + ) -> &mut Self::Value { + &mut self.name + } + } + ") + } + } + + #[test] + fn test_context_with_lifetime_field() { + let context = Context { name: "test" }; + + assert_eq!(context.get_field(PhantomData), &"test"); + } +} diff --git a/crates/tests/cgp-tests/src/tests/has_field/mod.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_field/mod.rs similarity index 100% rename from crates/tests/cgp-tests/src/tests/has_field/mod.rs rename to crates/tests/cgp-tests/tests/extensible_data_tests/has_field/mod.rs diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/enum_fields.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/enum_fields.rs new file mode 100644 index 00000000..074818b1 --- /dev/null +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/enum_fields.rs @@ -0,0 +1,323 @@ +pub mod simple_enum { + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub enum Person { + Anonymous(u32), + Named(String), + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Person { + type Fields = Either< + Field< + Symbol< + 9, + Chars< + 'A', + Chars< + 'n', + Chars< + 'o', + Chars< + 'n', + Chars< + 'y', + Chars<'m', Chars<'o', Chars<'u', Chars<'s', Nil>>>>, + >, + >, + >, + >, + >, + >, + u32, + >, + Either< + Field< + Symbol< + 5, + Chars<'N', Chars<'a', Chars<'m', Chars<'e', Chars<'d', Nil>>>>>, + >, + String, + >, + Void, + >, + >; + } + impl HasFieldsRef for Person { + type FieldsRef<'__a> = Either< + Field< + Symbol< + 9, + Chars< + 'A', + Chars< + 'n', + Chars< + 'o', + Chars< + 'n', + Chars< + 'y', + Chars<'m', Chars<'o', Chars<'u', Chars<'s', Nil>>>>, + >, + >, + >, + >, + >, + >, + &'__a u32, + >, + Either< + Field< + Symbol< + 5, + Chars<'N', Chars<'a', Chars<'m', Chars<'e', Chars<'d', Nil>>>>>, + >, + &'__a String, + >, + Void, + >, + > + where + Self: '__a; + } + impl FromFields for Person { + fn from_fields(rest: Self::Fields) -> Self { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Anonymous(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Named(field) + } + Either::Right(rest) => match rest {} + } + } + } + } + } + impl ToFields for Person { + fn to_fields(self) -> Self::Fields { + match self { + Self::Anonymous(field) => Either::Left(field.into()), + Self::Named(field) => Either::Right(Either::Left(field.into())), + } + } + } + impl ToFieldsRef for Person { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + match self { + Self::Anonymous(field) => Either::Left(field.into()), + Self::Named(field) => Either::Right(Either::Left(field.into())), + } + } + } + ") + } + } + + #[test] + fn test_simple_enum() { + { + let person_a1 = Person::Anonymous(42); + + let person_a2 = person_a1.clone().to_fields(); + assert_eq!(person_a2, Either::Left(42.into())); + + let person_a3 = Person::from_fields(person_a2); + assert_eq!(person_a3, person_a1); + + let person_a4 = person_a1.to_fields_ref(); + assert_eq!(person_a4, Either::Left((&42).into())); + } + + { + let name = "Alice".to_owned(); + + let person_b1 = Person::Named(name.clone()); + + let person_b2 = person_b1.clone().to_fields(); + assert_eq!(person_b2, Either::Right(Either::Left(name.clone().into()))); + + let person_b3 = Person::from_fields(person_b2); + assert_eq!(person_b3, person_b1); + + let person_b4 = person_b1.to_fields_ref(); + assert_eq!(person_b4, Either::Right(Either::Left((&name).into()))); + } + } +} + +pub mod generic_enum { + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub enum Person<'a, Name> { + Anonymous(u32), + Named(&'a Name), + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl<'a, Name> HasFields for Person<'a, Name> { + type Fields = Either< + Field< + Symbol< + 9, + Chars< + 'A', + Chars< + 'n', + Chars< + 'o', + Chars< + 'n', + Chars< + 'y', + Chars<'m', Chars<'o', Chars<'u', Chars<'s', Nil>>>>, + >, + >, + >, + >, + >, + >, + u32, + >, + Either< + Field< + Symbol< + 5, + Chars<'N', Chars<'a', Chars<'m', Chars<'e', Chars<'d', Nil>>>>>, + >, + &'a Name, + >, + Void, + >, + >; + } + impl<'a, Name> HasFieldsRef for Person<'a, Name> { + type FieldsRef<'__a> = Either< + Field< + Symbol< + 9, + Chars< + 'A', + Chars< + 'n', + Chars< + 'o', + Chars< + 'n', + Chars< + 'y', + Chars<'m', Chars<'o', Chars<'u', Chars<'s', Nil>>>>, + >, + >, + >, + >, + >, + >, + &'__a u32, + >, + Either< + Field< + Symbol< + 5, + Chars<'N', Chars<'a', Chars<'m', Chars<'e', Chars<'d', Nil>>>>>, + >, + &'__a &'a Name, + >, + Void, + >, + > + where + Self: '__a; + } + impl<'a, Name> FromFields for Person<'a, Name> { + fn from_fields(rest: Self::Fields) -> Self { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Anonymous(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Named(field) + } + Either::Right(rest) => match rest {} + } + } + } + } + } + impl<'a, Name> ToFields for Person<'a, Name> { + fn to_fields(self) -> Self::Fields { + match self { + Self::Anonymous(field) => Either::Left(field.into()), + Self::Named(field) => Either::Right(Either::Left(field.into())), + } + } + } + impl<'a, Name> ToFieldsRef for Person<'a, Name> { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + match self { + Self::Anonymous(field) => Either::Left(field.into()), + Self::Named(field) => Either::Right(Either::Left(field.into())), + } + } + } + ") + } + } + + #[test] + fn test_generic_enum() { + { + let person_a1: Person = Person::Anonymous(42); + + let person_a2 = person_a1.clone().to_fields(); + assert_eq!(person_a2, Either::Left(42.into())); + + let person_a3 = Person::from_fields(person_a2); + assert_eq!(person_a3, person_a1); + + let person_a4 = person_a1.to_fields_ref(); + assert_eq!(person_a4, Either::Left((&42).into())); + } + + { + let name = "Alice".to_owned(); + + let person_b1 = Person::Named(&name); + + let person_b2 = person_b1.clone().to_fields(); + assert_eq!(person_b2, Either::Right(Either::Left((&name).into()))); + + let person_b3 = Person::from_fields(person_b2); + assert_eq!(person_b3, person_b1); + + let person_b4 = person_b1.to_fields_ref(); + assert_eq!(person_b4, Either::Right(Either::Left((&&name).into()))); + } + } +} diff --git a/crates/tests/cgp-tests/src/tests/has_fields/mod.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/mod.rs similarity index 100% rename from crates/tests/cgp-tests/src/tests/has_fields/mod.rs rename to crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/mod.rs diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/struct_fields.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/struct_fields.rs new file mode 100644 index 00000000..adcb2dc1 --- /dev/null +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/has_fields/struct_fields.rs @@ -0,0 +1,462 @@ +pub mod single_name_field { + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person { + pub name: String, + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Person { + type Fields = Cons< + Field>>>>, String>, + Nil, + >; + } + impl HasFieldsRef for Person { + type FieldsRef<'__a> = Cons< + Field< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + &'__a String, + >, + Nil, + > + where + Self: '__a; + } + impl FromFields for Person { + fn from_fields(Cons(name, Nil): Self::Fields) -> Self { + Self { name: name.value } + } + } + impl ToFields for Person { + fn to_fields(self) -> Self::Fields { + Cons(self.name.into(), Nil) + } + } + impl ToFieldsRef for Person { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.name).into(), Nil) + } + } + ") + } + } + + #[test] + fn test_single_named_field() { + let name = "Alice".to_owned(); + + let person1 = Person { name: name.clone() }; + + let product = person1.clone().to_fields(); + assert_eq!(product, Cons(name.clone().into(), Nil)); + + let product_ref = person1.to_fields_ref(); + assert_eq!(product_ref, Cons((&name).into(), Nil)); + + let person2 = Person::from_fields(product); + + assert_eq!(person1, person2); + } +} + +pub mod two_named_field { + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person { + pub name: String, + pub age: u8, + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Person { + type Fields = Cons< + Field>>>>, String>, + Cons>>>, u8>, Nil>, + >; + } + impl HasFieldsRef for Person { + type FieldsRef<'__a> = Cons< + Field< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + &'__a String, + >, + Cons>>>, &'__a u8>, Nil>, + > + where + Self: '__a; + } + impl FromFields for Person { + fn from_fields(Cons(name, Cons(age, Nil)): Self::Fields) -> Self { + Self { + name: name.value, + age: age.value, + } + } + } + impl ToFields for Person { + fn to_fields(self) -> Self::Fields { + Cons(self.name.into(), Cons(self.age.into(), Nil)) + } + } + impl ToFieldsRef for Person { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.name).into(), Cons((&self.age).into(), Nil)) + } + } + ") + } + } + + #[test] + fn test_two_named_field() { + let name = "Alice".to_owned(); + + let person1 = Person { + name: name.clone(), + age: 32, + }; + + let product = person1.clone().to_fields(); + assert_eq!(product, Cons(name.clone().into(), Cons(32.into(), Nil))); + + let product_ref = person1.to_fields_ref(); + assert_eq!(product_ref, Cons((&name).into(), Cons((&32).into(), Nil))); + + let person2 = Person::from_fields(product); + + assert_eq!(person1, person2); + } +} + +pub mod generic_struct { + use core::fmt::Display; + + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person + where + Name: Display, + { + pub name: Name, + pub age: u8, + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Person + where + Name: Display, + { + type Fields = Cons< + Field>>>>, Name>, + Cons>>>, u8>, Nil>, + >; + } + impl HasFieldsRef for Person + where + Name: Display, + { + type FieldsRef<'__a> = Cons< + Field< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + &'__a Name, + >, + Cons>>>, &'__a u8>, Nil>, + > + where + Self: '__a; + } + impl FromFields for Person + where + Name: Display, + { + fn from_fields(Cons(name, Cons(age, Nil)): Self::Fields) -> Self { + Self { + name: name.value, + age: age.value, + } + } + } + impl ToFields for Person + where + Name: Display, + { + fn to_fields(self) -> Self::Fields { + Cons(self.name.into(), Cons(self.age.into(), Nil)) + } + } + impl ToFieldsRef for Person + where + Name: Display, + { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.name).into(), Cons((&self.age).into(), Nil)) + } + } + ") + } + } + + #[test] + fn test_generic_struct() { + let name = "Alice".to_owned(); + + let person1 = Person { + name: name.clone(), + age: 32, + }; + + let product = person1.clone().to_fields(); + assert_eq!(product, Cons(name.clone().into(), Cons(32.into(), Nil))); + + let product_ref = person1.to_fields_ref(); + assert_eq!(product_ref, Cons((&name).into(), Cons((&32).into(), Nil))); + + let person2 = Person::from_fields(product); + + assert_eq!(person1, person2); + } +} + +pub mod generic_lifetime_struct { + use core::fmt::Display; + + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person<'a, Name> + where + Name: Display, + { + pub name: &'a Name, + pub age: &'a u8, + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl<'a, Name> HasFields for Person<'a, Name> + where + Name: Display, + { + type Fields = Cons< + Field>>>>, &'a Name>, + Cons>>>, &'a u8>, Nil>, + >; + } + impl<'a, Name> HasFieldsRef for Person<'a, Name> + where + Name: Display, + { + type FieldsRef<'__a> = Cons< + Field< + Symbol<4, Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + &'__a &'a Name, + >, + Cons< + Field>>>, &'__a &'a u8>, + Nil, + >, + > + where + Self: '__a; + } + impl<'a, Name> FromFields for Person<'a, Name> + where + Name: Display, + { + fn from_fields(Cons(name, Cons(age, Nil)): Self::Fields) -> Self { + Self { + name: name.value, + age: age.value, + } + } + } + impl<'a, Name> ToFields for Person<'a, Name> + where + Name: Display, + { + fn to_fields(self) -> Self::Fields { + Cons(self.name.into(), Cons(self.age.into(), Nil)) + } + } + impl<'a, Name> ToFieldsRef for Person<'a, Name> + where + Name: Display, + { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.name).into(), Cons((&self.age).into(), Nil)) + } + } + ") + } + } + + #[test] + fn test_generic_lifetime_struct() { + let name = "Alice".to_owned(); + + let person1 = Person { + name: &name, + age: &32, + }; + + let product = person1.clone().to_fields(); + assert_eq!(product, Cons((&name).into(), Cons((&32).into(), Nil))); + + let product_ref = person1.to_fields_ref(); + assert_eq!(product_ref, Cons((&&name).into(), Cons((&&32).into(), Nil))); + + let person2 = Person::from_fields(product); + + assert_eq!(person1, person2); + } +} + +pub mod single_unnamed_field { + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person(String); + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Person { + type Fields = String; + } + impl HasFieldsRef for Person { + type FieldsRef<'__a> = &'__a String where Self: '__a; + } + impl FromFields for Person { + fn from_fields(field: Self::Fields) -> Self { + Self(field) + } + } + impl ToFields for Person { + fn to_fields(self) -> Self::Fields { + self.0 + } + } + impl ToFieldsRef for Person { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + &self.0 + } + } + ") + } + } + + #[test] + fn test_single_unnamed_field() { + let name = "Alice".to_owned(); + + let person1 = Person(name.clone()); + + let product = person1.clone().to_fields(); + assert_eq!(product, name.clone()); + + let product_ref = person1.to_fields_ref(); + assert_eq!(product_ref, &name); + + let person2 = Person::from_fields(product); + + assert_eq!(person1, person2); + } +} + +pub mod single_unnamed_multi_field { + use cgp::prelude::*; + use cgp_macro_test_util::snapshot_derive_has_fields; + + snapshot_derive_has_fields! { + #[derive(HasFields)] + #[derive(Clone, Debug, Eq, PartialEq)] + pub struct Person(String, u8); + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Person { + type Fields = Cons, String>, Cons, u8>, Nil>>; + } + impl HasFieldsRef for Person { + type FieldsRef<'__a> = Cons< + Field, &'__a String>, + Cons, &'__a u8>, Nil>, + > + where + Self: '__a; + } + impl FromFields for Person { + fn from_fields(Cons(field_1, Cons(field_0, Nil)): Self::Fields) -> Self { + Self(field_1.value, field_0.value) + } + } + impl ToFields for Person { + fn to_fields(self) -> Self::Fields { + Cons(self.0.into(), Cons(self.1.into(), Nil)) + } + } + impl ToFieldsRef for Person { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.0).into(), Cons((&self.1).into(), Nil)) + } + } + ") + } + } + + #[test] + fn test_single_unnamed_multi_field() { + let name = "Alice".to_owned(); + + let person1 = Person(name.clone(), 32); + + let product = person1.clone().to_fields(); + assert_eq!(product, Cons(name.clone().into(), Cons(32.into(), Nil))); + + let product_ref = person1.to_fields_ref(); + assert_eq!(product_ref, Cons((&name).into(), Cons((&32).into(), Nil))); + + let person2 = Person::from_fields(product); + + assert_eq!(person1, person2); + } +} diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/mod.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/mod.rs index 268448a9..f955c1f3 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/mod.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/mod.rs @@ -1,2 +1,4 @@ +pub mod has_field; +pub mod has_fields; pub mod records; pub mod variants; diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/records/basic.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/records/basic.rs index fa93bbcc..01693cd6 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/records/basic.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/records/basic.rs @@ -6,13 +6,293 @@ use cgp::core::field::impls::CanBuildFrom; use cgp::extra::dispatch::{BuildAndMerge, BuildAndSetField, BuildWithHandlers}; use cgp::extra::handler::{Computer, Producer, ProducerComponent}; use cgp::prelude::*; -use cgp_macro_test_util::snapshot_delegate_components; +use cgp_macro_test_util::{snapshot_delegate_components, snapshot_derive_cgp_data}; -#[derive(Debug, Eq, PartialEq, CgpData)] -pub struct FooBarBaz { - pub foo: u64, - pub bar: String, - pub baz: bool, +snapshot_derive_cgp_data! { + #[derive(CgpData)] + #[derive(Debug, Eq, PartialEq)] + pub struct FooBarBaz { + pub foo: u64, + pub bar: String, + pub baz: bool, + } + + expand_foo_bar_baz(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>> for FooBarBaz { + type Value = u64; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &Self::Value { + &self.foo + } + } + impl HasFieldMut>>>> for FooBarBaz { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.foo + } + } + impl HasField>>>> for FooBarBaz { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &Self::Value { + &self.bar + } + } + impl HasFieldMut>>>> for FooBarBaz { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.bar + } + } + impl HasField>>>> for FooBarBaz { + type Value = bool; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> &Self::Value { + &self.baz + } + } + impl HasFieldMut>>>> for FooBarBaz { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.baz + } + } + impl HasFields for FooBarBaz { + type Fields = Cons< + Field>>>, u64>, + Cons< + Field>>>, String>, + Cons>>>, bool>, Nil>, + >, + >; + } + impl HasFieldsRef for FooBarBaz { + type FieldsRef<'__a> = Cons< + Field>>>, &'__a u64>, + Cons< + Field>>>, &'__a String>, + Cons< + Field>>>, &'__a bool>, + Nil, + >, + >, + > + where + Self: '__a; + } + impl FromFields for FooBarBaz { + fn from_fields(Cons(foo, Cons(bar, Cons(baz, Nil))): Self::Fields) -> Self { + Self { + foo: foo.value, + bar: bar.value, + baz: baz.value, + } + } + } + impl ToFields for FooBarBaz { + fn to_fields(self) -> Self::Fields { + Cons(self.foo.into(), Cons(self.bar.into(), Cons(self.baz.into(), Nil))) + } + } + impl ToFieldsRef for FooBarBaz { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.foo).into(), Cons((&self.bar).into(), Cons((&self.baz).into(), Nil))) + } + } + pub struct __PartialFooBarBaz<__F0__: MapType, __F1__: MapType, __F2__: MapType> { + pub foo: <__F0__ as MapType>::Map, + pub bar: <__F1__ as MapType>::Map, + pub baz: <__F2__ as MapType>::Map, + } + impl HasBuilder for FooBarBaz { + type Builder = __PartialFooBarBaz; + fn builder() -> Self::Builder { + __PartialFooBarBaz { + foo: (), + bar: (), + baz: (), + } + } + } + impl IntoBuilder for FooBarBaz { + type Builder = __PartialFooBarBaz; + fn into_builder(self) -> Self::Builder { + __PartialFooBarBaz { + foo: self.foo, + bar: self.bar, + baz: self.baz, + } + } + } + impl<__F0__: MapType, __F1__: MapType, __F2__: MapType> PartialData + for __PartialFooBarBaz<__F0__, __F1__, __F2__> { + type Target = FooBarBaz; + } + impl FinalizeBuild for __PartialFooBarBaz { + fn finalize_build(self) -> Self::Target { + FooBarBaz { + foo: self.foo, + bar: self.bar, + baz: self.baz, + } + } + } + impl< + __M1__: MapType, + __M2__: MapType, + __F1__: MapType, + __F2__: MapType, + > UpdateField>>>, __M2__> + for __PartialFooBarBaz<__M1__, __F1__, __F2__> { + type Value = u64; + type Mapper = __M1__; + type Output = __PartialFooBarBaz<__M2__, __F1__, __F2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.foo, + __PartialFooBarBaz { + foo: value, + bar: self.bar, + baz: self.baz, + }, + ) + } + } + impl< + __F0__: MapType, + __M1__: MapType, + __M2__: MapType, + __F2__: MapType, + > UpdateField>>>, __M2__> + for __PartialFooBarBaz<__F0__, __M1__, __F2__> { + type Value = String; + type Mapper = __M1__; + type Output = __PartialFooBarBaz<__F0__, __M2__, __F2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.bar, + __PartialFooBarBaz { + foo: self.foo, + bar: value, + baz: self.baz, + }, + ) + } + } + impl< + __F0__: MapType, + __F1__: MapType, + __M1__: MapType, + __M2__: MapType, + > UpdateField>>>, __M2__> + for __PartialFooBarBaz<__F0__, __F1__, __M1__> { + type Value = bool; + type Mapper = __M1__; + type Output = __PartialFooBarBaz<__F0__, __F1__, __M2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.baz, + __PartialFooBarBaz { + foo: self.foo, + bar: self.bar, + baz: value, + }, + ) + } + } + impl< + __F1__: MapType, + __F2__: MapType, + > HasField>>>> + for __PartialFooBarBaz { + type Value = u64; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &Self::Value { + &self.foo + } + } + impl< + __F0__: MapType, + __F2__: MapType, + > HasField>>>> + for __PartialFooBarBaz<__F0__, IsPresent, __F2__> { + type Value = String; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &Self::Value { + &self.bar + } + } + impl< + __F0__: MapType, + __F1__: MapType, + > HasField>>>> + for __PartialFooBarBaz<__F0__, __F1__, IsPresent> { + type Value = bool; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> &Self::Value { + &self.baz + } + } + ") + } } #[derive(Debug, Eq, PartialEq, CgpData)] diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/records/generics.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/records/generics.rs index 4bc1be53..8c08ff53 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/records/generics.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/records/generics.rs @@ -1,11 +1,388 @@ -use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_cgp_data; -#[derive(CgpData)] -pub struct Context -where - Foo: Clone, -{ - pub foo: Foo, - pub bar: Bar, - pub baz: Baz, +snapshot_derive_cgp_data! { + #[derive(CgpData)] + pub struct Context + where + Foo: Clone, + { + pub foo: Foo, + pub bar: Bar, + pub baz: Baz, + } + + expand_context(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>> + for Context + where + Foo: Clone, + { + type Value = Foo; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &Self::Value { + &self.foo + } + } + impl HasFieldMut>>>> + for Context + where + Foo: Clone, + { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.foo + } + } + impl HasField>>>> + for Context + where + Foo: Clone, + { + type Value = Bar; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &Self::Value { + &self.bar + } + } + impl HasFieldMut>>>> + for Context + where + Foo: Clone, + { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.bar + } + } + impl HasField>>>> + for Context + where + Foo: Clone, + { + type Value = Baz; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> &Self::Value { + &self.baz + } + } + impl HasFieldMut>>>> + for Context + where + Foo: Clone, + { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.baz + } + } + impl HasFields for Context + where + Foo: Clone, + { + type Fields = Cons< + Field>>>, Foo>, + Cons< + Field>>>, Bar>, + Cons>>>, Baz>, Nil>, + >, + >; + } + impl HasFieldsRef for Context + where + Foo: Clone, + { + type FieldsRef<'__a> = Cons< + Field>>>, &'__a Foo>, + Cons< + Field>>>, &'__a Bar>, + Cons< + Field>>>, &'__a Baz>, + Nil, + >, + >, + > + where + Self: '__a; + } + impl FromFields for Context + where + Foo: Clone, + { + fn from_fields(Cons(foo, Cons(bar, Cons(baz, Nil))): Self::Fields) -> Self { + Self { + foo: foo.value, + bar: bar.value, + baz: baz.value, + } + } + } + impl ToFields for Context + where + Foo: Clone, + { + fn to_fields(self) -> Self::Fields { + Cons(self.foo.into(), Cons(self.bar.into(), Cons(self.baz.into(), Nil))) + } + } + impl ToFieldsRef for Context + where + Foo: Clone, + { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.foo).into(), Cons((&self.bar).into(), Cons((&self.baz).into(), Nil))) + } + } + pub struct __PartialContext< + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + __F2__: MapType, + > + where + Foo: Clone, + { + pub foo: <__F0__ as MapType>::Map, + pub bar: <__F1__ as MapType>::Map, + pub baz: <__F2__ as MapType>::Map, + } + impl HasBuilder for Context + where + Foo: Clone, + { + type Builder = __PartialContext; + fn builder() -> Self::Builder { + __PartialContext { + foo: (), + bar: (), + baz: (), + } + } + } + impl IntoBuilder for Context + where + Foo: Clone, + { + type Builder = __PartialContext; + fn into_builder(self) -> Self::Builder { + __PartialContext { + foo: self.foo, + bar: self.bar, + baz: self.baz, + } + } + } + impl PartialData + for __PartialContext + where + Foo: Clone, + { + type Target = Context; + } + impl FinalizeBuild + for __PartialContext + where + Foo: Clone, + { + fn finalize_build(self) -> Self::Target { + Context { + foo: self.foo, + bar: self.bar, + baz: self.baz, + } + } + } + impl< + Foo, + Bar, + Baz, + __M1__: MapType, + __M2__: MapType, + __F1__: MapType, + __F2__: MapType, + > UpdateField>>>, __M2__> + for __PartialContext + where + Foo: Clone, + { + type Value = Foo; + type Mapper = __M1__; + type Output = __PartialContext; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.foo, + __PartialContext { + foo: value, + bar: self.bar, + baz: self.baz, + }, + ) + } + } + impl< + Foo, + Bar, + Baz, + __F0__: MapType, + __M1__: MapType, + __M2__: MapType, + __F2__: MapType, + > UpdateField>>>, __M2__> + for __PartialContext + where + Foo: Clone, + { + type Value = Bar; + type Mapper = __M1__; + type Output = __PartialContext; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.bar, + __PartialContext { + foo: self.foo, + bar: value, + baz: self.baz, + }, + ) + } + } + impl< + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + __M1__: MapType, + __M2__: MapType, + > UpdateField>>>, __M2__> + for __PartialContext + where + Foo: Clone, + { + type Value = Baz; + type Mapper = __M1__; + type Output = __PartialContext; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.baz, + __PartialContext { + foo: self.foo, + bar: self.bar, + baz: value, + }, + ) + } + } + impl< + Foo, + Bar, + Baz, + __F1__: MapType, + __F2__: MapType, + > HasField>>>> + for __PartialContext + where + Foo: Clone, + { + type Value = Foo; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &Self::Value { + &self.foo + } + } + impl< + Foo, + Bar, + Baz, + __F0__: MapType, + __F2__: MapType, + > HasField>>>> + for __PartialContext + where + Foo: Clone, + { + type Value = Bar; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &Self::Value { + &self.bar + } + } + impl< + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + > HasField>>>> + for __PartialContext + where + Foo: Clone, + { + type Value = Baz; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> &Self::Value { + &self.baz + } + } + ") + } } diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/records/index.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/records/index.rs index 681ea680..dd82fc18 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/records/index.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/records/index.rs @@ -1,4 +1,218 @@ -use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_cgp_data; -#[derive(CgpData)] -pub struct Context(pub u64, pub String, pub bool); +snapshot_derive_cgp_data! { + #[derive(CgpData)] + pub struct Context(pub u64, pub String, pub bool); + + expand_context(output) { + insta::assert_snapshot!(output, @" + impl HasField> for Context { + type Value = u64; + fn get_field(&self, key: ::core::marker::PhantomData>) -> &Self::Value { + &self.0 + } + } + impl HasFieldMut> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>, + ) -> &mut Self::Value { + &mut self.0 + } + } + impl HasField> for Context { + type Value = String; + fn get_field(&self, key: ::core::marker::PhantomData>) -> &Self::Value { + &self.1 + } + } + impl HasFieldMut> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>, + ) -> &mut Self::Value { + &mut self.1 + } + } + impl HasField> for Context { + type Value = bool; + fn get_field(&self, key: ::core::marker::PhantomData>) -> &Self::Value { + &self.2 + } + } + impl HasFieldMut> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>, + ) -> &mut Self::Value { + &mut self.2 + } + } + impl HasFields for Context { + type Fields = Cons< + Field, u64>, + Cons, String>, Cons, bool>, Nil>>, + >; + } + impl HasFieldsRef for Context { + type FieldsRef<'__a> = Cons< + Field, &'__a u64>, + Cons, &'__a String>, Cons, &'__a bool>, Nil>>, + > + where + Self: '__a; + } + impl FromFields for Context { + fn from_fields( + Cons(field_2, Cons(field_1, Cons(field_0, Nil))): Self::Fields, + ) -> Self { + Self(field_2.value, field_1.value, field_0.value) + } + } + impl ToFields for Context { + fn to_fields(self) -> Self::Fields { + Cons(self.0.into(), Cons(self.1.into(), Cons(self.2.into(), Nil))) + } + } + impl ToFieldsRef for Context { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.0).into(), Cons((&self.1).into(), Cons((&self.2).into(), Nil))) + } + } + pub struct __PartialContext<__F0__: MapType, __F1__: MapType, __F2__: MapType>( + pub <__F0__ as MapType>::Map, + pub <__F1__ as MapType>::Map, + pub <__F2__ as MapType>::Map, + ); + impl HasBuilder for Context { + type Builder = __PartialContext; + fn builder() -> Self::Builder { + __PartialContext { + 0: (), + 1: (), + 2: (), + } + } + } + impl IntoBuilder for Context { + type Builder = __PartialContext; + fn into_builder(self) -> Self::Builder { + __PartialContext { + 0: self.0, + 1: self.1, + 2: self.2, + } + } + } + impl<__F0__: MapType, __F1__: MapType, __F2__: MapType> PartialData + for __PartialContext<__F0__, __F1__, __F2__> { + type Target = Context; + } + impl FinalizeBuild for __PartialContext { + fn finalize_build(self) -> Self::Target { + Context { + 0: self.0, + 1: self.1, + 2: self.2, + } + } + } + impl< + __M1__: MapType, + __M2__: MapType, + __F1__: MapType, + __F2__: MapType, + > UpdateField, __M2__> for __PartialContext<__M1__, __F1__, __F2__> { + type Value = u64; + type Mapper = __M1__; + type Output = __PartialContext<__M2__, __F1__, __F2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData>, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.0, + __PartialContext { + 0: value, + 1: self.1, + 2: self.2, + }, + ) + } + } + impl< + __F0__: MapType, + __M1__: MapType, + __M2__: MapType, + __F2__: MapType, + > UpdateField, __M2__> for __PartialContext<__F0__, __M1__, __F2__> { + type Value = String; + type Mapper = __M1__; + type Output = __PartialContext<__F0__, __M2__, __F2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData>, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.1, + __PartialContext { + 0: self.0, + 1: value, + 2: self.2, + }, + ) + } + } + impl< + __F0__: MapType, + __F1__: MapType, + __M1__: MapType, + __M2__: MapType, + > UpdateField, __M2__> for __PartialContext<__F0__, __F1__, __M1__> { + type Value = bool; + type Mapper = __M1__; + type Output = __PartialContext<__F0__, __F1__, __M2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData>, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.2, + __PartialContext { + 0: self.0, + 1: self.1, + 2: value, + }, + ) + } + } + impl<__F1__: MapType, __F2__: MapType> HasField> + for __PartialContext { + type Value = u64; + fn get_field(&self, tag: ::core::marker::PhantomData>) -> &Self::Value { + &self.0 + } + } + impl<__F0__: MapType, __F2__: MapType> HasField> + for __PartialContext<__F0__, IsPresent, __F2__> { + type Value = String; + fn get_field(&self, tag: ::core::marker::PhantomData>) -> &Self::Value { + &self.1 + } + } + impl<__F0__: MapType, __F1__: MapType> HasField> + for __PartialContext<__F0__, __F1__, IsPresent> { + type Value = bool; + fn get_field(&self, tag: ::core::marker::PhantomData>) -> &Self::Value { + &self.2 + } + } + ") + } +} diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/records/optional.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/records/optional.rs index 9b45dc37..4c329a81 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/records/optional.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/records/optional.rs @@ -2,11 +2,203 @@ use cgp::extra::field::impls::{ CanFinalizeWithDefault, FinalizeOptional, HasOptionalBuilder, SetOptional, }; use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_cgp_data; -#[derive(CgpData)] -pub struct Context { - pub foo: String, - pub bar: u64, +snapshot_derive_cgp_data! { + #[derive(CgpData)] + pub struct Context { + pub foo: String, + pub bar: u64, + } + + expand_context(output) { + insta::assert_snapshot!(output, @" + impl HasField>>>> for Context { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &Self::Value { + &self.foo + } + } + impl HasFieldMut>>>> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.foo + } + } + impl HasField>>>> for Context { + type Value = u64; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &Self::Value { + &self.bar + } + } + impl HasFieldMut>>>> for Context { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &mut Self::Value { + &mut self.bar + } + } + impl HasFields for Context { + type Fields = Cons< + Field>>>, String>, + Cons>>>, u64>, Nil>, + >; + } + impl HasFieldsRef for Context { + type FieldsRef<'__a> = Cons< + Field>>>, &'__a String>, + Cons>>>, &'__a u64>, Nil>, + > + where + Self: '__a; + } + impl FromFields for Context { + fn from_fields(Cons(foo, Cons(bar, Nil)): Self::Fields) -> Self { + Self { + foo: foo.value, + bar: bar.value, + } + } + } + impl ToFields for Context { + fn to_fields(self) -> Self::Fields { + Cons(self.foo.into(), Cons(self.bar.into(), Nil)) + } + } + impl ToFieldsRef for Context { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.foo).into(), Cons((&self.bar).into(), Nil)) + } + } + pub struct __PartialContext<__F0__: MapType, __F1__: MapType> { + pub foo: <__F0__ as MapType>::Map, + pub bar: <__F1__ as MapType>::Map, + } + impl HasBuilder for Context { + type Builder = __PartialContext; + fn builder() -> Self::Builder { + __PartialContext { + foo: (), + bar: (), + } + } + } + impl IntoBuilder for Context { + type Builder = __PartialContext; + fn into_builder(self) -> Self::Builder { + __PartialContext { + foo: self.foo, + bar: self.bar, + } + } + } + impl<__F0__: MapType, __F1__: MapType> PartialData for __PartialContext<__F0__, __F1__> { + type Target = Context; + } + impl FinalizeBuild for __PartialContext { + fn finalize_build(self) -> Self::Target { + Context { + foo: self.foo, + bar: self.bar, + } + } + } + impl< + __M1__: MapType, + __M2__: MapType, + __F1__: MapType, + > UpdateField>>>, __M2__> + for __PartialContext<__M1__, __F1__> { + type Value = String; + type Mapper = __M1__; + type Output = __PartialContext<__M2__, __F1__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.foo, + __PartialContext { + foo: value, + bar: self.bar, + }, + ) + } + } + impl< + __F0__: MapType, + __M1__: MapType, + __M2__: MapType, + > UpdateField>>>, __M2__> + for __PartialContext<__F0__, __M1__> { + type Value = u64; + type Mapper = __M1__; + type Output = __PartialContext<__F0__, __M2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.bar, + __PartialContext { + foo: self.foo, + bar: value, + }, + ) + } + } + impl<__F1__: MapType> HasField>>>> + for __PartialContext { + type Value = String; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'f', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> &Self::Value { + &self.foo + } + } + impl<__F0__: MapType> HasField>>>> + for __PartialContext<__F0__, IsPresent> { + type Value = u64; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol<3, Chars<'b', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> &Self::Value { + &self.bar + } + } + ") + } } #[test] diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/records/person.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/records/person.rs index aef61b21..e032058d 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/records/person.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/records/person.rs @@ -1,11 +1,617 @@ use cgp::core::field::impls::CanBuildFrom; use cgp::extra::dispatch::{BuildAndMerge, BuildAndSetField, BuildWithHandlers}; use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_cgp_data; -#[derive(CgpData)] -pub struct Person { - pub first_name: String, - pub last_name: String, +snapshot_derive_cgp_data! { + #[derive(CgpData)] + pub struct Person { + pub first_name: String, + pub last_name: String, + } + + expand_person(output) { + insta::assert_snapshot!(output, @" + impl HasField< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + > for Person { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + >, + ) -> &Self::Value { + &self.first_name + } + } + impl HasFieldMut< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + > for Person { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + >, + ) -> &mut Self::Value { + &mut self.first_name + } + } + impl HasField< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars<'_', Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + > for Person { + type Value = String; + fn get_field( + &self, + key: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + ) -> &Self::Value { + &self.last_name + } + } + impl HasFieldMut< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars<'_', Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + > for Person { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + ) -> &mut Self::Value { + &mut self.last_name + } + } + impl HasFields for Person { + type Fields = Cons< + Field< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + String, + >, + Cons< + Field< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + String, + >, + Nil, + >, + >; + } + impl HasFieldsRef for Person { + type FieldsRef<'__a> = Cons< + Field< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + &'__a String, + >, + Cons< + Field< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + &'__a String, + >, + Nil, + >, + > + where + Self: '__a; + } + impl FromFields for Person { + fn from_fields(Cons(first_name, Cons(last_name, Nil)): Self::Fields) -> Self { + Self { + first_name: first_name.value, + last_name: last_name.value, + } + } + } + impl ToFields for Person { + fn to_fields(self) -> Self::Fields { + Cons(self.first_name.into(), Cons(self.last_name.into(), Nil)) + } + } + impl ToFieldsRef for Person { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.first_name).into(), Cons((&self.last_name).into(), Nil)) + } + } + pub struct __PartialPerson<__F0__: MapType, __F1__: MapType> { + pub first_name: <__F0__ as MapType>::Map, + pub last_name: <__F1__ as MapType>::Map, + } + impl HasBuilder for Person { + type Builder = __PartialPerson; + fn builder() -> Self::Builder { + __PartialPerson { + first_name: (), + last_name: (), + } + } + } + impl IntoBuilder for Person { + type Builder = __PartialPerson; + fn into_builder(self) -> Self::Builder { + __PartialPerson { + first_name: self.first_name, + last_name: self.last_name, + } + } + } + impl<__F0__: MapType, __F1__: MapType> PartialData for __PartialPerson<__F0__, __F1__> { + type Target = Person; + } + impl FinalizeBuild for __PartialPerson { + fn finalize_build(self) -> Self::Target { + Person { + first_name: self.first_name, + last_name: self.last_name, + } + } + } + impl< + __M1__: MapType, + __M2__: MapType, + __F1__: MapType, + > UpdateField< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + __M2__, + > for __PartialPerson<__M1__, __F1__> { + type Value = String; + type Mapper = __M1__; + type Output = __PartialPerson<__M2__, __F1__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.first_name, + __PartialPerson { + first_name: value, + last_name: self.last_name, + }, + ) + } + } + impl< + __F0__: MapType, + __M1__: MapType, + __M2__: MapType, + > UpdateField< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars<'_', Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + __M2__, + > for __PartialPerson<__F0__, __M1__> { + type Value = String; + type Mapper = __M1__; + type Output = __PartialPerson<__F0__, __M2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.last_name, + __PartialPerson { + first_name: self.first_name, + last_name: value, + }, + ) + } + } + impl< + __F1__: MapType, + > HasField< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + > for __PartialPerson { + type Value = String; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol< + 10, + Chars< + 'f', + Chars< + 'i', + Chars< + 'r', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + >, + ) -> &Self::Value { + &self.first_name + } + } + impl< + __F0__: MapType, + > HasField< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars<'_', Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + > for __PartialPerson<__F0__, IsPresent> { + type Value = String; + fn get_field( + &self, + tag: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'l', + Chars< + 'a', + Chars< + 's', + Chars< + 't', + Chars< + '_', + Chars<'n', Chars<'a', Chars<'m', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + ) -> &Self::Value { + &self.last_name + } + } + ") + } } #[derive(CgpData)] diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/records/point.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/records/point.rs index d1b65ffa..26db2aee 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/records/point.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/records/point.rs @@ -1,10 +1,176 @@ use cgp::extra::field::impls::CanBuildWithDefault; use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_cgp_data; -#[derive(Debug, Clone, Eq, PartialEq, CgpData)] -struct Point2d { - x: u64, - y: u64, +snapshot_derive_cgp_data! { + #[derive(CgpData)] + #[derive(Debug, Clone, Eq, PartialEq)] + struct Point2d { + x: u64, + y: u64, + } + + expand_point_2d(output) { + insta::assert_snapshot!(output, @" + impl HasField>> for Point2d { + type Value = u64; + fn get_field( + &self, + key: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.x + } + } + impl HasFieldMut>> for Point2d { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>>, + ) -> &mut Self::Value { + &mut self.x + } + } + impl HasField>> for Point2d { + type Value = u64; + fn get_field( + &self, + key: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.y + } + } + impl HasFieldMut>> for Point2d { + fn get_field_mut( + &mut self, + key: ::core::marker::PhantomData>>, + ) -> &mut Self::Value { + &mut self.y + } + } + impl HasFields for Point2d { + type Fields = Cons< + Field>, u64>, + Cons>, u64>, Nil>, + >; + } + impl HasFieldsRef for Point2d { + type FieldsRef<'__a> = Cons< + Field>, &'__a u64>, + Cons>, &'__a u64>, Nil>, + > + where + Self: '__a; + } + impl FromFields for Point2d { + fn from_fields(Cons(x, Cons(y, Nil)): Self::Fields) -> Self { + Self { x: x.value, y: y.value } + } + } + impl ToFields for Point2d { + fn to_fields(self) -> Self::Fields { + Cons(self.x.into(), Cons(self.y.into(), Nil)) + } + } + impl ToFieldsRef for Point2d { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + Cons((&self.x).into(), Cons((&self.y).into(), Nil)) + } + } + struct __PartialPoint2d<__F0__: MapType, __F1__: MapType> { + x: <__F0__ as MapType>::Map, + y: <__F1__ as MapType>::Map, + } + impl HasBuilder for Point2d { + type Builder = __PartialPoint2d; + fn builder() -> Self::Builder { + __PartialPoint2d { x: (), y: () } + } + } + impl IntoBuilder for Point2d { + type Builder = __PartialPoint2d; + fn into_builder(self) -> Self::Builder { + __PartialPoint2d { + x: self.x, + y: self.y, + } + } + } + impl<__F0__: MapType, __F1__: MapType> PartialData for __PartialPoint2d<__F0__, __F1__> { + type Target = Point2d; + } + impl FinalizeBuild for __PartialPoint2d { + fn finalize_build(self) -> Self::Target { + Point2d { x: self.x, y: self.y } + } + } + impl< + __M1__: MapType, + __M2__: MapType, + __F1__: MapType, + > UpdateField>, __M2__> for __PartialPoint2d<__M1__, __F1__> { + type Value = u64; + type Mapper = __M1__; + type Output = __PartialPoint2d<__M2__, __F1__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData>>, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.x, + __PartialPoint2d { + x: value, + y: self.y, + }, + ) + } + } + impl< + __F0__: MapType, + __M1__: MapType, + __M2__: MapType, + > UpdateField>, __M2__> for __PartialPoint2d<__F0__, __M1__> { + type Value = u64; + type Mapper = __M1__; + type Output = __PartialPoint2d<__F0__, __M2__>; + fn update_field( + self, + _tag: ::core::marker::PhantomData>>, + value: __M2__::Map, + ) -> (__M1__::Map, Self::Output) { + ( + self.y, + __PartialPoint2d { + x: self.x, + y: value, + }, + ) + } + } + impl<__F1__: MapType> HasField>> + for __PartialPoint2d { + type Value = u64; + fn get_field( + &self, + tag: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.x + } + } + impl<__F0__: MapType> HasField>> + for __PartialPoint2d<__F0__, IsPresent> { + type Value = u64; + fn get_field( + &self, + tag: ::core::marker::PhantomData>>, + ) -> &Self::Value { + &self.y + } + } + ") + } } #[derive(Debug, Clone, Eq, PartialEq, CgpData)] diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/variants/basic.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/variants/basic.rs index e15fe018..932e734e 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/variants/basic.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/variants/basic.rs @@ -12,14 +12,347 @@ use cgp::extra::handler::{ Computer, ComputerComponent, ComputerRef, ComputerRefComponent, PromoteAsync, }; use cgp::prelude::*; -use cgp_macro_test_util::{snapshot_cgp_new_provider, snapshot_delegate_components}; +use cgp_macro_test_util::{ + snapshot_cgp_new_provider, snapshot_delegate_components, snapshot_derive_cgp_data, +}; use futures::executor::block_on; -#[derive(Debug, Eq, PartialEq, CgpData)] -pub enum FooBarBaz { - Foo(u64), - Bar(String), - Baz(bool), +snapshot_derive_cgp_data! { + #[derive(CgpData)] + #[derive(Debug, Eq, PartialEq)] + pub enum FooBarBaz { + Foo(u64), + Bar(String), + Baz(bool), + } + + expand_foo_bar_baz(output) { + insta::assert_snapshot!(output, @" + impl HasFields for FooBarBaz { + type Fields = Either< + Field>>>, u64>, + Either< + Field>>>, String>, + Either>>>, bool>, Void>, + >, + >; + } + impl HasFieldsRef for FooBarBaz { + type FieldsRef<'__a> = Either< + Field>>>, &'__a u64>, + Either< + Field>>>, &'__a String>, + Either< + Field>>>, &'__a bool>, + Void, + >, + >, + > + where + Self: '__a; + } + impl FromFields for FooBarBaz { + fn from_fields(rest: Self::Fields) -> Self { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Foo(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Bar(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Baz(field) + } + Either::Right(rest) => match rest {} + } + } + } + } + } + } + } + impl ToFields for FooBarBaz { + fn to_fields(self) -> Self::Fields { + match self { + Self::Foo(field) => Either::Left(field.into()), + Self::Bar(field) => Either::Right(Either::Left(field.into())), + Self::Baz(field) => Either::Right(Either::Right(Either::Left(field.into()))), + } + } + } + impl ToFieldsRef for FooBarBaz { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + match self { + Self::Foo(field) => Either::Left(field.into()), + Self::Bar(field) => Either::Right(Either::Left(field.into())), + Self::Baz(field) => Either::Right(Either::Right(Either::Left(field.into()))), + } + } + } + impl FromVariant>>>> for FooBarBaz { + type Value = u64; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'F', Chars<'o', Chars<'o', Nil>>>>, + >, + value: Self::Value, + ) -> Self { + Self::Foo(value) + } + } + impl FromVariant>>>> for FooBarBaz { + type Value = String; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'r', Nil>>>>, + >, + value: Self::Value, + ) -> Self { + Self::Bar(value) + } + } + impl FromVariant>>>> for FooBarBaz { + type Value = bool; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'z', Nil>>>>, + >, + value: Self::Value, + ) -> Self { + Self::Baz(value) + } + } + pub enum __PartialFooBarBaz<__F0__: MapType, __F1__: MapType, __F2__: MapType> { + Foo(<__F0__ as MapType>::Map), + Bar(<__F1__ as MapType>::Map), + Baz(<__F2__ as MapType>::Map), + } + pub enum __PartialRefFooBarBaz< + '__a__, + __R__: MapTypeRef, + __F0__: MapType, + __F1__: MapType, + __F2__: MapType, + > { + Foo(<__F0__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, u64>>), + Bar(<__F1__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, String>>), + Baz(<__F2__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, bool>>), + } + impl<__F0__: MapType, __F1__: MapType, __F2__: MapType> PartialData + for __PartialFooBarBaz<__F0__, __F1__, __F2__> { + type Target = FooBarBaz; + } + impl< + '__a__, + __R__: MapTypeRef, + __F0__: MapType, + __F1__: MapType, + __F2__: MapType, + > PartialData for __PartialRefFooBarBaz<'__a__, __R__, __F0__, __F1__, __F2__> { + type Target = FooBarBaz; + } + impl HasExtractor for FooBarBaz { + type Extractor = __PartialFooBarBaz; + fn to_extractor(self) -> Self::Extractor { + match self { + Self::Foo(value) => __PartialFooBarBaz::Foo(value), + Self::Bar(value) => __PartialFooBarBaz::Bar(value), + Self::Baz(value) => __PartialFooBarBaz::Baz(value), + } + } + fn from_extractor(extractor: Self::Extractor) -> Self { + match extractor { + __PartialFooBarBaz::Foo(value) => Self::Foo(value), + __PartialFooBarBaz::Bar(value) => Self::Bar(value), + __PartialFooBarBaz::Baz(value) => Self::Baz(value), + } + } + } + impl HasExtractorRef for FooBarBaz { + type ExtractorRef<'a> = __PartialRefFooBarBaz< + 'a, + IsRef, + IsPresent, + IsPresent, + IsPresent, + > + where + Self: 'a; + fn extractor_ref<'a>(&'a self) -> Self::ExtractorRef<'a> { + match self { + Self::Foo(value) => __PartialRefFooBarBaz::Foo(value), + Self::Bar(value) => __PartialRefFooBarBaz::Bar(value), + Self::Baz(value) => __PartialRefFooBarBaz::Baz(value), + } + } + } + impl HasExtractorMut for FooBarBaz { + type ExtractorMut<'a> = __PartialRefFooBarBaz< + 'a, + IsMut, + IsPresent, + IsPresent, + IsPresent, + > + where + Self: 'a; + fn extractor_mut<'a>(&'a mut self) -> Self::ExtractorMut<'a> { + match self { + Self::Foo(value) => __PartialRefFooBarBaz::Foo(value), + Self::Bar(value) => __PartialRefFooBarBaz::Bar(value), + Self::Baz(value) => __PartialRefFooBarBaz::Baz(value), + } + } + } + impl FinalizeExtract for __PartialFooBarBaz { + fn finalize_extract<__T__>(self) -> __T__ { + match self {} + } + } + impl<'a, __R__: MapTypeRef> FinalizeExtract + for __PartialRefFooBarBaz<'a, __R__, IsVoid, IsVoid, IsVoid> { + fn finalize_extract<__T__>(self) -> __T__ { + match self {} + } + } + impl< + __F1__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialFooBarBaz { + type Value = u64; + type Remainder = __PartialFooBarBaz; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'F', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> Result { + match self { + __PartialFooBarBaz::Foo(value) => Ok(value), + __PartialFooBarBaz::Bar(value) => Err(__PartialFooBarBaz::Bar(value)), + __PartialFooBarBaz::Baz(value) => Err(__PartialFooBarBaz::Baz(value)), + } + } + } + impl< + __F0__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialFooBarBaz<__F0__, IsPresent, __F2__> { + type Value = String; + type Remainder = __PartialFooBarBaz<__F0__, IsVoid, __F2__>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> Result { + match self { + __PartialFooBarBaz::Foo(value) => Err(__PartialFooBarBaz::Foo(value)), + __PartialFooBarBaz::Bar(value) => Ok(value), + __PartialFooBarBaz::Baz(value) => Err(__PartialFooBarBaz::Baz(value)), + } + } + } + impl< + __F0__: MapType, + __F1__: MapType, + > ExtractField>>>> + for __PartialFooBarBaz<__F0__, __F1__, IsPresent> { + type Value = bool; + type Remainder = __PartialFooBarBaz<__F0__, __F1__, IsVoid>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> Result { + match self { + __PartialFooBarBaz::Foo(value) => Err(__PartialFooBarBaz::Foo(value)), + __PartialFooBarBaz::Bar(value) => Err(__PartialFooBarBaz::Bar(value)), + __PartialFooBarBaz::Baz(value) => Ok(value), + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + __F1__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialRefFooBarBaz<'__a__, __R__, IsPresent, __F1__, __F2__> { + type Value = <__R__ as MapTypeRef>::Map<'__a__, u64>; + type Remainder = __PartialRefFooBarBaz<'__a__, __R__, IsVoid, __F1__, __F2__>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'F', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> Result { + match self { + __PartialRefFooBarBaz::Foo(value) => Ok(value), + __PartialRefFooBarBaz::Bar(value) => Err(__PartialRefFooBarBaz::Bar(value)), + __PartialRefFooBarBaz::Baz(value) => Err(__PartialRefFooBarBaz::Baz(value)), + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + __F0__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialRefFooBarBaz<'__a__, __R__, __F0__, IsPresent, __F2__> { + type Value = <__R__ as MapTypeRef>::Map<'__a__, String>; + type Remainder = __PartialRefFooBarBaz<'__a__, __R__, __F0__, IsVoid, __F2__>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> Result { + match self { + __PartialRefFooBarBaz::Foo(value) => Err(__PartialRefFooBarBaz::Foo(value)), + __PartialRefFooBarBaz::Bar(value) => Ok(value), + __PartialRefFooBarBaz::Baz(value) => Err(__PartialRefFooBarBaz::Baz(value)), + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + __F0__: MapType, + __F1__: MapType, + > ExtractField>>>> + for __PartialRefFooBarBaz<'__a__, __R__, __F0__, __F1__, IsPresent> { + type Value = <__R__ as MapTypeRef>::Map<'__a__, bool>; + type Remainder = __PartialRefFooBarBaz<'__a__, __R__, __F0__, __F1__, IsVoid>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> Result { + match self { + __PartialRefFooBarBaz::Foo(value) => Err(__PartialRefFooBarBaz::Foo(value)), + __PartialRefFooBarBaz::Bar(value) => Err(__PartialRefFooBarBaz::Bar(value)), + __PartialRefFooBarBaz::Baz(value) => Ok(value), + } + } + } + ") + } } #[derive(Debug, Eq, PartialEq, CgpData)] diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/variants/generic.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/variants/generic.rs index 9213f8c9..c0ab9c7d 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/variants/generic.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/variants/generic.rs @@ -1,11 +1,470 @@ use cgp::core::field::impls::{CanDowncast, CanUpcast}; use cgp::prelude::*; +use cgp_macro_test_util::snapshot_derive_cgp_data; -#[derive(Debug, Eq, PartialEq, CgpData)] -pub enum FooBarBazGeneric { - Foo(Foo), - Bar(Bar), - Baz(Baz), +snapshot_derive_cgp_data! { + #[derive(CgpData)] + #[derive(Debug, Eq, PartialEq)] + pub enum FooBarBazGeneric { + Foo(Foo), + Bar(Bar), + Baz(Baz), + } + + expand_foo_bar_baz_generic(output) { + insta::assert_snapshot!(output, @" + impl HasFields for FooBarBazGeneric { + type Fields = Either< + Field>>>, Foo>, + Either< + Field>>>, Bar>, + Either>>>, Baz>, Void>, + >, + >; + } + impl HasFieldsRef for FooBarBazGeneric { + type FieldsRef<'__a> = Either< + Field>>>, &'__a Foo>, + Either< + Field>>>, &'__a Bar>, + Either< + Field>>>, &'__a Baz>, + Void, + >, + >, + > + where + Self: '__a; + } + impl FromFields for FooBarBazGeneric { + fn from_fields(rest: Self::Fields) -> Self { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Foo(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Bar(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Baz(field) + } + Either::Right(rest) => match rest {} + } + } + } + } + } + } + } + impl ToFields for FooBarBazGeneric { + fn to_fields(self) -> Self::Fields { + match self { + Self::Foo(field) => Either::Left(field.into()), + Self::Bar(field) => Either::Right(Either::Left(field.into())), + Self::Baz(field) => Either::Right(Either::Right(Either::Left(field.into()))), + } + } + } + impl ToFieldsRef for FooBarBazGeneric { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + match self { + Self::Foo(field) => Either::Left(field.into()), + Self::Bar(field) => Either::Right(Either::Left(field.into())), + Self::Baz(field) => Either::Right(Either::Right(Either::Left(field.into()))), + } + } + } + impl FromVariant>>>> + for FooBarBazGeneric { + type Value = Foo; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'F', Chars<'o', Chars<'o', Nil>>>>, + >, + value: Self::Value, + ) -> Self { + Self::Foo(value) + } + } + impl FromVariant>>>> + for FooBarBazGeneric { + type Value = Bar; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'r', Nil>>>>, + >, + value: Self::Value, + ) -> Self { + Self::Bar(value) + } + } + impl FromVariant>>>> + for FooBarBazGeneric { + type Value = Baz; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'z', Nil>>>>, + >, + value: Self::Value, + ) -> Self { + Self::Baz(value) + } + } + pub enum __PartialFooBarBazGeneric< + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + __F2__: MapType, + > { + Foo(<__F0__ as MapType>::Map), + Bar(<__F1__ as MapType>::Map), + Baz(<__F2__ as MapType>::Map), + } + pub enum __PartialRefFooBarBazGeneric< + '__a__, + __R__: MapTypeRef, + Foo: '__a__, + Bar: '__a__, + Baz: '__a__, + __F0__: MapType, + __F1__: MapType, + __F2__: MapType, + > { + Foo(<__F0__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, Foo>>), + Bar(<__F1__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, Bar>>), + Baz(<__F2__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, Baz>>), + } + impl PartialData + for __PartialFooBarBazGeneric { + type Target = FooBarBazGeneric; + } + impl< + '__a__, + __R__: MapTypeRef, + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + __F2__: MapType, + > PartialData + for __PartialRefFooBarBazGeneric<'__a__, __R__, Foo, Bar, Baz, __F0__, __F1__, __F2__> { + type Target = FooBarBazGeneric; + } + impl HasExtractor for FooBarBazGeneric { + type Extractor = __PartialFooBarBazGeneric< + Foo, + Bar, + Baz, + IsPresent, + IsPresent, + IsPresent, + >; + fn to_extractor(self) -> Self::Extractor { + match self { + Self::Foo(value) => __PartialFooBarBazGeneric::Foo(value), + Self::Bar(value) => __PartialFooBarBazGeneric::Bar(value), + Self::Baz(value) => __PartialFooBarBazGeneric::Baz(value), + } + } + fn from_extractor(extractor: Self::Extractor) -> Self { + match extractor { + __PartialFooBarBazGeneric::Foo(value) => Self::Foo(value), + __PartialFooBarBazGeneric::Bar(value) => Self::Bar(value), + __PartialFooBarBazGeneric::Baz(value) => Self::Baz(value), + } + } + } + impl HasExtractorRef for FooBarBazGeneric { + type ExtractorRef<'a> = __PartialRefFooBarBazGeneric< + 'a, + IsRef, + Foo, + Bar, + Baz, + IsPresent, + IsPresent, + IsPresent, + > + where + Self: 'a; + fn extractor_ref<'a>(&'a self) -> Self::ExtractorRef<'a> { + match self { + Self::Foo(value) => __PartialRefFooBarBazGeneric::Foo(value), + Self::Bar(value) => __PartialRefFooBarBazGeneric::Bar(value), + Self::Baz(value) => __PartialRefFooBarBazGeneric::Baz(value), + } + } + } + impl HasExtractorMut for FooBarBazGeneric { + type ExtractorMut<'a> = __PartialRefFooBarBazGeneric< + 'a, + IsMut, + Foo, + Bar, + Baz, + IsPresent, + IsPresent, + IsPresent, + > + where + Self: 'a; + fn extractor_mut<'a>(&'a mut self) -> Self::ExtractorMut<'a> { + match self { + Self::Foo(value) => __PartialRefFooBarBazGeneric::Foo(value), + Self::Bar(value) => __PartialRefFooBarBazGeneric::Bar(value), + Self::Baz(value) => __PartialRefFooBarBazGeneric::Baz(value), + } + } + } + impl FinalizeExtract + for __PartialFooBarBazGeneric { + fn finalize_extract<__T__>(self) -> __T__ { + match self {} + } + } + impl<'a, __R__: MapTypeRef, Foo, Bar, Baz> FinalizeExtract + for __PartialRefFooBarBazGeneric<'a, __R__, Foo, Bar, Baz, IsVoid, IsVoid, IsVoid> { + fn finalize_extract<__T__>(self) -> __T__ { + match self {} + } + } + impl< + Foo, + Bar, + Baz, + __F1__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialFooBarBazGeneric { + type Value = Foo; + type Remainder = __PartialFooBarBazGeneric; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'F', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> Result { + match self { + __PartialFooBarBazGeneric::Foo(value) => Ok(value), + __PartialFooBarBazGeneric::Bar(value) => { + Err(__PartialFooBarBazGeneric::Bar(value)) + } + __PartialFooBarBazGeneric::Baz(value) => { + Err(__PartialFooBarBazGeneric::Baz(value)) + } + } + } + } + impl< + Foo, + Bar, + Baz, + __F0__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialFooBarBazGeneric { + type Value = Bar; + type Remainder = __PartialFooBarBazGeneric; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> Result { + match self { + __PartialFooBarBazGeneric::Foo(value) => { + Err(__PartialFooBarBazGeneric::Foo(value)) + } + __PartialFooBarBazGeneric::Bar(value) => Ok(value), + __PartialFooBarBazGeneric::Baz(value) => { + Err(__PartialFooBarBazGeneric::Baz(value)) + } + } + } + } + impl< + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + > ExtractField>>>> + for __PartialFooBarBazGeneric { + type Value = Baz; + type Remainder = __PartialFooBarBazGeneric; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> Result { + match self { + __PartialFooBarBazGeneric::Foo(value) => { + Err(__PartialFooBarBazGeneric::Foo(value)) + } + __PartialFooBarBazGeneric::Bar(value) => { + Err(__PartialFooBarBazGeneric::Bar(value)) + } + __PartialFooBarBazGeneric::Baz(value) => Ok(value), + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + Foo, + Bar, + Baz, + __F1__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialRefFooBarBazGeneric< + '__a__, + __R__, + Foo, + Bar, + Baz, + IsPresent, + __F1__, + __F2__, + > { + type Value = <__R__ as MapTypeRef>::Map<'__a__, Foo>; + type Remainder = __PartialRefFooBarBazGeneric< + '__a__, + __R__, + Foo, + Bar, + Baz, + IsVoid, + __F1__, + __F2__, + >; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'F', Chars<'o', Chars<'o', Nil>>>>, + >, + ) -> Result { + match self { + __PartialRefFooBarBazGeneric::Foo(value) => Ok(value), + __PartialRefFooBarBazGeneric::Bar(value) => { + Err(__PartialRefFooBarBazGeneric::Bar(value)) + } + __PartialRefFooBarBazGeneric::Baz(value) => { + Err(__PartialRefFooBarBazGeneric::Baz(value)) + } + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + Foo, + Bar, + Baz, + __F0__: MapType, + __F2__: MapType, + > ExtractField>>>> + for __PartialRefFooBarBazGeneric< + '__a__, + __R__, + Foo, + Bar, + Baz, + __F0__, + IsPresent, + __F2__, + > { + type Value = <__R__ as MapTypeRef>::Map<'__a__, Bar>; + type Remainder = __PartialRefFooBarBazGeneric< + '__a__, + __R__, + Foo, + Bar, + Baz, + __F0__, + IsVoid, + __F2__, + >; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'r', Nil>>>>, + >, + ) -> Result { + match self { + __PartialRefFooBarBazGeneric::Foo(value) => { + Err(__PartialRefFooBarBazGeneric::Foo(value)) + } + __PartialRefFooBarBazGeneric::Bar(value) => Ok(value), + __PartialRefFooBarBazGeneric::Baz(value) => { + Err(__PartialRefFooBarBazGeneric::Baz(value)) + } + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + Foo, + Bar, + Baz, + __F0__: MapType, + __F1__: MapType, + > ExtractField>>>> + for __PartialRefFooBarBazGeneric< + '__a__, + __R__, + Foo, + Bar, + Baz, + __F0__, + __F1__, + IsPresent, + > { + type Value = <__R__ as MapTypeRef>::Map<'__a__, Baz>; + type Remainder = __PartialRefFooBarBazGeneric< + '__a__, + __R__, + Foo, + Bar, + Baz, + __F0__, + __F1__, + IsVoid, + >; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol<3, Chars<'B', Chars<'a', Chars<'z', Nil>>>>, + >, + ) -> Result { + match self { + __PartialRefFooBarBazGeneric::Foo(value) => { + Err(__PartialRefFooBarBazGeneric::Foo(value)) + } + __PartialRefFooBarBazGeneric::Bar(value) => { + Err(__PartialRefFooBarBazGeneric::Bar(value)) + } + __PartialRefFooBarBazGeneric::Baz(value) => Ok(value), + } + } + } + ") + } } #[derive(Debug, Eq, PartialEq, CgpData)] diff --git a/crates/tests/cgp-tests/tests/extensible_data_tests/variants/shape.rs b/crates/tests/cgp-tests/tests/extensible_data_tests/variants/shape.rs index d2024e6c..7a98bf4a 100644 --- a/crates/tests/cgp-tests/tests/extensible_data_tests/variants/shape.rs +++ b/crates/tests/cgp-tests/tests/extensible_data_tests/variants/shape.rs @@ -8,12 +8,437 @@ use cgp::extra::dispatch::{ }; use cgp::extra::handler::{NoCode, UseInputDelegate}; use cgp::prelude::*; -use cgp_macro_test_util::{snapshot_check_components, snapshot_delegate_components}; +use cgp_macro_test_util::{ + snapshot_check_components, snapshot_delegate_components, snapshot_derive_cgp_data, +}; -#[derive(Debug, PartialEq, CgpData)] -pub enum Shape { - Circle(Circle), - Rectangle(Rectangle), +snapshot_derive_cgp_data! { + #[derive(CgpData)] + #[derive(Debug, PartialEq)] + pub enum Shape { + Circle(Circle), + Rectangle(Rectangle), + } + + expand_shape(output) { + insta::assert_snapshot!(output, @" + impl HasFields for Shape { + type Fields = Either< + Field< + Symbol< + 6, + Chars< + 'C', + Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + Circle, + >, + Either< + Field< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars< + 'a', + Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + Rectangle, + >, + Void, + >, + >; + } + impl HasFieldsRef for Shape { + type FieldsRef<'__a> = Either< + Field< + Symbol< + 6, + Chars< + 'C', + Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + &'__a Circle, + >, + Either< + Field< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars< + 'a', + Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + &'__a Rectangle, + >, + Void, + >, + > + where + Self: '__a; + } + impl FromFields for Shape { + fn from_fields(rest: Self::Fields) -> Self { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Circle(field) + } + Either::Right(rest) => { + match rest { + Either::Left(field) => { + let field = field.value; + Self::Rectangle(field) + } + Either::Right(rest) => match rest {} + } + } + } + } + } + impl ToFields for Shape { + fn to_fields(self) -> Self::Fields { + match self { + Self::Circle(field) => Either::Left(field.into()), + Self::Rectangle(field) => Either::Right(Either::Left(field.into())), + } + } + } + impl ToFieldsRef for Shape { + fn to_fields_ref<'__a>(&'__a self) -> Self::FieldsRef<'__a> + where + Self: '__a, + { + match self { + Self::Circle(field) => Either::Left(field.into()), + Self::Rectangle(field) => Either::Right(Either::Left(field.into())), + } + } + } + impl FromVariant< + Symbol< + 6, + Chars<'C', Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>>, + >, + > for Shape { + type Value = Circle; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol< + 6, + Chars< + 'C', + Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + >, + value: Self::Value, + ) -> Self { + Self::Circle(value) + } + } + impl FromVariant< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars<'a', Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + > for Shape { + type Value = Rectangle; + fn from_variant( + _tag: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars< + 'a', + Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + value: Self::Value, + ) -> Self { + Self::Rectangle(value) + } + } + pub enum __PartialShape<__F0__: MapType, __F1__: MapType> { + Circle(<__F0__ as MapType>::Map), + Rectangle(<__F1__ as MapType>::Map), + } + pub enum __PartialRefShape<'__a__, __R__: MapTypeRef, __F0__: MapType, __F1__: MapType> { + Circle(<__F0__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, Circle>>), + Rectangle(<__F1__ as MapType>::Map<<__R__ as MapTypeRef>::Map<'__a__, Rectangle>>), + } + impl<__F0__: MapType, __F1__: MapType> PartialData for __PartialShape<__F0__, __F1__> { + type Target = Shape; + } + impl<'__a__, __R__: MapTypeRef, __F0__: MapType, __F1__: MapType> PartialData + for __PartialRefShape<'__a__, __R__, __F0__, __F1__> { + type Target = Shape; + } + impl HasExtractor for Shape { + type Extractor = __PartialShape; + fn to_extractor(self) -> Self::Extractor { + match self { + Self::Circle(value) => __PartialShape::Circle(value), + Self::Rectangle(value) => __PartialShape::Rectangle(value), + } + } + fn from_extractor(extractor: Self::Extractor) -> Self { + match extractor { + __PartialShape::Circle(value) => Self::Circle(value), + __PartialShape::Rectangle(value) => Self::Rectangle(value), + } + } + } + impl HasExtractorRef for Shape { + type ExtractorRef<'a> = __PartialRefShape<'a, IsRef, IsPresent, IsPresent> + where + Self: 'a; + fn extractor_ref<'a>(&'a self) -> Self::ExtractorRef<'a> { + match self { + Self::Circle(value) => __PartialRefShape::Circle(value), + Self::Rectangle(value) => __PartialRefShape::Rectangle(value), + } + } + } + impl HasExtractorMut for Shape { + type ExtractorMut<'a> = __PartialRefShape<'a, IsMut, IsPresent, IsPresent> + where + Self: 'a; + fn extractor_mut<'a>(&'a mut self) -> Self::ExtractorMut<'a> { + match self { + Self::Circle(value) => __PartialRefShape::Circle(value), + Self::Rectangle(value) => __PartialRefShape::Rectangle(value), + } + } + } + impl FinalizeExtract for __PartialShape { + fn finalize_extract<__T__>(self) -> __T__ { + match self {} + } + } + impl<'a, __R__: MapTypeRef> FinalizeExtract + for __PartialRefShape<'a, __R__, IsVoid, IsVoid> { + fn finalize_extract<__T__>(self) -> __T__ { + match self {} + } + } + impl< + __F1__: MapType, + > ExtractField< + Symbol< + 6, + Chars<'C', Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>>, + >, + > for __PartialShape { + type Value = Circle; + type Remainder = __PartialShape; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol< + 6, + Chars< + 'C', + Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + >, + ) -> Result { + match self { + __PartialShape::Circle(value) => Ok(value), + __PartialShape::Rectangle(value) => Err(__PartialShape::Rectangle(value)), + } + } + } + impl< + __F0__: MapType, + > ExtractField< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars<'a', Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + > for __PartialShape<__F0__, IsPresent> { + type Value = Rectangle; + type Remainder = __PartialShape<__F0__, IsVoid>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars< + 'a', + Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + ) -> Result { + match self { + __PartialShape::Circle(value) => Err(__PartialShape::Circle(value)), + __PartialShape::Rectangle(value) => Ok(value), + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + __F1__: MapType, + > ExtractField< + Symbol< + 6, + Chars<'C', Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>>, + >, + > for __PartialRefShape<'__a__, __R__, IsPresent, __F1__> { + type Value = <__R__ as MapTypeRef>::Map<'__a__, Circle>; + type Remainder = __PartialRefShape<'__a__, __R__, IsVoid, __F1__>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol< + 6, + Chars< + 'C', + Chars<'i', Chars<'r', Chars<'c', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + >, + ) -> Result { + match self { + __PartialRefShape::Circle(value) => Ok(value), + __PartialRefShape::Rectangle(value) => { + Err(__PartialRefShape::Rectangle(value)) + } + } + } + } + impl< + '__a__, + __R__: MapTypeRef, + __F0__: MapType, + > ExtractField< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars<'a', Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>>, + >, + >, + >, + >, + >, + > for __PartialRefShape<'__a__, __R__, __F0__, IsPresent> { + type Value = <__R__ as MapTypeRef>::Map<'__a__, Rectangle>; + type Remainder = __PartialRefShape<'__a__, __R__, __F0__, IsVoid>; + fn extract_field( + self, + _tag: ::core::marker::PhantomData< + Symbol< + 9, + Chars< + 'R', + Chars< + 'e', + Chars< + 'c', + Chars< + 't', + Chars< + 'a', + Chars<'n', Chars<'g', Chars<'l', Chars<'e', Nil>>>>, + >, + >, + >, + >, + >, + >, + >, + ) -> Result { + match self { + __PartialRefShape::Circle(value) => Err(__PartialRefShape::Circle(value)), + __PartialRefShape::Rectangle(value) => Ok(value), + } + } + } + ") + } } #[derive(Debug, PartialEq, CgpData)] diff --git a/crates/tests/cgp-tests/tests/getter_tests/abstract_type/explicit.rs b/crates/tests/cgp-tests/tests/getter_tests/abstract_type/explicit.rs index 5d5d5dc4..ce61576e 100644 --- a/crates/tests/cgp-tests/tests/getter_tests/abstract_type/explicit.rs +++ b/crates/tests/cgp-tests/tests/getter_tests/abstract_type/explicit.rs @@ -1,4 +1,3 @@ -use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_auto_getter, snapshot_cgp_getter, snapshot_cgp_type}; snapshot_cgp_type! { @@ -86,8 +85,8 @@ snapshot_cgp_type! { impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, { type Scalar = Scalar; } @@ -98,8 +97,8 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, {} ") } diff --git a/crates/tests/cgp-tests/tests/getter_tests/abstract_type/import.rs b/crates/tests/cgp-tests/tests/getter_tests/abstract_type/import.rs index ecbf733a..ef603bbb 100644 --- a/crates/tests/cgp-tests/tests/getter_tests/abstract_type/import.rs +++ b/crates/tests/cgp-tests/tests/getter_tests/abstract_type/import.rs @@ -1,4 +1,3 @@ -use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_auto_getter, snapshot_cgp_getter, snapshot_cgp_type}; snapshot_cgp_type! { @@ -86,8 +85,8 @@ snapshot_cgp_type! { impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, { type Scalar = Scalar; } @@ -98,8 +97,8 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, {} ") } diff --git a/crates/tests/cgp-tests/tests/getter_tests/abstract_type/use_type.rs b/crates/tests/cgp-tests/tests/getter_tests/abstract_type/use_type.rs index ecbf733a..ef603bbb 100644 --- a/crates/tests/cgp-tests/tests/getter_tests/abstract_type/use_type.rs +++ b/crates/tests/cgp-tests/tests/getter_tests/abstract_type/use_type.rs @@ -1,4 +1,3 @@ -use cgp::prelude::*; use cgp_macro_test_util::{snapshot_cgp_auto_getter, snapshot_cgp_getter, snapshot_cgp_type}; snapshot_cgp_type! { @@ -86,8 +85,8 @@ snapshot_cgp_type! { impl<__Provider__, Scalar, __Context__> ScalarTypeProvider<__Context__> for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, { type Scalar = Scalar; } @@ -98,8 +97,8 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where - __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, Scalar: Copy, + __Provider__: TypeProvider<__Context__, ScalarTypeProviderComponent, Type = Scalar>, {} ") } diff --git a/crates/tests/cgp-tests/tests/getter_tests/clone.rs b/crates/tests/cgp-tests/tests/getter_tests/clone.rs index 4355a627..25599ccc 100644 --- a/crates/tests/cgp-tests/tests/getter_tests/clone.rs +++ b/crates/tests/cgp-tests/tests/getter_tests/clone.rs @@ -75,22 +75,15 @@ mod clone_getter { >>::Delegate: IsProviderFor + NameTypeProvider<__Context__>, {} - impl NameTypeProvider<__Context__> for UseType - where - Name:, - { + impl NameTypeProvider<__Context__> for UseType { type Name = Name; } impl IsProviderFor - for UseType - where - Name:, - {} + for UseType {} impl<__Provider__, Name, __Context__> NameTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, { type Name = Name; } @@ -102,7 +95,6 @@ mod clone_getter { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, {} ") } @@ -387,22 +379,15 @@ mod clone_auto_getter { >>::Delegate: IsProviderFor + NameTypeProvider<__Context__>, {} - impl NameTypeProvider<__Context__> for UseType - where - Name:, - { + impl NameTypeProvider<__Context__> for UseType { type Name = Name; } impl IsProviderFor - for UseType - where - Name:, - {} + for UseType {} impl<__Provider__, Name, __Context__> NameTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, { type Name = Name; } @@ -414,7 +399,6 @@ mod clone_auto_getter { for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, NameTypeProviderComponent, Type = Name>, - Name:, {} ") } diff --git a/crates/tests/cgp-tests/tests/getter_tests/non_self.rs b/crates/tests/cgp-tests/tests/getter_tests/non_self.rs index 0af7397b..3aade009 100644 --- a/crates/tests/cgp-tests/tests/getter_tests/non_self.rs +++ b/crates/tests/cgp-tests/tests/getter_tests/non_self.rs @@ -71,22 +71,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + FooTypeProvider<__Context__>, {} - impl FooTypeProvider<__Context__> for UseType - where - Foo:, - { + impl FooTypeProvider<__Context__> for UseType { type Foo = Foo; } impl IsProviderFor - for UseType - where - Foo:, - {} + for UseType {} impl<__Provider__, Foo, __Context__> FooTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -97,7 +90,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, {} ") } @@ -173,22 +165,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + BarTypeProvider<__Context__>, {} - impl BarTypeProvider<__Context__> for UseType - where - Bar:, - { + impl BarTypeProvider<__Context__> for UseType { type Bar = Bar; } impl IsProviderFor - for UseType - where - Bar:, - {} + for UseType {} impl<__Provider__, Bar, __Context__> BarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, { type Bar = Bar; } @@ -199,7 +184,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, {} ") } diff --git a/crates/tests/cgp-tests/tests/getter_tests/non_self_auto.rs b/crates/tests/cgp-tests/tests/getter_tests/non_self_auto.rs index f1bdeda6..0fc47e79 100644 --- a/crates/tests/cgp-tests/tests/getter_tests/non_self_auto.rs +++ b/crates/tests/cgp-tests/tests/getter_tests/non_self_auto.rs @@ -73,22 +73,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + FooTypeProvider<__Context__>, {} - impl FooTypeProvider<__Context__> for UseType - where - Foo:, - { + impl FooTypeProvider<__Context__> for UseType { type Foo = Foo; } impl IsProviderFor - for UseType - where - Foo:, - {} + for UseType {} impl<__Provider__, Foo, __Context__> FooTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, { type Foo = Foo; } @@ -99,7 +92,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, FooTypeProviderComponent, Type = Foo>, - Foo:, {} ") } @@ -175,22 +167,15 @@ snapshot_cgp_type! { >>::Delegate: IsProviderFor + BarTypeProvider<__Context__>, {} - impl BarTypeProvider<__Context__> for UseType - where - Bar:, - { + impl BarTypeProvider<__Context__> for UseType { type Bar = Bar; } impl IsProviderFor - for UseType - where - Bar:, - {} + for UseType {} impl<__Provider__, Bar, __Context__> BarTypeProvider<__Context__> for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, { type Bar = Bar; } @@ -201,7 +186,6 @@ snapshot_cgp_type! { > IsProviderFor for WithProvider<__Provider__> where __Provider__: TypeProvider<__Context__, BarTypeProviderComponent, Type = Bar>, - Bar:, {} ") }