Skip to content

Commit

Permalink
Support wrapping uninstantiated datamodel nodes
Browse files Browse the repository at this point in the history
Previously we just hardcoded the Settings/Acquisition and
Settings2D/Acquisition nodes. This commit makes it work for any
uninstantiated node that is part of a datamodelList by recursively
searching the datamodel.
  • Loading branch information
johningve committed Nov 28, 2024
1 parent fd763de commit aedd11b
Showing 1 changed file with 62 additions and 6 deletions.
68 changes: 62 additions & 6 deletions src/include/ZividPython/DataModelWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ namespace ZividPython
static constexpr const char *value{ TypeName<T>::value };
};

template<typename DM, typename Dest, typename Node>
void findAndWrapUninstantiatedNodesInDataModel(Dest &dest, const Node &node);

template<bool isRoot, typename Dest, typename Target>
py::class_<Target> wrapDataModel(Dest &dest, const Target &target, const bool uninstantiatedNode = false)
{
Expand Down Expand Up @@ -172,12 +175,7 @@ namespace ZividPython

if constexpr(Target::nodeType == Zivid::DataModel::NodeType::group)
{
// TODO: Workaround for no API to access uninstansiated nodes.
// This generator should work on types and not instances.
if constexpr(std::is_same_v<Target, Zivid::Settings> || std::is_same_v<Target, Zivid::Settings2D>)
{
wrapDataModel<false>(pyClass, typename Target::Acquisition{}, true);
}
findAndWrapUninstantiatedNodesInDataModel<Target>(pyClass, target);

target.forEach([&](const auto &member) {
wrapDataModel<false>(pyClass, member);
Expand Down Expand Up @@ -292,6 +290,64 @@ namespace ZividPython
}
return pyClass;
}

constexpr bool isDirectChild(const std::string_view parent, const std::string_view child)
{
// Top-level nodes are always direct children of the root
if(parent.empty() && child.find('/') == std::string::npos)
{
return true;
}
if(child.size() <= parent.size())
{
return false;
}
if(child.compare(0, parent.size(), parent) != 0)
{
return false;
}
// Ensure there are no additional path components
const auto remainingPath = child.substr(parent.size());
return remainingPath.find('/') == 0 && remainingPath.find('/', 1) == std::string::npos;
}

static_assert(isDirectChild("", "TopLevel") == true);
static_assert(isDirectChild("", "TopLevel/WithChild") == false);
static_assert(isDirectChild("TopLevel", "TopLevel/WithChild") == true);
static_assert(isDirectChild("TopLevel", "TopLevel/WithChild/GrandChild") == false);

template<typename DM, typename PyDest, typename Node>
void findAndWrapUninstantiatedNodesInDataModel(PyDest &dest, const Node &node)
{
node.forEach([&](const auto &member) {
using MemberType = std::remove_const_t<std::remove_reference_t<decltype(member)>>;

if constexpr(MemberType::nodeType == Zivid::DataModel::NodeType::group)
{
findAndWrapUninstantiatedNodesInDataModel<DM>(dest, member);
}
else if constexpr(MemberType::nodeType == Zivid::DataModel::NodeType::leafDataModelList)
{
using ValueTypeContained = typename MemberType::ValueType::value_type;

// Sanity check
static_assert(Zivid::DataModel::IsDataModelType<ValueTypeContained>::value);

if constexpr(Zivid::Detail::TypeTraits::IsInTuple<ValueTypeContained,
typename DM::Descendants>::value)
{
// This node is instantiated.
return;
}

// Check via path that the contained type is a direct child of the dest
if constexpr(isDirectChild(DM::path, ValueTypeContained::path))
{
wrapDataModel<false>(dest, ValueTypeContained{}, true);
}
}
});
}
} // namespace Detail

template<typename Dest, typename Target>
Expand Down

0 comments on commit aedd11b

Please sign in to comment.