Fix leafDataFromValue
Leafrefs were not working correctly, when pointing to a data node not in
the tree. Because of this I had to rework the thing a little bit (I
basically copied the algorithm from cla-sysrepo, where I had the same
issue). I also changed the name. And also added test, both versions of
leafref included.
Funnily enough, it seems that I was already fixing this before, but for
some reason the bug appeared again while using netconf-cli, oh well, now
the tests should cover that hopefully.
Change-Id: I8a102c54bf58a4221610c8a83d26979fb7b4461d
diff --git a/src/libyang_utils.cpp b/src/libyang_utils.cpp
index 274fec1..f1af868 100644
--- a/src/libyang_utils.cpp
+++ b/src/libyang_utils.cpp
@@ -4,60 +4,65 @@
#include "libyang_utils.hpp"
#include "utils.hpp"
-leaf_data_ leafValueFromValue(const libyang::S_Value& value, LY_DATA_TYPE type)
+leaf_data_ leafValueFromNode(libyang::S_Data_Node_Leaf_List node)
{
- using namespace std::string_literals;
- switch (type) {
- case LY_TYPE_INT8:
- return value->int8();
- case LY_TYPE_INT16:
- return value->int16();
- case LY_TYPE_INT32:
- return value->int32();
- case LY_TYPE_INT64:
- return value->int64();
- case LY_TYPE_UINT8:
- return value->uint8();
- case LY_TYPE_UINT16:
- return value->uint16();
- case LY_TYPE_UINT32:
- return value->uint32();
- case LY_TYPE_UINT64:
- return value->uint64();
- case LY_TYPE_BOOL:
- return value->bln();
- case LY_TYPE_STRING:
- return std::string(value->string());
- case LY_TYPE_ENUM:
- return enum_{std::string(value->enm()->name())};
- case LY_TYPE_IDENT:
- return identityRef_{value->ident()->module()->name(), value->ident()->name()};
- case LY_TYPE_BINARY:
- return binary_{value->binary()};
- case LY_TYPE_EMPTY:
- return empty_{};
- case LY_TYPE_BITS:
- {
- auto bits = value->bit();
- std::vector<libyang::S_Type_Bit> filterNull;
- std::copy_if(bits.begin(), bits.end(), std::back_inserter(filterNull), [] (auto bit) { return bit; });
- bits_ res;
- std::transform(filterNull.begin(), filterNull.end(), std::inserter(res.m_bits, res.m_bits.end()), [] (const auto& bit) { return bit->name(); });
- return bits_{res};
+ std::function<leaf_data_(libyang::S_Data_Node_Leaf_List)> impl = [&impl] (libyang::S_Data_Node_Leaf_List node) -> leaf_data_ {
+ // value_type() is what's ACTUALLY stored inside `node`
+ // Leafrefs sometimes don't hold a reference to another, but they have the actual pointed-to value.
+ switch (node->value_type()) {
+ case LY_TYPE_ENUM:
+ return enum_{node->value()->enm()->name()};
+ case LY_TYPE_UINT8:
+ return node->value()->uint8();
+ case LY_TYPE_UINT16:
+ return node->value()->uint16();
+ case LY_TYPE_UINT32:
+ return node->value()->uint32();
+ case LY_TYPE_UINT64:
+ return node->value()->uint64();
+ case LY_TYPE_INT8:
+ return node->value()->int8();
+ case LY_TYPE_INT16:
+ return node->value()->int16();
+ case LY_TYPE_INT32:
+ return node->value()->int32();
+ case LY_TYPE_INT64:
+ return node->value()->int64();
+ case LY_TYPE_DEC64:
+ {
+ auto v = node->value()->dec64();
+ return v.value * std::pow(10, -v.digits);
+ }
+ case LY_TYPE_BOOL:
+ return node->value()->bln();
+ case LY_TYPE_STRING:
+ return std::string{node->value()->string()};
+ case LY_TYPE_BINARY:
+ return binary_{node->value()->binary()};
+ case LY_TYPE_IDENT:
+ return identityRef_{node->value()->ident()->module()->name(), node->value()->ident()->name()};
+ case LY_TYPE_EMPTY:
+ return empty_{};
+ case LY_TYPE_LEAFREF:
+ {
+ auto refsTo = node->value()->leafref();
+ assert(refsTo);
+ return impl(std::make_shared<libyang::Data_Node_Leaf_List>(node->value()->leafref()));
+ }
+ case LY_TYPE_BITS:
+ {
+ auto bits = node->value()->bit();
+ std::vector<libyang::S_Type_Bit> filterNull;
+ std::copy_if(bits.begin(), bits.end(), std::back_inserter(filterNull), [] (auto bit) { return bit; });
+ bits_ res;
+ std::transform(filterNull.begin(), filterNull.end(), std::inserter(res.m_bits, res.m_bits.end()), [] (const auto& bit) { return bit->name(); });
+ return bits_{res};
+ }
+ default:
+ return std::string{"(can't print)"};
}
- case LY_TYPE_DEC64:
- {
- auto v = value->dec64();
- return v.value * std::pow(10, -v.digits);
- }
- case LY_TYPE_LEAFREF:
- {
- libyang::Data_Node_Leaf_List toPrint{value->leafref()};
- return leafValueFromValue(toPrint.value(), toPrint.value_type());
- }
- default: // TODO: implement all types
- return "(can't print)"s;
- }
+ };
+ return impl(node);
}
namespace {
@@ -80,8 +85,8 @@
res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::List});
}
if (it->schema()->nodetype() == LYS_LEAF || it->schema()->nodetype() == LYS_LEAFLIST) {
- libyang::Data_Node_Leaf_List leaf(it);
- auto value = leafValueFromValue(leaf.value(), leaf.value_type());
+ auto leaf = std::make_shared<libyang::Data_Node_Leaf_List>(it);
+ auto value = leafValueFromNode(leaf);
res.emplace_back(stripXPathPrefix(it->path()), value);
}
}
diff --git a/src/libyang_utils.hpp b/src/libyang_utils.hpp
index d8bf4ad..a33e70b 100644
--- a/src/libyang_utils.hpp
+++ b/src/libyang_utils.hpp
@@ -9,5 +9,5 @@
#include "ast_values.hpp"
#include "datastore_access.hpp"
-leaf_data_ leafValueFromValue(const libyang::S_Value& value, LY_DATA_TYPE type);
+leaf_data_ leafValueFromNode(libyang::S_Data_Node_Leaf_List node);
void lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix = std::nullopt);
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index 307ccf1..2c64cd4 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -232,9 +232,8 @@
// I take the first child here, because the first element (the parent of the child()) will be the list
for (const auto& keyLeaf : instance->child()->tree_for()) {
- auto leafData = libyang::Data_Node_Leaf_List{keyLeaf};
- auto leafSchema = libyang::Schema_Node_Leaf{leafData.schema()};
- instanceRes.insert({ leafSchema.name(), leafValueFromValue(leafData.value(), leafSchema.type()->base())});
+ auto leafData = std::make_shared<libyang::Data_Node_Leaf_List>(keyLeaf);
+ instanceRes.insert({ leafData->schema()->name(), leafValueFromNode(leafData)});
}
res.emplace_back(instanceRes);
}
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index 6176f67..cdaff49 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -419,8 +419,8 @@
ListInstance instanceRes;
for (const auto& key : keys) {
auto vec = wantedList->find_path(key->name())->data();
- auto leaf = libyang::Data_Node_Leaf_List{*(vec.begin())};
- instanceRes.emplace(key->name(), leafValueFromValue(leaf.value(), leaf.leaf_type()->base()));
+ auto leaf = std::make_shared<libyang::Data_Node_Leaf_List>(*(vec.begin()));
+ instanceRes.emplace(key->name(), leafValueFromNode(leaf));
}
res.emplace_back(instanceRes);
}
diff --git a/src/yang_access.cpp b/src/yang_access.cpp
index 8171c89..a460150 100644
--- a/src/yang_access.cpp
+++ b/src/yang_access.cpp
@@ -284,8 +284,8 @@
if (child->schema()->nodetype() == LYS_LEAF) {
libyang::Schema_Node_Leaf leafSchema(child->schema());
if (leafSchema.is_key()) {
- libyang::Data_Node_Leaf_List leafData(child);
- instance.insert({leafSchema.name(), leafValueFromValue(leafData.value(), leafSchema.type()->base())});
+ auto leafData = std::make_shared<libyang::Data_Node_Leaf_List>(child);
+ instance.insert({leafSchema.name(), leafValueFromNode(leafData)});
}
}
}