Disable readonly data paths in set

The first solution to this was to just filter operational nodes directly
inside NodeParser. That however can't work, because we might want to
parse operational data paths (for `get` and also `ls`). That means I
have to define, what gets filtered out, outside of NodeParser. The first
thing that came to mind is using a template argument, however, that
can't be used with lambdas (at least not easily). Instead I just use the
constructor and std::function.

Change-Id: Ic9e503ff721970066ef53d7b5626ff153ad44e18
diff --git a/src/static_schema.cpp b/src/static_schema.cpp
index aecad5a..738ce49 100644
--- a/src/static_schema.cpp
+++ b/src/static_schema.cpp
@@ -12,10 +12,10 @@
 
 StaticSchema::StaticSchema()
 {
-    m_nodes.emplace("/", std::unordered_map<std::string, NodeType>());
+    m_nodes.emplace("/", std::unordered_map<std::string, NodeInfo>());
 }
 
-const std::unordered_map<std::string, NodeType>& StaticSchema::children(const std::string& name) const
+const std::unordered_map<std::string, NodeInfo>& StaticSchema::children(const std::string& name) const
 {
     return m_nodes.at(name);
 }
@@ -36,11 +36,11 @@
 
 void StaticSchema::addContainer(const std::string& location, const std::string& name, yang::ContainerTraits isPresence)
 {
-    m_nodes.at(location).emplace(name, yang::container{isPresence});
+    m_nodes.at(location).emplace(name, NodeInfo{yang::container{isPresence}, yang::AccessType::Writable});
 
     //create a new set of children for the new node
     std::string key = joinPaths(location, name);
-    m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
+    m_nodes.emplace(key, std::unordered_map<std::string, NodeInfo>());
 }
 
 bool StaticSchema::listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const
@@ -49,7 +49,7 @@
     assert(isList(location, node));
 
     const auto& child = children(locationString).at(fullNodeName(location, node));
-    const auto& list = boost::get<yang::list>(child);
+    const auto& list = boost::get<yang::list>(child.m_nodeType);
     return list.m_keys.find(key) != list.m_keys.end();
 }
 
@@ -59,16 +59,16 @@
     assert(isList(location, node));
 
     const auto& child = children(locationString).at(fullNodeName(location, node));
-    const auto& list = boost::get<yang::list>(child);
+    const auto& list = boost::get<yang::list>(child.m_nodeType);
     return list.m_keys;
 }
 
 void StaticSchema::addList(const std::string& location, const std::string& name, const std::set<std::string>& keys)
 {
-    m_nodes.at(location).emplace(name, yang::list{keys});
+    m_nodes.at(location).emplace(name, NodeInfo{yang::list{keys}, yang::AccessType::Writable});
 
     std::string key = joinPaths(location, name);
-    m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
+    m_nodes.emplace(key, std::unordered_map<std::string, NodeInfo>());
 }
 
 std::set<identityRef_> StaticSchema::validIdentities(std::string_view module, std::string_view value)
@@ -79,11 +79,11 @@
     return identities;
 }
 
-void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataType& type)
+void StaticSchema::addLeaf(const std::string& location, const std::string& name, const yang::LeafDataType& type, const yang::AccessType accessType)
 {
-    m_nodes.at(location).emplace(name, yang::leaf{yang::TypeInfo{type, std::nullopt}});
+    m_nodes.at(location).emplace(name, NodeInfo{yang::leaf{yang::TypeInfo{type, std::nullopt}}, accessType});
     std::string key = joinPaths(location, name);
-    m_nodes.emplace(key, std::unordered_map<std::string, NodeType>());
+    m_nodes.emplace(key, std::unordered_map<std::string, NodeInfo>());
 }
 
 void StaticSchema::addModule(const std::string& name)
@@ -120,14 +120,14 @@
 yang::TypeInfo StaticSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
 {
     std::string locationString = pathToSchemaString(location, Prefixes::Always);
-    return boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node))).m_type;
+    return boost::get<yang::leaf>(children(locationString).at(fullNodeName(location, node)).m_nodeType).m_type;
 }
 
 yang::TypeInfo StaticSchema::leafType(const std::string& path) const
 {
     auto locationString = stripLastNodeFromPath(path);
     auto node = lastNodeOfSchemaPath(path);
-    return boost::get<yang::leaf>(children(locationString).at(node)).m_type;
+    return boost::get<yang::leaf>(children(locationString).at(node).m_nodeType).m_type;
 }
 
 std::set<ModuleNodePair> StaticSchema::availableNodes(const boost::variant<dataPath_, schemaPath_, module_>& path, const Recursion recursion) const
@@ -185,18 +185,18 @@
     try {
         auto targetNode = children(locationString).at(fullName);
 
-        if (targetNode.type() == typeid(yang::container)) {
-            if (boost::get<yang::container>(targetNode).m_presence == yang::ContainerTraits::Presence) {
+        if (targetNode.m_nodeType.type() == typeid(yang::container)) {
+            if (boost::get<yang::container>(targetNode.m_nodeType).m_presence == yang::ContainerTraits::Presence) {
                 return yang::NodeTypes::PresenceContainer;
             }
             return yang::NodeTypes::Container;
         }
 
-        if (targetNode.type() == typeid(yang::list)) {
+        if (targetNode.m_nodeType.type() == typeid(yang::list)) {
             return yang::NodeTypes::List;
         }
 
-        if (targetNode.type() == typeid(yang::leaf)) {
+        if (targetNode.m_nodeType.type() == typeid(yang::leaf)) {
             return yang::NodeTypes::Leaf;
         }
 
@@ -207,6 +207,25 @@
     }
 }
 
+std::string fullNodeName(const std::string& location, const std::string& node)
+{
+    // If the node already contains a module name, just return it.
+    if (node.find_first_of(':') != std::string::npos) {
+        return node;
+    }
+
+    // Otherwise take the module name from the first node of location.
+    return location.substr(location.find_first_not_of('/'), location.find_first_of(':') - 1) + ":" + node;
+}
+
+bool StaticSchema::isConfig(const std::string& leafPath) const
+{
+    auto locationString = stripLastNodeFromPath(leafPath);
+
+    auto node = fullNodeName(locationString, lastNodeOfSchemaPath(leafPath));
+    return children(locationString).at(node).m_configType == yang::AccessType::Writable;
+}
+
 std::optional<std::string> StaticSchema::description([[maybe_unused]] const std::string& path) const
 {
     throw std::runtime_error{"StaticSchema::description not implemented"};
@@ -237,11 +256,6 @@
     throw std::runtime_error{"Internal error: StaticSchema::leafTypeName(std::string) not implemented. The tests should not have called this overload."};
 }
 
-bool StaticSchema::isConfig([[maybe_unused]] const std::string& leafPath) const
-{
-    throw std::runtime_error{"Internal error: StaticSchema::isConfigLeaf(std::string) not implemented. The tests should not have called this overload."};
-}
-
 std::optional<std::string> StaticSchema::defaultValue([[maybe_unused]] const std::string& leafPath) const
 {
     throw std::runtime_error{"Internal error: StaticSchema::defaultValue(std::string) not implemented. The tests should not have called this overload."};