diff options
-rw-r--r-- | slicer/Jamfile.jam | 2 | ||||
-rw-r--r-- | slicer/json/Jamfile.jam | 23 | ||||
-rw-r--r-- | slicer/json/serializer.cpp | 252 | ||||
-rw-r--r-- | slicer/json/serializer.h | 25 | ||||
-rw-r--r-- | slicer/slicer/modelParts.h | 23 | ||||
-rw-r--r-- | slicer/test/Jamfile.jam | 1 | ||||
-rw-r--r-- | slicer/test/initial/builtins2.json | 1 | ||||
-rw-r--r-- | slicer/test/initial/optionals-areset2.json | 1 | ||||
-rw-r--r-- | slicer/test/run-slicer.cpp | 15 |
9 files changed, 339 insertions, 4 deletions
diff --git a/slicer/Jamfile.jam b/slicer/Jamfile.jam index b6de7a4..04fc453 100644 --- a/slicer/Jamfile.jam +++ b/slicer/Jamfile.jam @@ -3,7 +3,9 @@ import package ; build-project tool ; build-project slicer ; build-project xml ; +build-project json ; build-project test ; package.install install : <install-source-root>. : tool//slicer : slicer//slicer : [ glob slicer/*.h ] ; package.install install-xml : <install-source-root>. : : xml//slicer-xml : [ glob xml/*.h ] ; +package.install install-json : <install-source-root>. : : json//slicer-json : [ glob json/*.h ] ; diff --git a/slicer/json/Jamfile.jam b/slicer/json/Jamfile.jam new file mode 100644 index 0000000..27022ee --- /dev/null +++ b/slicer/json/Jamfile.jam @@ -0,0 +1,23 @@ +alias glibmm : : : : + <cflags>"`pkg-config --cflags glibmm-2.4`" + <linkflags>"`pkg-config --libs glibmm-2.4`" + ; + +lib jsonpp : : : : + <cflags>"`pkg-config --cflags glibmm-2.4`" + ; + +lib boost_system ; +lib boost_filesystem ; +lib IceUtil ; + +lib slicer-json : + [ glob *.cpp ] + : + <include>.. + <library>boost_system + <library>boost_filesystem + <library>IceUtil + <library>jsonpp + <library>glibmm + ; diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp new file mode 100644 index 0000000..e9cd58c --- /dev/null +++ b/slicer/json/serializer.cpp @@ -0,0 +1,252 @@ +#include "serializer.h" +#include <jsonpp.h> +#include <boost/lexical_cast.hpp> +#include <boost/bind.hpp> +#include <stdexcept> +#include <fstream> +#include <glibmm/ustring.h> + +namespace Slicer { + class JsonValueSource : public ValueSource { + public: + JsonValueSource(const json::Value & s) : + value(s) + { + } + + void set(bool & v) const override + { + v = boost::get<bool>(value); + } + + void set(Ice::Byte & v) const override + { + v = boost::numeric_cast<Ice::Byte>(boost::get<json::Number>(value)); + } + + void set(Ice::Short & v) const override + { + v = boost::numeric_cast<Ice::Short>(boost::get<json::Number>(value)); + } + + void set(Ice::Int & v) const override + { + v = boost::numeric_cast<Ice::Int>(boost::get<json::Number>(value)); + } + + void set(Ice::Long & v) const override + { + v = boost::numeric_cast<Ice::Long>(boost::get<json::Number>(value)); + } + + void set(Ice::Float & v) const override + { + v = boost::numeric_cast<Ice::Float>(boost::get<json::Number>(value)); + } + + void set(Ice::Double & v) const override + { + v = boost::numeric_cast<Ice::Double>(boost::get<json::Number>(value)); + } + + void set(std::string & v) const override + { + v = boost::get<json::String>(value); + } + + protected: + const json::Value & value; + }; + + class JsonValueTarget : public ValueTarget { + public: + JsonValueTarget(json::Value & t) : + target(t) + { + target = json::Null(); + } + + virtual void get(const bool & value) const + { + target = value; + } + + virtual void get(const Ice::Byte & value) const + { + target = boost::numeric_cast<json::Number>(value); + } + + virtual void set(const Ice::Short & value) const + { + target = boost::numeric_cast<json::Number>(value); + } + + virtual void get(const Ice::Int & value) const + { + target = boost::numeric_cast<json::Number>(value); + } + + virtual void get(const Ice::Long & value) const + { + target = boost::numeric_cast<json::Number>(value); + } + + virtual void get(const Ice::Float & value) const + { + target = boost::numeric_cast<json::Number>(value); + } + + virtual void get(const Ice::Double & value) const + { + target = boost::numeric_cast<json::Number>(value); + } + + virtual void get(const std::string & value) const + { + target = value; + } + + private: + json::Value & target; + }; + + class DocumentTreeIterate : public boost::static_visitor<> { + public: + DocumentTreeIterate(ModelPartPtr mp) : modelPart(mp) + { + } + template<typename SimpleT> + void operator()(const SimpleT & v) const + { + modelPart->Create(); + modelPart->SetValue(new JsonValueSource(v)); + modelPart->Complete(); + } + void operator()(const json::Null &) const + { + modelPart->Complete(); + } + void operator()(const json::Object & o) const + { + modelPart->Create(); + BOOST_FOREACH(const auto & element, o) { + auto emp = modelPart->GetChild(element.first); + if (emp) { + emp->Create(); + boost::apply_visitor(DocumentTreeIterate(emp), *element.second); + emp->Complete(); + } + } + modelPart->Complete(); + } + void operator()(const json::Array & a) const + { + modelPart->Create(); + BOOST_FOREACH(const auto & element, a) { + auto emp = modelPart->GetChild(std::string()); + if (emp) { + emp->Create(); + boost::apply_visitor(DocumentTreeIterate(emp), *element); + emp->Complete(); + } + } + modelPart->Complete(); + } + private: + ModelPartPtr modelPart; + }; + + void + Json::ModelTreeIterateSeq(json::Value * n, ModelPartPtr mp) + { + auto & arr = boost::get<json::Array &>(*n); + arr.push_back(json::ValuePtr(new json::Value())); + ModelTreeIterateRoot(arr.back().get(), mp); + } + + void + Json::ModelTreeIterate(json::Value * n, const std::string & name, ModelPartPtr mp) + { + if (name.empty() || !n) { + return; + } + if (mp) { + switch (mp->GetType()) { + case mpt_Null: + boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}); + return; + case mpt_Simple: + mp->GetValue(new JsonValueTarget(*boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value())}).first->second)); + break; + case mpt_Complex: + { + auto nn = json::ValuePtr(new json::Value(json::Object())); + if (auto typeId = mp->GetTypeId()) { + boost::get<json::Object>(*nn).insert({"slicer-typeid", json::ValuePtr(new json::Value(*typeId))}); + mp = mp->GetSubclassModelPart(*typeId); + } + mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, boost::get<json::Object>(*n).insert({name, nn}).first->second.get(), _1, _2)); + break; + } + case mpt_Sequence: + case mpt_Dictionary: + mp->OnEachChild(boost::bind(&Json::ModelTreeIterateSeq, boost::get<json::Object>(*n).insert({name, json::ValuePtr(new json::Value(json::Array()))}).first->second.get(), _2)); + break; + } + } + } + + void + Json::ModelTreeIterateRoot(json::Value * n, ModelPartPtr mp) + { + if (mp) { + switch (mp->GetType()) { + case mpt_Null: + *n = json::Null(); + return; + case mpt_Simple: + mp->GetValue(new JsonValueTarget(*n)); + break; + case mpt_Complex: + *n = json::Object(); + if (auto typeId = mp->GetTypeId()) { + boost::get<json::Object>(*n).insert({"slicer-typeid", json::ValuePtr(new json::Value(*typeId))}); + mp = mp->GetSubclassModelPart(*typeId); + } + mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, n, _1, _2)); + break; + case mpt_Sequence: + *n = json::Array(); + mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, n, _1, _2)); + break; + case mpt_Dictionary: + *n = json::Array(); + mp->OnEachChild(boost::bind(&Json::ModelTreeIterate, n, _1, _2)); + break; + } + } + } + + void + Json::Deserialize(const boost::filesystem::path & path, ModelPartPtr modelRoot) + { + std::ifstream inFile(path.string()); + std::stringstream buffer; + buffer << inFile.rdbuf(); + Glib::ustring doc(buffer.str()); + Glib::ustring::const_iterator itr = doc.begin(); + json::Value obj = json::parseValue(itr); + boost::apply_visitor(DocumentTreeIterate(modelRoot->GetChild(std::string())), obj); + } + + void + Json::Serialize(const boost::filesystem::path & path, ModelPartPtr modelRoot) + { + json::Value doc; + modelRoot->OnEachChild(boost::bind(&Json::ModelTreeIterateRoot, &doc, _2)); + std::ofstream outFile(path.string()); + json::serializeValue(doc, outFile, "utf-8"); + } +} + + diff --git a/slicer/json/serializer.h b/slicer/json/serializer.h new file mode 100644 index 0000000..0d70f21 --- /dev/null +++ b/slicer/json/serializer.h @@ -0,0 +1,25 @@ +#ifndef SLICER_JSON_H +#define SLICER_JSON_H + +#include <slicer/serializer.h> + +namespace json { + class Value; +} + +namespace Slicer { + class Json : public Serializer { + public: + virtual void Deserialize(const boost::filesystem::path &, ModelPartPtr) override; + virtual void Serialize(const boost::filesystem::path &, ModelPartPtr) override; + + protected: + static void ModelTreeIterate(json::Value *, const std::string &, ModelPartPtr mp); + static void ModelTreeIterateSeq(json::Value *, ModelPartPtr mp); + static void ModelTreeIterateRoot(json::Value *, ModelPartPtr mp); + }; +} + +#endif + + diff --git a/slicer/slicer/modelParts.h b/slicer/slicer/modelParts.h index 28ab86d..ca1573a 100644 --- a/slicer/slicer/modelParts.h +++ b/slicer/slicer/modelParts.h @@ -60,6 +60,13 @@ namespace Slicer { typedef boost::function<ModelPartPtr(void *)> ClassRef; typedef std::map<std::string, ClassRef> ClassRefMap; ClassRefMap * & classRefMap(); + enum ModelPartType { + mpt_Null, + mpt_Simple, + mpt_Complex, + mpt_Sequence, + mpt_Dictionary, + }; class ModelPart : public IceUtil::Shared { public: @@ -69,6 +76,7 @@ namespace Slicer { virtual ModelPartPtr GetChild(const std::string & memberName) = 0; virtual ModelPartPtr GetSubclassModelPart(const std::string &); virtual TypeId GetTypeId() const; + virtual ModelPartType GetType() const = 0; virtual void Create(); virtual void Complete(); virtual void SetValue(ValueSourcePtr); @@ -94,6 +102,7 @@ namespace Slicer { virtual void SetValue(ValueSourcePtr s) override { s->set(Member); } virtual void GetValue(ValueTargetPtr s) override { s->get(Member); } virtual bool HasValue() const override { return true; } + virtual ModelPartType GetType() const { return mpt_Simple; } private: T & Member; @@ -160,6 +169,14 @@ namespace Slicer { virtual bool HasValue() const override { return OptionalMember; } + virtual ModelPartType GetType() const + { + if (HasValue()) { + return modelPart->GetType(); + } + return mpt_Null; + } + private: IceUtil::Optional< typename T::element_type > & OptionalMember; ModelPartPtr modelPart; @@ -217,6 +234,8 @@ namespace Slicer { return NULL; } + virtual ModelPartType GetType() const { return mpt_Complex; } + virtual T * GetModel() = 0; typedef std::vector<HookPtr> Hooks; @@ -359,6 +378,8 @@ namespace Slicer { virtual bool HasValue() const override { return true; } + virtual ModelPartType GetType() const { return mpt_Sequence; } + private: ModelPartPtr elementModelPart(typename T::value_type &) const; @@ -435,6 +456,8 @@ namespace Slicer { virtual bool HasValue() const override { return true; } + virtual ModelPartType GetType() const { return mpt_Dictionary; } + private: T & dictionary; static std::string pairName; diff --git a/slicer/test/Jamfile.jam b/slicer/test/Jamfile.jam index ebc6c25..1426704 100644 --- a/slicer/test/Jamfile.jam +++ b/slicer/test/Jamfile.jam @@ -57,4 +57,5 @@ unit-test run-slicer : <library>IceUtil <library>../slicer//slicer <library>../xml//slicer-xml + <library>../json//slicer-json ; diff --git a/slicer/test/initial/builtins2.json b/slicer/test/initial/builtins2.json new file mode 100644 index 0000000..ed9ee11 --- /dev/null +++ b/slicer/test/initial/builtins2.json @@ -0,0 +1 @@ +{"mbool":true,"mbyte":4.000000,"mdouble":3.062500,"mfloat":3.125000,"mint":80.000000,"mlong":800.000000,"mshort":40.000000,"mstring":"Sample text"} diff --git a/slicer/test/initial/optionals-areset2.json b/slicer/test/initial/optionals-areset2.json new file mode 100644 index 0000000..33bf12a --- /dev/null +++ b/slicer/test/initial/optionals-areset2.json @@ -0,0 +1 @@ +{"optClass":{"a":1.000000,"b":2.000000},"optDict":[{"key":10.000000,"value":{"a":11.000000,"b":12.000000}},{"key":13.000000,"value":{"a":14.000000,"b":15.000000}}],"optSeq":[{"a":3.000000,"b":4.000000},{"a":5.000000,"b":6.000000}],"optSimple":4.000000,"optStruct":{"a":1.000000,"b":2.000000}}
\ No newline at end of file diff --git a/slicer/test/run-slicer.cpp b/slicer/test/run-slicer.cpp index c6a1ed2..955b735 100644 --- a/slicer/test/run-slicer.cpp +++ b/slicer/test/run-slicer.cpp @@ -1,6 +1,7 @@ #include <slicer/parser.h> #include <slicer/slicer.h> #include <xml/serializer.h> +#include <json/serializer.h> #include <boost/filesystem/convenience.hpp> #include <boost/filesystem/operations.hpp> #include <boost/format.hpp> @@ -12,21 +13,25 @@ namespace fs = boost::filesystem; -template<typename T, typename Serializer> +template<typename T, typename SerializerIn> void verify(const fs::path & root, const fs::path & tmp, const fs::path & infile, const boost::function<void(const T &)> & check = NULL) { const fs::path input = root / "initial" / infile; const fs::path output = tmp / infile; + const fs::path outputJson = tmp / fs::change_extension(infile, "json"); + const fs::path outputXml = tmp / fs::change_extension(infile, "xml"); fprintf(stderr, "%s : Deserialize\n", input.string().c_str()); - IceInternal::Handle<T> p = Slicer::Deserialize<Serializer, T>(input); + IceInternal::Handle<T> p = Slicer::Deserialize<SerializerIn, T>(input); if (check) { fprintf(stderr, "%s : Check1\n", input.string().c_str()); check(*p); } - fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), output.string().c_str()); - Slicer::Serialize<Serializer>(p, output); + fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), outputJson.string().c_str()); + Slicer::Serialize<Slicer::Json>(p, outputJson); + fprintf(stderr, "%s : Serialize -> %s\n", input.string().c_str(), outputXml.string().c_str()); + Slicer::Serialize<Slicer::Xml>(p, outputXml); if (check) { fprintf(stderr, "%s : Check2\n", input.string().c_str()); check(*p); @@ -108,6 +113,8 @@ main(int, char ** argv) verify<TestModule::Optionals, Slicer::Xml>(root, tmp, "optionals-areset.xml", checkOptionals_areset); verify<TestModule::InheritanceCont, Slicer::Xml>(root, tmp, "inherit-a.xml"); verify<TestModule::InheritanceCont, Slicer::Xml>(root, tmp, "inherit-b.xml"); + verify<TestModule::BuiltIns, Slicer::Json>(root, tmp, "builtins2.json", checkBuiltIns_valuesCorrect); + verify<TestModule::Optionals, Slicer::Json>(root, tmp, "optionals-areset2.json", checkOptionals_areset); return 0; } |