use core::marker::PhantomData;
use crate::traits::{BuildField, HasFields, IntoBuilder, TakeField};
use crate::types::{Cons, Field, Nil};
pub trait CanBuildFrom<Source> {
type Output;
fn build_from(self, source: Source) -> Self::Output;
}
impl<Builder, Source, Output> CanBuildFrom<Source> for Builder
where
Source: HasFields + IntoBuilder,
Source::Fields: FieldsBuilder<Source::Builder, Builder, Output = Output>,
{
type Output = Output;
fn build_from(self, source: Source) -> Output {
Source::Fields::build_fields(source.into_builder(), self)
}
}
trait FieldsBuilder<Source, Target> {
type Output;
fn build_fields(source: Source, target: Target) -> Self::Output;
}
impl<Source, Target, RestFields, Tag, Value> FieldsBuilder<Source, Target>
for Cons<Field<Tag, Value>, RestFields>
where
Source: TakeField<Tag, Value = Value>,
Target: BuildField<Tag, Value = Value>,
RestFields: FieldsBuilder<Source::Remainder, Target::Output>,
{
type Output = RestFields::Output;
fn build_fields(source: Source, target: Target) -> Self::Output {
let (value, next_source) = source.take_field(PhantomData);
let next_target = target.build_field(PhantomData, value);
RestFields::build_fields(next_source, next_target)
}
}
impl<Source, Target> FieldsBuilder<Source, Target> for Nil {
type Output = Target;
fn build_fields(_source: Source, target: Target) -> Self::Output {
target
}
}