WIP: define binding behaviour for diff->GenNode

...need still to solve a problem with circular definition dependencies
This commit is contained in:
Fischlurch 2016-09-01 22:58:08 +02:00
parent c791763890
commit f907ff05d6
4 changed files with 130 additions and 70 deletions

View file

@ -190,9 +190,11 @@ namespace diff{
template<typename X>
X const& get() const;
/** determine if payload constitutes a nested scope ("object") */
bool isNested() const;
/** peek into the type field of a nested `Record<GenNode>` */
string
recordType() const;
string recordType() const;
/** visit _children_ of a nested `Record<GenNode>` */
Rec::scopeIter
@ -712,6 +714,12 @@ namespace diff{
: util::BOTTOM_INDICATOR;
}
inline bool
DataCap::isNested() const
{
return util::BOTTOM_INDICATOR != recordType();
}

View file

@ -76,11 +76,11 @@
* an otherwise opaque implementation data structure.
*
* @tparam COLL a STL compliant collection type holding "child elements"
* @tparam MAT a closure to determine if a child matches a diff spec (GenNode)
* @tparam CTR a closure to construct a new child element from a given diff spec
* @tparam MAT a functor to determine if a child matches a diff spec (GenNode)
* @tparam CTR a functor to construct a new child element from a given diff spec
* @tparam SEL predicate to determine if this binding layer has to process a diff message
* @tparam ASS a closure to assign / set a new value from a given diff spec
* @tparam MUT a closure to construct a nested mutator for some child element
* @tparam ASS a functor to assign / set a new value from a given diff spec
* @tparam MUT a functor to construct a nested mutator for some child element
*/
template<class COLL, class MAT, class CTR, class SEL, class ASS, class MUT>
struct CollectionBinding
@ -436,42 +436,70 @@
};
using lib::meta::enable_if;
using lib::diff::can_wrap_in_GenNode;
/** builder function to synthesise builder type from given functors */
template<class COLL, class MAT, class CTR, class SEL, class ASS, class MUT>
inline auto
createCollectionBindingBuilder (COLL& coll, MAT m, CTR c, SEL s, ASS a, MUT u)
{
using Coll = typename Strip<COLL>::TypeReferred;
return CollectionBindingBuilder<Coll, MAT,CTR,SEL,ASS,MUT> {coll, m,c,s,a,u};
}
template<typename ELM, typename SEL =void>
struct _DefaultPayload
template<class ELM>
struct _EmptyBinding
{
static bool
match (GenNode const&, ELM const&)
__ERROR_missing_matcher (GenNode const&, ELM const&)
{
throw error::Logic ("unable to build a sensible default matching predicate");
}
static ELM
construct (GenNode const&)
__ERROR_missing_constructor (GenNode const&)
{
throw error::Logic ("unable to build a sensible default for creating new elements");
}
};
template<typename ELM>
struct _DefaultPayload<ELM, enable_if<can_wrap_in_GenNode<ELM>>>
{
static bool
match (GenNode const& spec, ELM const& elm)
ignore_selector (GenNode const&)
{
return spec.matches(elm);
return true; // by default apply diff unconditionally
}
static ELM
construct (GenNode const& spec)
static bool
disable_assignment (ELM&, GenNode const&)
{
return spec.data.get<ELM>();
return false;
}
static bool
disable_childMutation (ELM&, GenNode::ID const&, TreeMutator::Handle)
{
return false;
}
template<class COLL>
static auto
attachTo (COLL& coll)
{
return createCollectionBindingBuilder (coll
,__ERROR_missing_matcher
,__ERROR_missing_constructor
,ignore_selector
,disable_assignment
,disable_childMutation
);
}
};
using lib::meta::enable_if;
using lib::diff::can_wrap_in_GenNode;
/**
* starting point for configuration of a binding to STL container.
* When using the "nested DSL" to setup a binding to child elements
@ -482,56 +510,74 @@
* the created (\ref CollectionBindingBuilder) to replace
* those defaults with lambdas tied into the actual
* implementation of the target data structure.
* @note depending on the payload type within the collection,
* we provide some preconfigured default specialisations
*/
template<class COLL>
template<class ELM, typename SEL =void>
struct _DefaultBinding
: _EmptyBinding<ELM>
{ };
template<class ELM>
struct _DefaultBinding<ELM, enable_if<can_wrap_in_GenNode<ELM>>>
{
using Coll = typename Strip<COLL>::TypeReferred;
using Elm = typename Coll::value_type;
using Payload = _DefaultPayload<Elm>;
static bool
ignore_selector (GenNode const&)
template<class COLL>
static auto
attachTo (COLL& coll)
{
return true; // by default apply diff unconditionally
}
static bool
disable_assignment (Elm&, GenNode const&)
{
return false;
}
static bool
disable_childMutation (Elm&, GenNode::ID const&, TreeMutator::Handle)
{
return false;
}
using FallbackBindingConfiguration
= CollectionBindingBuilder<Coll
,decltype(&Payload::match)
,decltype(&Payload::construct)
,decltype(&ignore_selector)
,decltype(&disable_assignment)
,decltype(&disable_childMutation)
>;
static FallbackBindingConfiguration
attachTo (Coll& coll)
{
return FallbackBindingConfiguration{ coll
, Payload::match
, Payload::construct
, ignore_selector
, disable_assignment
, disable_childMutation
};
return _EmptyBinding<ELM>::attachTo(coll)
.matchElement([](GenNode const& spec, ELM const& elm)
{
return spec.matches(elm);
})
.constructFrom([](GenNode const& spec) -> ELM
{
return spec.data.get<ELM>();
});
}
};
template<>
struct _DefaultBinding<GenNode>
{
template<class COLL>
static auto
attachTo (COLL& coll)
{
return _EmptyBinding<GenNode>::attachTo(coll)
.matchElement([](GenNode const& spec, GenNode const& elm)
{
return spec.matches(elm);
})
.constructFrom([](GenNode const& spec) -> GenNode
{
return GenNode{spec};
})
.assignElement ([](GenNode& target, GenNode const& spec) -> bool
{
target.data = spec.data;
return true;
})
.buildChildMutator ([](GenNode& target, GenNode::ID const& subID, TreeMutator::Handle buff) -> bool
{
if (target.idi == subID // require match on already existing child object
and target.data.isNested())
{
Rec& nestedScope = target.data.get<Rec>();
buff.create (
TreeMutator::build()
.attach (mutateInPlace (nestedScope)));
return true;
}
else
return false;
});
}
};
/**
* Entry point to a nested DSL
@ -544,9 +590,11 @@
*/
template<class COLL>
auto
collection (COLL& coll) -> decltype(_DefaultBinding<COLL>::attachTo(coll))
collection (COLL& coll)
{
return _DefaultBinding<COLL>::attachTo(coll);
using Elm = typename COLL::value_type;
return _DefaultBinding<Elm>::attachTo(coll);
}

View file

@ -66,7 +66,7 @@
using lib::diff::GenNode;
using Storage = RecordSetup<GenNode>::Storage;
@ -96,7 +96,11 @@
{
return builderBase
.attach (collection (accessChildren(targetTree)))
.attach (collection (accessAttribs(targetTree)));
.attach (collection (accessAttribs(targetTree)))
.isApplicableIf ([&](GenNode const& spec)
{
return spec.isNamed(); // »Selector« : treat key-value elements here
});
}

View file

@ -213,7 +213,7 @@ namespace test{
.attach (collection(nestedObj_)
.isApplicableIf ([&](GenNode const& spec) -> bool
{
return BOTTOM_INDICATOR != spec.data.recordType(); // »Selector« : require object-like sub scope
return spec.data.isNested(); // »Selector« : require object-like sub scope
})
.matchElement ([&](GenNode const& spec, Opaque const& elm) -> bool
{