Add special type for representing special values

Before this, pseudo-values like lists and containers were represented by
a string leaf value. Now, I can tell these values apart. This can be
helpful for filtering (for example, when printing the values).  It will
also be used for implementing key value completion.

Change-Id: I48f6fa2facaf3e8e52aa3b3b4d92130e63acdb6f
diff --git a/src/ast_values.cpp b/src/ast_values.cpp
index b8ca68d..8d9c40c 100644
--- a/src/ast_values.cpp
+++ b/src/ast_values.cpp
@@ -48,3 +48,21 @@
     return this->m_value == b.m_value;
 }
 
+bool special_::operator==(const special_& b) const
+{
+    return this->m_value == b.m_value;
+}
+
+std::string specialValueToString(const special_& value)
+{
+    switch (value.m_value) {
+    case SpecialValue::Container:
+        return "(container)";
+    case SpecialValue::PresenceContainer:
+        return "(presence container)";
+    case SpecialValue::List:
+        return "(list)";
+    }
+
+    __builtin_unreachable();
+}
diff --git a/src/ast_values.hpp b/src/ast_values.hpp
index 44e98af..b2f2c3a 100644
--- a/src/ast_values.hpp
+++ b/src/ast_values.hpp
@@ -38,9 +38,23 @@
     std::string m_value;
 };
 
+enum class SpecialValue {
+    List,
+    Container,
+    PresenceContainer
+};
+
+struct special_ {
+    bool operator==(const special_& b) const;
+    SpecialValue m_value;
+};
+
+std::string specialValueToString(const special_& value);
+
 using leaf_data_ = boost::variant<enum_,
                                   binary_,
                                   identityRef_,
+                                  special_,
                                   double,
                                   bool,
                                   int8_t,
diff --git a/src/netconf_access.cpp b/src/netconf_access.cpp
index d1619cb..78d80b1 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -58,7 +58,7 @@
             if (!it)
                 continue;
             if (it->schema()->nodetype() == LYS_LIST) {
-                res.emplace(it->path(), std::string{"(list)"});
+                res.emplace(it->path(), special_{SpecialValue::List});
             }
             if (it->schema()->nodetype() == LYS_LEAF) {
                 libyang::Data_Node_Leaf_List leaf(it);
diff --git a/src/sysrepo_access.cpp b/src/sysrepo_access.cpp
index b01b484..221f482 100644
--- a/src/sysrepo_access.cpp
+++ b/src/sysrepo_access.cpp
@@ -39,11 +39,11 @@
     case SR_DECIMAL64_T:
         return value->data()->get_decimal64();
     case SR_CONTAINER_T:
-        return "(container)"s;
+        return special_{SpecialValue::Container};
     case SR_CONTAINER_PRESENCE_T:
-        return "(presence container)"s;
+        return special_{SpecialValue::PresenceContainer};
     case SR_LIST_T:
-        return "(list)"s;
+        return special_{SpecialValue::List};
     default: // TODO: implement all types
         return value->val_to_string();
     }
@@ -66,6 +66,11 @@
         return std::make_shared<sysrepo::Val>(res.c_str(), SR_IDENTITYREF_T);
     }
 
+    sysrepo::S_Val operator()(const special_& value) const
+    {
+        throw std::runtime_error("Tried constructing S_Val from a " + specialValueToString(value));
+    }
+
     sysrepo::S_Val operator()(const std::string& value) const
     {
         return std::make_shared<sysrepo::Val>(value.c_str());
diff --git a/src/utils.cpp b/src/utils.cpp
index 672cd36..eb4f432 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -108,6 +108,11 @@
         return data.m_prefix.value().m_name + ":" + data.m_value;
     }
 
+    std::string operator()(const special_& data) const
+    {
+        return specialValueToString(data);
+    }
+
     std::string operator()(const std::string& data) const
     {
         return data;