Skip to content
4 changes: 2 additions & 2 deletions crates/cgp-core/src/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ pub use cgp_field::{
BuildField, Char, Cons, Either, ExtractField, Field, FieldGetter, FinalizeBuild,
FinalizeExtract, FromFields, FromVariant, HasBuilder, HasExtractor, HasExtractorMut,
HasExtractorRef, HasField, HasFieldMut, HasFields, HasFieldsRef, Index, IntoBuilder, IsMut,
IsNothing, IsPresent, IsRef, IsVoid, MapType, MapTypeRef, MutFieldGetter, Nil, TakeField,
ToFields, ToFieldsRef, TransformMap, TransformMapFields, UseField, Void,
IsNothing, IsPresent, IsRef, IsVoid, MapType, MapTypeRef, MutFieldGetter, Nil, PartialData,
ToFields, ToFieldsRef, UpdateField, UseField, Void,
};
pub use cgp_macro::{
cgp_auto_getter, cgp_component, cgp_context, cgp_getter, cgp_new_provider, cgp_preset,
Expand Down
25 changes: 14 additions & 11 deletions crates/cgp-field/src/traits/build_field.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
use core::marker::PhantomData;

pub trait HasBuilder {
type Builder;

fn builder() -> Self::Builder;
}

pub trait IntoBuilder {
type Builder;

fn into_builder(self) -> Self::Builder;
}
use crate::{IsNothing, IsPresent, UpdateField};

pub trait BuildField<Tag> {
type Value;
Expand All @@ -20,6 +10,19 @@ pub trait BuildField<Tag> {
fn build_field(self, _tag: PhantomData<Tag>, value: Self::Value) -> Self::Output;
}

impl<Context, Tag> BuildField<Tag> for Context
where
Context: UpdateField<Tag, IsPresent, Mapper = IsNothing>,
{
type Value = Context::Value;

type Output = Context::Output;

fn build_field(self, tag: PhantomData<Tag>, value: Self::Value) -> Self::Output {
self.update_field(tag, value).1
}
}

pub trait FinalizeBuild {
type Output;

Expand Down
11 changes: 11 additions & 0 deletions crates/cgp-field/src/traits/has_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
pub trait HasBuilder {
type Builder;

fn builder() -> Self::Builder;
}

pub trait IntoBuilder {
type Builder;

fn into_builder(self) -> Self::Builder;
}
6 changes: 6 additions & 0 deletions crates/cgp-field/src/traits/map_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,9 @@ pub struct IsVoid;
impl MapType for IsVoid {
type Map<T> = Void;
}

pub struct IsOptional;

impl MapType for IsOptional {
type Map<T> = Option<T>;
}
6 changes: 6 additions & 0 deletions crates/cgp-field/src/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,35 @@ mod extract_field;
mod format;
mod from_fields;
mod from_variant;
mod has_builder;
mod has_field;
mod has_field_mut;
mod has_fields;
mod map_field;
mod map_fields;
mod map_type;
mod map_type_ref;
mod partial_data;
mod take_field;
mod to_fields;
mod transform_map;
mod update_field;

pub use build_field::*;
pub use extract_field::*;
pub use format::*;
pub use from_fields::*;
pub use from_variant::*;
pub use has_builder::*;
pub use has_field::*;
pub use has_field_mut::*;
pub use has_fields::*;
pub use map_field::*;
pub use map_fields::*;
pub use map_type::*;
pub use map_type_ref::*;
pub use partial_data::*;
pub use take_field::*;
pub use to_fields::*;
pub use transform_map::*;
pub use update_field::*;
3 changes: 3 additions & 0 deletions crates/cgp-field/src/traits/partial_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub trait PartialData {
type Target;
}
15 changes: 15 additions & 0 deletions crates/cgp-field/src/traits/take_field.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
use core::marker::PhantomData;

use crate::{IsNothing, IsPresent, UpdateField};

pub trait TakeField<Tag> {
type Value;

type Remainder;

fn take_field(self, _tag: PhantomData<Tag>) -> (Self::Value, Self::Remainder);
}

impl<Context, Tag> TakeField<Tag> for Context
where
Context: UpdateField<Tag, IsNothing, Mapper = IsPresent>,
{
type Value = Context::Value;

type Remainder = Context::Output;

fn take_field(self, tag: PhantomData<Tag>) -> (Self::Value, Self::Remainder) {
self.update_field(tag, ())
}
}
61 changes: 57 additions & 4 deletions crates/cgp-field/src/traits/transform_map.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,65 @@
use crate::MapType;
use core::marker::PhantomData;

use crate::{Cons, Field, HasFields, IsNothing, MapType, Nil, PartialData, UpdateField};

/// Natural transformation from M1::Map<T> to M2::Map<T>
pub trait TransformMap<M1: MapType, M2: MapType, T> {
fn transform_mapped(value: M1::Map<T>) -> M2::Map<T>;
}

pub trait TransformMapFields<Transform, TargetMap> {
type Output;

fn transform_map_fields(self) -> Self::Output;
}

/// Natural transformation from M1::Map<T> to M2::Map<T>
pub trait TransformMap<M1: MapType, M2: MapType, T> {
fn transform_mapped(value: M1::Map<T>) -> M2::Map<T>;
impl<ContextA, ContextB, Transform, TargetMap, Output> TransformMapFields<Transform, TargetMap>
for ContextA
where
ContextA: PartialData<Target = ContextB>,
ContextB: HasFields,
ContextB::Fields: TransformMapFieldsImpl<ContextA, Transform, TargetMap, Output = Output>,
{
type Output = Output;

fn transform_map_fields(self) -> Self::Output {
ContextB::Fields::transform_map_fields(self)
}
}

trait TransformMapFieldsImpl<Context, Transform, TargetMap> {
type Output;

fn transform_map_fields(context: Context) -> Self::Output;
}

impl<Context, Transform, TargetMap> TransformMapFieldsImpl<Context, Transform, TargetMap> for Nil {
type Output = Context;

fn transform_map_fields(context: Context) -> Self::Output {
context
}
}

impl<Tag, Value, Tail, ContextA, ContextB, ContextC, ContextD, Transform, TargetMap, SourceMap>
TransformMapFieldsImpl<ContextA, Transform, TargetMap> for Cons<Field<Tag, Value>, Tail>
where
TargetMap: MapType,
SourceMap: MapType,
Tail: TransformMapFieldsImpl<ContextA, Transform, TargetMap, Output = ContextB>,
ContextB: UpdateField<Tag, IsNothing, Value = Value, Mapper = SourceMap, Output = ContextC>,
ContextC: UpdateField<Tag, TargetMap, Value = Value, Output = ContextD>,
Transform: TransformMap<SourceMap, TargetMap, Value>,
{
type Output = ContextD;

fn transform_map_fields(context_a: ContextA) -> Self::Output {
let context_b = Tail::transform_map_fields(context_a);

let (value_a, context_c) = context_b.update_field(PhantomData, ());
let value_b = Transform::transform_mapped(value_a);
let (_, context_d) = context_c.update_field(PhantomData, value_b);

context_d
}
}
17 changes: 17 additions & 0 deletions crates/cgp-field/src/traits/update_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use core::marker::PhantomData;

use crate::MapType;

pub trait UpdateField<Tag, M: MapType> {
type Value;

type Mapper: MapType;

type Output;

fn update_field(
self,
_tag: PhantomData<Tag>,
value: M::Map<Self::Value>,
) -> (<Self::Mapper as MapType>::Map<Self::Value>, Self::Output);
}
85 changes: 0 additions & 85 deletions crates/cgp-macro-lib/src/derive_builder/build_field_impls.rs

This file was deleted.

10 changes: 4 additions & 6 deletions crates/cgp-macro-lib/src/derive_builder/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
mod build_field_impls;
mod builder_struct;
mod finalize_build_impl;
mod has_builder_impl;
mod has_field_impls;
mod into_builder_impl;
mod take_field_impls;
mod transform_map_impl;
mod partial_data;
mod update_field_impls;
mod utils;

pub use build_field_impls::*;
pub use builder_struct::*;
pub use finalize_build_impl::*;
pub use has_builder_impl::*;
pub use has_field_impls::*;
pub use into_builder_impl::*;
pub use take_field_impls::*;
pub use transform_map_impl::*;
pub use partial_data::*;
pub use update_field_impls::*;
pub use utils::*;
35 changes: 35 additions & 0 deletions crates/cgp-macro-lib/src/derive_builder/partial_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use quote::quote;
use syn::{parse2, Ident, ItemImpl, ItemStruct};

use crate::derive_builder::index_to_generic_ident;

pub fn derive_partial_data_impl(
context_struct: &ItemStruct,
builder_ident: &Ident,
) -> syn::Result<ItemImpl> {
let mut generics = context_struct.generics.clone();

for (index, _) in context_struct.fields.iter().enumerate() {
let generic_param_name = index_to_generic_ident(index);

generics.params.push(parse2(quote! {
#generic_param_name: MapType
})?);
}

let (impl_generics, type_generics, where_clause) = generics.split_for_impl();

let context_ident = &context_struct.ident;
let context_generics = context_struct.generics.split_for_impl().1;

let item_impl = parse2(quote! {
impl #impl_generics PartialData
for #builder_ident #type_generics
#where_clause
{
type Target = #context_ident #context_generics;
}
})?;

Ok(item_impl)
}
Loading
Loading