diff Resources/CodeGeneration/template.in.h @ 494:fc17251477d6 bgo-commands-codegen

TS and CPP tests OK. Ongoing code for C++ program that reads list of serialized messages in N files. Requires conan
author bgo-osimis
date Sat, 23 Feb 2019 10:18:13 +0100
parents 6470248790db
children 6405435480ae
line wrap: on
line diff
--- a/Resources/CodeGeneration/template.in.h	Fri Feb 22 10:48:43 2019 +0100
+++ b/Resources/CodeGeneration/template.in.h	Sat Feb 23 10:18:13 2019 +0100
@@ -7,38 +7,95 @@
 #include <string>
 #include <sstream>
 #include <assert.h>
+#include <memory>
+#include <optional>
 #include <json/json.h>
+#include <gtest/gtest.h>
 
+//#define STONEGEN_NO_CPP11 1
 
-namespace VsolStuff
+#ifdef STONEGEN_NO_CPP11
+#define StoneSmartPtr std::auto_ptr
+#else 
+#define StoneSmartPtr std::unique_ptr
+#endif 
+
+namespace {{rootName}}
 {
-  Json::Value StoneSerialize(int32_t value)
+  /** Throws in case of problem */
+  void _StoneDeserializeValue(int32_t& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asInt();
+  }
+
+  Json::Value _StoneSerializeValue(int32_t value)
   {
     Json::Value result(value);
     return result;
   }
 
-  Json::Value StoneSerialize(double value)
+  /** Throws in case of problem */
+  void _StoneDeserializeValue(double& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asDouble();
+  }
+
+  Json::Value _StoneSerializeValue(double value)
   {
     Json::Value result(value);
     return result;
   }
 
-  Json::Value StoneSerialize(bool value)
+  /** Throws in case of problem */
+  void _StoneDeserializeValue(bool& destValue, const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asBool();
+  }
+
+  Json::Value _StoneSerializeValue(bool value)
   {
     Json::Value result(value);
     return result;
   }
 
-  Json::Value StoneSerialize(const std::string& value)
+  /** Throws in case of problem */
+  void _StoneDeserializeValue(
+       std::string& destValue
+     , const Json::Value& jsonValue)
+  {
+    destValue = jsonValue.asString();
+  }
+
+  Json::Value _StoneSerializeValue(const std::string& value)
   {
     // the following is better than 
     Json::Value result(value.data(),value.data()+value.size());
     return result;
   }
     
+  /** Throws in case of problem */
   template<typename T>
-  Json::Value StoneSerialize(const std::map<std::string,T>& value)
+  void _StoneDeserializeValue(
+    std::map<std::string, T>& destValue, const Json::Value& jsonValue)
+  {
+    destValue.clear();
+    for (
+      Json::Value::const_iterator itr = jsonValue.begin();
+      itr != jsonValue.end();
+      itr++)
+    {
+      std::string key;
+      _StoneDeserializeValue(key, itr.key());
+
+      T innerDestValue;
+      _StoneDeserializeValue(innerDestValue, *itr);
+
+      destValue[key] = innerDestValue;
+    }
+  }
+
+  template<typename T>
+  Json::Value _StoneSerializeValue(const std::map<std::string,T>& value)
   {
     Json::Value result(Json::objectValue);
 
@@ -46,24 +103,190 @@
       it != value.cend(); ++it)
     {
       // it->first it->second
-      result[it->first] = StoneSerialize(it->second);
+      result[it->first] = _StoneSerializeValue(it->second);
     }
     return result;
   }
 
+  /** Throws in case of problem */
   template<typename T>
-  Json::Value StoneSerialize(const std::vector<T>& value)
+  void _StoneDeserializeValue(
+    std::vector<T>& destValue, const Json::Value& jsonValue)
+  {
+    destValue.clear();
+    destValue.reserve(jsonValue.size());
+    for (Json::Value::ArrayIndex i = 0; i != jsonValue.size(); i++)
+    {
+      T innerDestValue;
+      _StoneDeserializeValue(innerDestValue, jsonValue[i]);
+      destValue.push_back(innerDestValue);
+    }
+  }
+
+  template<typename T>
+  Json::Value _StoneSerializeValue(const std::vector<T>& value)
   {
     Json::Value result(Json::arrayValue);
     for (size_t i = 0; i < value.size(); ++i)
     {
-      result.append(StoneSerialize(value[i]));
+      result.append(_StoneSerializeValue(value[i]));
     }
     return result;
   }
 
-  %enumerationscpp%
+  void StoneCheckSerializedValueTypeGeneric(const Json::Value& value)
+  {
+    if ((!value.isMember("type")) || (!value["type"].isString()))
+    {
+      std::stringstream ss;
+      ss << "Cannot deserialize value ('type' key invalid)";
+      throw std::runtime_error(ss.str());
+    }
+  }
+
+  void StoneCheckSerializedValueType(
+    const Json::Value& value, std::string typeStr)
+  {
+    StoneCheckSerializedValueTypeGeneric(value);
+
+    std::string actTypeStr = value["type"].asString();
+    if (actTypeStr != typeStr)
+    {
+      std::stringstream ss;
+      ss << "Cannot deserialize type" << actTypeStr
+        << "into " << typeStr;
+      throw std::runtime_error(ss.str());
+    }
+  }
+
+  // end of generic methods
+
+// end of generic methods
+{% for enum in enums%}
+  enum {{enum['name']}} {
+{% for key in enum['fields']%}    {{key}},
+{%endfor%}  };
+
+  void _StoneDeserializeValue(
+    {{enum['name']}}& destValue, const Json::Value& jsonValue)
+  {
+    destValue = static_cast<{{enum['name']}}>(jsonValue.asInt64());
+  }
+
+  Json::Value _StoneSerializeValue(const {{enum['name']}}& value)
+  {
+    return Json::Value(static_cast<int64_t>(value));
+  }
+{%endfor%}
+{% for struct in structs%}
+#ifdef _MSC_VER
+#pragma region {{struct['name']}}
+#endif //_MSC_VER
+
+  struct {{struct['name']}}
+  {
+{% for key in struct['fields']%}    {{CanonToCpp(struct['fields'][key])}} {{key}};
+{% endfor %}
+    {{struct['name']}}()
+    {
+{% for key in struct['fields']%}      {{key}} = {{CanonToCpp(struct['fields'][key])}}();
+{% endfor %}
+    }
+  };
+
+  void _StoneDeserializeValue({{struct['name']}}& destValue, const Json::Value& value)
+  {
+{% for key in struct['fields']%}    _StoneDeserializeValue(destValue.{{key}}, value["{{key}}"]);
+{% endfor %}
+  }
+
+  Json::Value _StoneSerializeValue(const {{struct['name']}}& value)
+  {
+    Json::Value result(Json::objectValue);
+{% for key in struct['fields']%}    result["{{key}}"] = _StoneSerializeValue(value.{{key}});
+{% endfor %}
+    return result;
+  }
 
-  %structscpp%
+  void StoneDeserialize({{struct['name']}}& destValue, const Json::Value& value)
+  {
+    StoneCheckSerializedValueType(value, "{{rootName}}.{{struct['name']}}");
+    _StoneDeserializeValue(destValue, value["value"]);
+  }
+
+  Json::Value StoneSerialize(const {{struct['name']}}& value)
+  {
+    Json::Value result(Json::objectValue);
+    result["type"] = "{{rootName}}.{{struct['name']}}";
+    result["value"] = _StoneSerializeValue(value);
+    return result;
+  }
+
+#ifdef _MSC_VER
+#pragma endregion {{struct['name']}}
+#endif //_MSC_VER
+{% endfor %}
+#ifdef _MSC_VER
+#pragma region Dispatching code
+#endif //_MSC_VER
+
+  class IDispatcher
+  {
+  public:
+{% for struct in structs%}    virtual bool Handle(const {{struct['name']}}& value) = 0;
+{% endfor %}  };
 
+  /** Service function for StoneDispatchToHandler */
+  bool StoneDispatchJsonToHandler(
+    const Json::Value& jsonValue, IDispatcher* dispatcher)
+  {
+    StoneCheckSerializedValueTypeGeneric(jsonValue);
+    std::string type = jsonValue["type"].asString();
+    if (type == "")
+    {
+      // this should never ever happen
+      throw std::runtime_error("Caught empty type while dispatching");
+    }
+{% for struct in structs%}    else if (type == "{{rootName}}.{{struct['name']}}")
+    {
+      {{struct['name']}} value;
+      _StoneDeserializeValue(value, jsonValue["value"]);
+      return dispatcher->Handle(value);
+    }
+{% endfor %}    else
+    {
+      return false;
+    }
+  }
+
+  /** Takes a serialized type and passes this to the dispatcher */
+  bool StoneDispatchToHandler(std::string strValue, IDispatcher* dispatcher)
+  {
+    Json::Value readValue;
+
+    Json::CharReaderBuilder builder;
+    Json::CharReader* reader = builder.newCharReader();
+
+    StoneSmartPtr<Json::CharReader> ptr(reader);
+
+    std::string errors;
+
+    bool ok = reader->parse(
+      strValue.c_str(),
+      strValue.c_str() + strValue.size(),
+      &readValue,
+      &errors
+    );
+    if (!ok)
+    {
+      std::stringstream ss;
+      ss << "Jsoncpp parsing error: " << errors;
+      throw std::runtime_error(ss.str());
+    }
+    return StoneDispatchJsonToHandler(readValue, dispatcher);
+  }
+
+#ifdef _MSC_VER
+#pragma endregion Dispatching code
+#endif //_MSC_VER
 }