Add 'xo-printjson/' from commit '6743b9ef18'
git-subtree-dir: xo-printjson git-subtree-mainline:d49c309f80git-subtree-split:6743b9ef18
This commit is contained in:
commit
9c8e23577e
16 changed files with 1214 additions and 0 deletions
136
xo-printjson/.github/workflows/main.yml
vendored
Normal file
136
xo-printjson/.github/workflows/main.yml
vendored
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
name: build on ubuntu base platform for xo-printjson
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
build:
|
||||
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
|
||||
# You can convert this to a matrix build if you need cross-platform coverage.
|
||||
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout source
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install catch2
|
||||
# install catch2. see [[https://stackoverflow.com/questions/57982945/how-to-apt-get-install-in-a-github-actions-workflow]]
|
||||
run: sudo apt-get install -y catch2
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: Clone xo-cmake
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/xo-cmake
|
||||
path: repo/xo-cmake
|
||||
|
||||
- name: Configure xo-cmake
|
||||
run: cmake -B ${{github.workspace}}/build_xo-cmake -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/xo-cmake
|
||||
|
||||
- name: Build xo-cmake (trivial)
|
||||
run: cmake --build ${{github.workspace}}/build_xo-cmake --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Install xo-cmake
|
||||
run: cmake --install ${{github.workspace}}/build_xo-cmake
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: Clone indentlog
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/indentlog
|
||||
path: repo/indentlog
|
||||
|
||||
- name: Configure indentlog
|
||||
# configure cmake for indentlog in dedicated build directory.
|
||||
run: cmake -B ${{github.workspace}}/build_indentlog -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/indentlog
|
||||
|
||||
- name: Build indentlog
|
||||
run: cmake --build ${{github.workspace}}/build_indentlog --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Install indentlog
|
||||
# install into ${{github.workspace}}/local
|
||||
run: cmake --install ${{github.workspace}}/build_indentlog
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: Clone subsys
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/subsys
|
||||
path: repo/subsys
|
||||
|
||||
- name: Configure subsys
|
||||
# configure cmake for subsys in dedicated build directory.
|
||||
run: cmake -B ${{github.workspace}}/build_subsys -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/subsys
|
||||
|
||||
- name: Build subsys
|
||||
run: cmake --build ${{github.workspace}}/build_subsys --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Install subsys
|
||||
# install into ${{github.workspace}}/local
|
||||
run: cmake --install ${{github.workspace}}/build_subsys
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: Clone refcnt
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/refcnt
|
||||
path: repo/refcnt
|
||||
|
||||
- name: Configure refcnt
|
||||
# configure cmake for refcnt in dedicated build directory.
|
||||
run: cmake -B ${{github.workspace}}/build_refcnt -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_PREFIX_PATH=${{github.workspace}}/local -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/refcnt
|
||||
|
||||
- name: Build refcnt
|
||||
run: cmake --build ${{github.workspace}}/build_refcnt --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Install refcnt
|
||||
# install into ${{github.workspace}}/local
|
||||
run: cmake --install ${{github.workspace}}/build_refcnt
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: Clone reflect
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: Rconybea/reflect
|
||||
path: repo/reflect
|
||||
|
||||
- name: Configure reflect
|
||||
# configure cmake for reflect in dedicated build directory.
|
||||
run: cmake -B ${{github.workspace}}/build_reflect -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_PREFIX_PATH=${{github.workspace}}/local -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local repo/reflect
|
||||
|
||||
- name: Build reflect
|
||||
run: cmake --build ${{github.workspace}}/build_reflect --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Install reflect
|
||||
# install into ${{github.workspace}}/local
|
||||
run: cmake --install ${{github.workspace}}/build_reflect
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
- name: Configure self (printjson)
|
||||
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
|
||||
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
|
||||
run: cmake -B ${{github.workspace}}/build_printjson -DCMAKE_MODULE_PATH=${{github.workspace}}/local/share/cmake -DCMAKE_PREFIX_PATH=${{github.workspace}}/local -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/local -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Build self (printjson)
|
||||
# Build your program with the given configuration
|
||||
run: cmake --build ${{github.workspace}}/build_printjson --config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Test self (printjson)
|
||||
working-directory: ${{github.workspace}}/build_printjson
|
||||
# Execute tests defined by the CMake configuration.
|
||||
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
|
||||
run: ctest -C ${{env.BUILD_TYPE}}
|
||||
6
xo-printjson/.gitignore
vendored
Normal file
6
xo-printjson/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# lsp keeps state here
|
||||
.cache
|
||||
# typical build directories
|
||||
.build*
|
||||
# compile_commands.json symlink -> build/compile_commands.json should be created manually
|
||||
compile_commands.json
|
||||
30
xo-printjson/CMakeLists.txt
Normal file
30
xo-printjson/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# printjson/CMakeLists.txt
|
||||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(printjson VERSION 0.1)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
include(cmake/xo-bootstrap-macros.cmake)
|
||||
|
||||
xo_cxx_toplevel_options3()
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# c++ settings
|
||||
|
||||
# one-time project-specific c++ flags. usually empty
|
||||
set(PROJECT_CXX_FLAGS "")
|
||||
#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2")
|
||||
add_definitions(${PROJECT_CXX_FLAGS})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
add_subdirectory(src/printjson)
|
||||
add_subdirectory(utest)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# provide find_package() support for printjson customers
|
||||
|
||||
xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets)
|
||||
|
||||
# end CMakeLists.txt
|
||||
38
xo-printjson/README.md
Normal file
38
xo-printjson/README.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# printjson library
|
||||
|
||||
## Getting Started
|
||||
|
||||
### build + install dependencies
|
||||
|
||||
- [github/Rconybea/reflect](https://github.com/Rconybea/reflect)
|
||||
|
||||
### build + install
|
||||
|
||||
```
|
||||
$ cd xo-printjson
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ PREFIX=/usr/local # or wherever you prefer
|
||||
$ cmake -DCMAKE_MODULE_PATH=${PREFIX}/share/cmake -DCMAKE_PREFIX_PATH=${PREFIX} -DCMAKE_INSTALL_PREFIX=${PREFIX} ..
|
||||
$ make
|
||||
$ make install
|
||||
```
|
||||
|
||||
### build for unit test coverage
|
||||
|
||||
```
|
||||
$ cd xo-printjson
|
||||
$ mkdir ccov
|
||||
$ cd ccov
|
||||
$ cmake -DCMAKE_MODULE_PATH=${PREFIX}/share/cmake -DCMAKE_PREFIX_PATH=${PREFIX} -DCODE_COVERAGE=ON -DCMAKE_BUILD_TYPE=Debug ..
|
||||
$ make # builds executables
|
||||
$ make ccov # runs instrumented unit tests
|
||||
$ make ccov-all # generates lcov report
|
||||
```
|
||||
|
||||
### LSP support
|
||||
|
||||
```
|
||||
$ cd xo-printjson
|
||||
$ ln -s build/compile_commands.json # lsp will look for compile_commands.json in the root of the source tree
|
||||
```
|
||||
7
xo-printjson/cmake/printjsonConfig.cmake.in
Normal file
7
xo-printjson/cmake/printjsonConfig.cmake.in
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
@PACKAGE_INIT@
|
||||
|
||||
include(CMakeFindDependencyMacro)
|
||||
find_dependency(reflect)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake")
|
||||
check_required_components("@PROJECT_NAME@")
|
||||
35
xo-printjson/cmake/xo-bootstrap-macros.cmake
Normal file
35
xo-printjson/cmake/xo-bootstrap-macros.cmake
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# ----------------------------------------------------------------
|
||||
# for example:
|
||||
# $ PREFIX=/usr/local # for example
|
||||
# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build
|
||||
#
|
||||
# will get
|
||||
# CMAKE_MODULE_PATH
|
||||
# from xo-cmake-config --cmake-module-path
|
||||
#
|
||||
# and expect .cmake macros in
|
||||
# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED)
|
||||
|
||||
if ("${XO_CMAKE_CONFIG_EXECUTABLE}" STREQUAL "XO_CMAKE_CONFIG_EXECUTABLE-NOT_FOUND")
|
||||
message(FATAL "could not find xo-cmake-config executable")
|
||||
endif()
|
||||
|
||||
message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}")
|
||||
|
||||
if (NOT XO_SUBMODULE_BUILD)
|
||||
if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix))
|
||||
# default to typical install location for xo-project-macros
|
||||
execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH)
|
||||
message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# needs to have been installed somewhere on CMAKE_MODULE_PATH,
|
||||
# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX)
|
||||
#
|
||||
include(xo_macros/xo_cxx)
|
||||
|
||||
xo_cxx_bootstrap_message()
|
||||
99
xo-printjson/include/xo/printjson/JsonPrinter.hpp
Normal file
99
xo-printjson/include/xo/printjson/JsonPrinter.hpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* @file JsonPrinter.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
#include "xo/reflect/TypeDrivenMap.hpp"
|
||||
#include "xo/reflect/TaggedPtr.hpp"
|
||||
//#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace json {
|
||||
class PrintJson;
|
||||
|
||||
class JsonPrinter {
|
||||
public:
|
||||
using Reflect = xo::reflect::Reflect;
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
using TypeId = xo::reflect::TypeId;
|
||||
|
||||
public:
|
||||
JsonPrinter(PrintJson const * pjson) : pjson_{pjson} {}
|
||||
virtual ~JsonPrinter() = default;
|
||||
|
||||
PrintJson const * pjson() const { return pjson_; }
|
||||
|
||||
/* print tagged pointer in json format */
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const = 0;
|
||||
|
||||
void report_internal_type_consistency_error(TypeDescr td1,
|
||||
TypeDescr td2,
|
||||
std::ostream * p_os) const;
|
||||
|
||||
/* convenience method for derived printers.
|
||||
* retrieves contents of tp as a T*, complains to *p_os if that fails.
|
||||
*
|
||||
* (Failure would occur if printer for type T was instead installed
|
||||
* for some unrelated type U)
|
||||
*/
|
||||
template<typename T>
|
||||
T * check_recover_native(TaggedPtr tp, std::ostream * p_os) const {
|
||||
T * x = tp.recover_native<T>();
|
||||
|
||||
if (!x) {
|
||||
this->report_internal_type_consistency_error(Reflect::require<T>(),
|
||||
tp.td(),
|
||||
p_os);
|
||||
}
|
||||
|
||||
return x;
|
||||
} /*check_recover_native*/
|
||||
|
||||
void assign_pjson(PrintJson const * pjson) {
|
||||
assert(this->pjson_ == nullptr || this->pjson_ == pjson);
|
||||
this->pjson_ = pjson;
|
||||
} /*assign_pjson*/
|
||||
|
||||
private:
|
||||
/* a json printers is installed into one PrintJson instance;
|
||||
* capture address of that instance at install time
|
||||
*/
|
||||
PrintJson const * pjson_ = nullptr;
|
||||
}; /*JsonPrinter*/
|
||||
|
||||
/* AsStringJsonPrinter<T>
|
||||
* prints a T-instance by using operator<< and surrounding in quotes.
|
||||
*
|
||||
* e.g:
|
||||
* T & x = ..;
|
||||
* std::ostream * p_os = ..;
|
||||
*
|
||||
* *p_os << "\"" << x << "\""
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
class AsStringJsonPrinter : public JsonPrinter {
|
||||
public:
|
||||
AsStringJsonPrinter(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override
|
||||
{
|
||||
T * x = this->check_recover_native<T>(tp, p_os);
|
||||
|
||||
if(x) {
|
||||
*p_os << "\"" << *x << "\"";
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*AsStringJsonPrinter*/
|
||||
} /*namespace json*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end JsonPrinter.hpp */
|
||||
143
xo-printjson/include/xo/printjson/PrintJson.hpp
Normal file
143
xo-printjson/include/xo/printjson/PrintJson.hpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* @file JsonPrinter.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "JsonPrinter.hpp"
|
||||
#include "xo/reflect/TypeDrivenMap.hpp"
|
||||
#include "xo/reflect/SelfTagging.hpp"
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
namespace xo {
|
||||
namespace json {
|
||||
class PrintJson : public reflect::SelfTagging {
|
||||
public:
|
||||
using Reflect = xo::reflect::Reflect;
|
||||
using TypeDrivenMap = xo::reflect::TypeDrivenMap<std::unique_ptr<JsonPrinter>>;
|
||||
using SelfTagging = xo::reflect::SelfTagging;
|
||||
using TaggedPtr = xo::reflect::TaggedPtr;
|
||||
using TaggedRcptr = xo::reflect::TaggedRcptr;
|
||||
using TypeDescr = xo::reflect::TypeDescr;
|
||||
using TypeId = xo::reflect::TypeId;
|
||||
|
||||
public:
|
||||
PrintJson();
|
||||
~PrintJson() = default;
|
||||
|
||||
template<typename T>
|
||||
void print(T const & x_arg, std::ostream * p_os) const {
|
||||
T * x = const_cast<T *>(&x_arg);
|
||||
|
||||
this->print_tp(Reflect::make_tp(x), p_os);
|
||||
} /*print*/
|
||||
|
||||
/* print object tp on stream *p_os, in JSON format;
|
||||
*/
|
||||
void print_tp(TaggedPtr tp, std::ostream * p_os) const;
|
||||
|
||||
/* convenience -- shorthand for
|
||||
* .print(obj->self_tp(), p_os)
|
||||
*/
|
||||
void print_obj(rp<SelfTagging> const & obj, std::ostream * p_os) const;
|
||||
|
||||
void provide_printer(TypeId id, std::unique_ptr<JsonPrinter> p) {
|
||||
*(printer_map_.require(id)) = std::move(p);
|
||||
}
|
||||
|
||||
void provide_printer(TypeDescr td, std::unique_ptr<JsonPrinter> p) {
|
||||
this->provide_printer(td->id(), std::move(p));
|
||||
}
|
||||
|
||||
/* write json representation for tp on *p_os */
|
||||
void print_aux(TaggedPtr tp, std::ostream * p_os) const;
|
||||
|
||||
// ----- inherited from SelfTagging -----
|
||||
|
||||
virtual TaggedRcptr self_tp();
|
||||
|
||||
private:
|
||||
/* provide printers for common basic types */
|
||||
void provide_std_printers();
|
||||
|
||||
private:
|
||||
/* map contains specialized printers for specific c++ types */
|
||||
TypeDrivenMap printer_map_;
|
||||
}; /*PrintJson*/
|
||||
|
||||
/* Using singleton here to collect type-specific json printers,
|
||||
* collected during program initialization.
|
||||
*
|
||||
* Could relabel as PrintJsonInitContext if desired
|
||||
*/
|
||||
class PrintJsonSingleton {
|
||||
public:
|
||||
static rp<PrintJson> instance();
|
||||
|
||||
private:
|
||||
/* we don't need this to be stored as pointer.
|
||||
* memory burned if unused will be one empty std::vector<>
|
||||
*/
|
||||
static rp<PrintJson> s_instance;
|
||||
}; /*PrintJsonSingleton*/
|
||||
|
||||
} /*namespace json*/
|
||||
|
||||
#ifdef NOT_USING
|
||||
namespace print {
|
||||
using PrintJson = xo::json::PrintJson;
|
||||
|
||||
/* stream inserter for printing a T-instance in json format */
|
||||
template<typename T>
|
||||
class jsonp_impl {
|
||||
public:
|
||||
jsonp_impl(T const & x, PrintJson const * pjson) : value_(x), pjson_{pjson} {}
|
||||
//jsonp_impl(T const & x, PrintJson const * pjson) : value_{x}, pjson_{pjson} {}
|
||||
//jsonp_impl(T && x, PrintJson const * pjson) : value_(std::move(x)), pjson_{pjson} {}
|
||||
|
||||
void print(std::ostream & os) const {
|
||||
using xo::reflect::Reflect;
|
||||
|
||||
this->pjson_->print_tp(Reflect::make_tp(&value_), &os);
|
||||
} /*print*/
|
||||
|
||||
private:
|
||||
/* value, to be printed, in json format */
|
||||
T value_;
|
||||
/* json printer (bc we don't care for singletons) */
|
||||
PrintJson const * pjson_ = nullptr;
|
||||
}; /*jsonp_impl*/
|
||||
|
||||
template<typename T>
|
||||
inline
|
||||
std::ostream & operator<<(std::ostream & os, jsonp_impl<T> const & x) {
|
||||
x.print(os);
|
||||
return os;
|
||||
} /*operator<<*/
|
||||
|
||||
/* writing out std::forward<T> behavior for completeness' sake:
|
||||
*
|
||||
* 1. call jsonp(x) with rvalue std::string x, then:
|
||||
* - T will be deduced to [std::string]
|
||||
* (in particular: _not_ std::string &, std::string const &, std::string &&)
|
||||
* - rvalue std::string passed to jsonp_impl ctor
|
||||
*
|
||||
* 2a. call jsonp(x) with std::string & x, then:
|
||||
* - T deduced to [std::string &]
|
||||
* - std::string & passed to jsonp_impl ctor
|
||||
*
|
||||
* 2b. call jsonp(x) with std::string const & x, then:
|
||||
* - T deduced to [std::string const &]
|
||||
* - std::string const & passed to jsonp_impl ctor
|
||||
*/
|
||||
template<typename T>
|
||||
auto jsonp(T && x, PrintJson const * pjson) {
|
||||
return jsonp_impl<T>(std::forward<T>(x), pjson);
|
||||
} /*jsonp*/
|
||||
} /*namespace print*/
|
||||
#endif
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end JsonPrinter.hpp */
|
||||
29
xo-printjson/include/xo/printjson/init_printjson.hpp
Normal file
29
xo-printjson/include/xo/printjson/init_printjson.hpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* file init_printjson.hpp
|
||||
*
|
||||
* author: Roland Conybeare, Sep 2022
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "xo/subsys/Subsystem.hpp"
|
||||
|
||||
namespace xo {
|
||||
/* tag to represent the printjson/ subsystem within ordered initialization */
|
||||
enum S_printjson_tag {};
|
||||
|
||||
/* Use:
|
||||
* // anywhere, to declare printjson dependency e.g. at file scope
|
||||
* InitEvidence s_evidence = InitSubsys<S_printjson_tag>::require();
|
||||
*
|
||||
* // from main(), though can resort to module initialization in a pybind11 library
|
||||
* Subsystem::initialize_all();
|
||||
*/
|
||||
template<>
|
||||
struct InitSubsys<S_printjson_tag> {
|
||||
static void init();
|
||||
static InitEvidence require();
|
||||
};
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end init_printjson.hpp */
|
||||
13
xo-printjson/src/printjson/CMakeLists.txt
Normal file
13
xo-printjson/src/printjson/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
# xo-printjson/src/printjson/CMakeLists.txt
|
||||
|
||||
set(SELF_LIB printjson)
|
||||
set(SELF_SRCS PrintJson.cpp init_printjson.cpp)
|
||||
|
||||
xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# dependencies: indentlog, ...
|
||||
|
||||
xo_dependency(${SELF_LIB} reflect)
|
||||
|
||||
# end CMakeLists.txt
|
||||
447
xo-printjson/src/printjson/PrintJson.cpp
Normal file
447
xo-printjson/src/printjson/PrintJson.cpp
Normal file
|
|
@ -0,0 +1,447 @@
|
|||
/* file JsonPrinter.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#include "PrintJson.hpp"
|
||||
//#include "time/Time.hpp"
|
||||
#include "xo/reflect/TypeDescr.hpp"
|
||||
#include "xo/indentlog/print/tag.hpp"
|
||||
#include <cmath>
|
||||
|
||||
namespace xo {
|
||||
using xo::time::utc_nanos;
|
||||
using xo::reflect::Metatype;
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::SelfTagging;
|
||||
using xo::reflect::TypeDescr;
|
||||
using xo::reflect::TaggedPtr;
|
||||
using xo::reflect::TaggedRcptr;
|
||||
using xo::print::quot;
|
||||
using xo::time::iso8601;
|
||||
using xo::xtag;
|
||||
|
||||
namespace json {
|
||||
TaggedRcptr
|
||||
PrintJson::self_tp()
|
||||
{
|
||||
return Reflect::make_rctp(this);
|
||||
//return TaggedRcptr::make(this);
|
||||
} /*self_tp*/
|
||||
|
||||
void
|
||||
JsonPrinter::report_internal_type_consistency_error(TypeDescr td1,
|
||||
TypeDescr td2,
|
||||
std::ostream * p_os) const
|
||||
{
|
||||
*p_os << "<internal-error: type mismatch between T & S"
|
||||
<< xtag("T", td1->canonical_name())
|
||||
<< xtag("S", td2->canonical_name())
|
||||
<< ">";
|
||||
} /*report_internal_type_consistency_error*/
|
||||
|
||||
namespace {
|
||||
/* this will be used when TaggedPtr refers to a pointer-like value,
|
||||
* e.g.
|
||||
* xo::ref::rp<T>
|
||||
*/
|
||||
void
|
||||
print_generic_pointer(PrintJson const & print_json,
|
||||
TaggedPtr tp,
|
||||
std::ostream * p_os)
|
||||
{
|
||||
/* e.g. if
|
||||
* xo::ref::rp<VanillaOption> opt = ...;
|
||||
* then expect to print just as we would for
|
||||
* VanillaOption & opt = ...;
|
||||
* if pointer is null, will print {}
|
||||
*/
|
||||
|
||||
if (tp.n_child()) {
|
||||
print_json.print_aux(tp.get_child(0), p_os);
|
||||
} else {
|
||||
/* note: this can be distinguished from a bona fide struct,
|
||||
* b/c it doesn't supply the _name_ member
|
||||
*/
|
||||
*p_os << "{}";
|
||||
}
|
||||
} /*print_generic_pointer*/
|
||||
|
||||
/* this will be used when TaggedPtr refers to a vector-like value,
|
||||
* e.g.
|
||||
* std::vector<T>
|
||||
* std::array<T, N>
|
||||
*/
|
||||
void
|
||||
print_generic_vector(PrintJson const & print_json,
|
||||
TaggedPtr tp,
|
||||
std::ostream * p_os)
|
||||
{
|
||||
/* e.g. if
|
||||
* std::array<double, 3> v{1, 2, 3};
|
||||
*
|
||||
* then expect to print
|
||||
* [1.0, 2.0, 3.0]
|
||||
*/
|
||||
|
||||
*p_os << "[";
|
||||
|
||||
for (uint32_t i = 0, n = tp.n_child(); i < n; ++i) {
|
||||
if (i > 0)
|
||||
*p_os << ", ";
|
||||
|
||||
print_json.print_aux(tp.get_child(i), p_os);
|
||||
}
|
||||
|
||||
*p_os << "]";
|
||||
} /*print_generic_vector*/
|
||||
|
||||
/* this will be used when TaggedPtr is understood to refer to a struct-like value.
|
||||
*/
|
||||
void
|
||||
print_generic_struct(PrintJson const & print_json,
|
||||
TaggedPtr tp,
|
||||
std::ostream * p_os)
|
||||
{
|
||||
/* e.g. if
|
||||
* struct Foo { int x_; double y_; };
|
||||
* Foo foo{1, 1.4142};
|
||||
*
|
||||
* then expect to print
|
||||
* {"_name_": "Foo", "x": 1, "y": 1.4142}
|
||||
*
|
||||
* note that python json parser requires property names in double quotes
|
||||
*/
|
||||
|
||||
*p_os << "{";
|
||||
|
||||
*p_os << "\"_name_\": \"" << tp.td()->short_name() << "\"";
|
||||
|
||||
for (uint32_t i = 0, n = tp.n_child(); i < n; ++i) {
|
||||
*p_os << ", \"" << tp.struct_member_name(i) << "\": ";
|
||||
|
||||
print_json.print_aux(tp.get_child(i), p_os);
|
||||
}
|
||||
|
||||
*p_os << "}";
|
||||
} /*print_generic_struct*/
|
||||
|
||||
} /*namespace*/
|
||||
|
||||
void
|
||||
PrintJson::print_aux(TaggedPtr tp,
|
||||
std::ostream * p_os) const
|
||||
{
|
||||
if (tp.td()) {
|
||||
TypeId id = tp.td()->id();
|
||||
|
||||
std::unique_ptr<JsonPrinter> const * printer
|
||||
= this->printer_map_.lookup(id);
|
||||
|
||||
if (printer && *printer) {
|
||||
(*printer)->print_json(tp, p_os);
|
||||
} else {
|
||||
/* if no special-case printer, apply generic printing behavior */
|
||||
switch (tp.td()->metatype()) {
|
||||
case Metatype::mt_pointer:
|
||||
print_generic_pointer(*this, tp, p_os);
|
||||
return;
|
||||
case Metatype::mt_vector:
|
||||
print_generic_vector(*this, tp, p_os);
|
||||
return;
|
||||
case Metatype::mt_struct:
|
||||
print_generic_struct(*this, tp, p_os);
|
||||
return;
|
||||
case Metatype::mt_function:
|
||||
/** new branch (added for xo-expression / xo-jit) **/
|
||||
(*p_os) << "<error-json-printer-not-implemented"
|
||||
<< xtag("type", tp.td()->canonical_name())
|
||||
<< xtag("metatype", tp.td()->metatype())
|
||||
<< ">";
|
||||
return;
|
||||
case Metatype::mt_invalid:
|
||||
case Metatype::mt_atomic:
|
||||
break;
|
||||
}
|
||||
|
||||
(*p_os) << "<error-json-printer-not-found"
|
||||
<< xtag("type", tp.td()->canonical_name())
|
||||
<< xtag("metatype", tp.td()->metatype())
|
||||
<< ">";
|
||||
}
|
||||
} else {
|
||||
(*p_os) << "<error-null-tp>";
|
||||
}
|
||||
} /*print_aux*/
|
||||
|
||||
void
|
||||
PrintJson::print_tp(TaggedPtr tp,
|
||||
std::ostream * p_os) const
|
||||
{
|
||||
this->print_aux(tp, p_os);
|
||||
//*p_os << std::ends;
|
||||
} /*print*/
|
||||
|
||||
void
|
||||
PrintJson::print_obj(rp<SelfTagging> const & obj, std::ostream * p_os) const
|
||||
{
|
||||
assert(obj.get());
|
||||
|
||||
this->print_tp(obj->self_tp(), p_os);
|
||||
} /*print_obj*/
|
||||
|
||||
/* Consider:
|
||||
* TaggedPtr tp = ...;
|
||||
* std::ostream * p_os = ...;
|
||||
*
|
||||
* PrintJson * pjson = PrintJsonSingleton::instance();
|
||||
*
|
||||
* // print json representation, depending on runtime type of tp's target
|
||||
* pjson->print_tp(tp, p_os);
|
||||
*
|
||||
* // can also use .print(), relying on JsonPrinter_TaggedPtr
|
||||
* // .print() will next original TaggedPtr in another;
|
||||
* // this shim unwinds that
|
||||
* //
|
||||
* pjson->print(tp, p_os);
|
||||
*/
|
||||
class JsonPrinter_TaggedPtr : public JsonPrinter {
|
||||
public:
|
||||
JsonPrinter_TaggedPtr(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override {
|
||||
TaggedPtr * x = this->check_recover_native<TaggedPtr>(tp, p_os);
|
||||
|
||||
if (x) {
|
||||
this->pjson()->print_tp(*x, p_os);
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*JsonPrinter_TaggedPtr*/
|
||||
|
||||
namespace {
|
||||
void
|
||||
provide_tagged_ptr_printer(PrintJson * p_json)
|
||||
{
|
||||
std::unique_ptr<JsonPrinter> printer(new JsonPrinter_TaggedPtr(p_json));
|
||||
|
||||
p_json->provide_printer(Reflect::require<TaggedPtr>(),
|
||||
std::move(printer));
|
||||
} /*provide_tagged_ptr_printer*/
|
||||
} /*namespace*/
|
||||
|
||||
class JsonPrinter_bool : public JsonPrinter {
|
||||
public:
|
||||
JsonPrinter_bool(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override {
|
||||
bool * x = this->check_recover_native<bool>(tp, p_os);
|
||||
|
||||
if (x) {
|
||||
/* json boolean format is lower case true/false.
|
||||
* (note that this conflicts with python True/False, achtung!)
|
||||
*/
|
||||
*p_os << (*x ? "true" : "false");
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*JsonPrinter_bool*/
|
||||
|
||||
namespace {
|
||||
void
|
||||
provide_bool_printer(PrintJson * p_json)
|
||||
{
|
||||
std::unique_ptr<JsonPrinter> printer(new JsonPrinter_bool(p_json));
|
||||
|
||||
p_json->provide_printer(Reflect::require<bool>(),
|
||||
std::move(printer));
|
||||
} /*provide_bool_printer*/
|
||||
} /*namespace*/
|
||||
|
||||
template<typename T>
|
||||
class JsonPrinter_integer : public JsonPrinter {
|
||||
public:
|
||||
JsonPrinter_integer(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override {
|
||||
T * x = tp.recover_native<T>();
|
||||
|
||||
if (x) {
|
||||
*p_os << *x;
|
||||
} else {
|
||||
report_internal_type_consistency_error(Reflect::require<T>(),
|
||||
tp.td(),
|
||||
p_os);
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*JsonPrinter_integer*/
|
||||
|
||||
namespace {
|
||||
template<typename T>
|
||||
void
|
||||
provide_integer_printer(PrintJson * p_json)
|
||||
{
|
||||
std::unique_ptr<JsonPrinter> printer(new JsonPrinter_integer<T>(p_json));
|
||||
|
||||
p_json->provide_printer(Reflect::require<T>(), std::move(printer));
|
||||
} /*provide_integer_printer*/
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class JsonPrinter_floatingpoint : public JsonPrinter {
|
||||
public:
|
||||
JsonPrinter_floatingpoint(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override
|
||||
{
|
||||
T * x = tp.recover_native<T>();
|
||||
|
||||
if (x) {
|
||||
if (std::isfinite(*x)) {
|
||||
*p_os << *x;
|
||||
} else {
|
||||
/* special cases.
|
||||
* use javascript-friendly format
|
||||
*
|
||||
* Note non-finite floating-point values are not representable in
|
||||
* standard json (?!#), though it's a standard extension
|
||||
*/
|
||||
|
||||
if (std::isnan(*x))
|
||||
*p_os << "NaN";
|
||||
else if (*x > 0.0)
|
||||
*p_os << "Infinity";
|
||||
else
|
||||
*p_os << "-Infinity";
|
||||
}
|
||||
} else {
|
||||
report_internal_type_consistency_error(Reflect::require<T>(),
|
||||
tp.td(),
|
||||
p_os);
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*JsonPrinter_floatingpoint*/
|
||||
|
||||
namespace {
|
||||
template<typename T>
|
||||
void
|
||||
provide_floatingpoint_printer(PrintJson * p_json)
|
||||
{
|
||||
std::unique_ptr<JsonPrinter> printer(new JsonPrinter_floatingpoint<T>(p_json));
|
||||
|
||||
p_json->provide_printer(Reflect::require<T>(), std::move(printer));
|
||||
} /*provide_floatingpoint_printer*/
|
||||
} /*namespace*/
|
||||
|
||||
template<typename T>
|
||||
class JsonPrinter_string : public JsonPrinter {
|
||||
public:
|
||||
JsonPrinter_string(PrintJson const * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override {
|
||||
T * x = tp.recover_native<T>();
|
||||
|
||||
if (x) {
|
||||
/* TODO: escapes special characters */
|
||||
*p_os << quot(*x);
|
||||
} else {
|
||||
report_internal_type_consistency_error(Reflect::require<T>(),
|
||||
tp.td(),
|
||||
p_os);
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*JsonPrinter_string*/
|
||||
|
||||
namespace {
|
||||
template<typename T>
|
||||
void
|
||||
provide_string_printer(PrintJson * p_json)
|
||||
{
|
||||
std::unique_ptr<JsonPrinter> printer(new JsonPrinter_string<T>(p_json));
|
||||
|
||||
p_json->provide_printer(Reflect::require<T>(), std::move(printer));
|
||||
} /*provide_string_printer*/
|
||||
} /*namespace */
|
||||
|
||||
class JsonPrinter_utc_nanos : public JsonPrinter {
|
||||
public:
|
||||
JsonPrinter_utc_nanos(PrintJson * pjson) : JsonPrinter(pjson) {}
|
||||
|
||||
virtual void print_json(TaggedPtr tp,
|
||||
std::ostream * p_os) const override {
|
||||
utc_nanos * x = tp.recover_native<utc_nanos>();
|
||||
|
||||
if (x) {
|
||||
/* format like
|
||||
* "2012-04-23T18:25:43.511Z"
|
||||
* since that's what javascript uses
|
||||
*/
|
||||
*p_os << "\"" << iso8601(*x) << "\"";
|
||||
} else {
|
||||
report_internal_type_consistency_error(Reflect::require<utc_nanos>(),
|
||||
tp.td(),
|
||||
p_os);
|
||||
}
|
||||
} /*print_json*/
|
||||
}; /*JsonPrinter_utc_nanos*/
|
||||
|
||||
namespace {
|
||||
void
|
||||
provide_utc_nanos_printer(PrintJson * p_json)
|
||||
{
|
||||
std::unique_ptr<JsonPrinter> printer(new JsonPrinter_utc_nanos(p_json));
|
||||
|
||||
p_json->provide_printer(Reflect::require<utc_nanos>(),
|
||||
std::move(printer));
|
||||
} /*provide_utc_nanos_printer*/
|
||||
} /*namespace*/
|
||||
|
||||
PrintJson::PrintJson() {
|
||||
this->provide_std_printers();
|
||||
} /*ctor*/
|
||||
|
||||
/* provide printers for common basic types */
|
||||
void
|
||||
PrintJson::provide_std_printers()
|
||||
{
|
||||
provide_tagged_ptr_printer(this);
|
||||
|
||||
provide_bool_printer(this);
|
||||
|
||||
provide_integer_printer<std::int16_t>(this);
|
||||
provide_integer_printer<std::uint16_t>(this);
|
||||
provide_integer_printer<std::int32_t>(this);
|
||||
provide_integer_printer<std::uint32_t>(this);
|
||||
provide_integer_printer<std::int64_t>(this);
|
||||
provide_integer_printer<std::uint64_t>(this);
|
||||
|
||||
provide_floatingpoint_printer<float>(this);
|
||||
provide_floatingpoint_printer<double>(this);
|
||||
|
||||
provide_string_printer<char *>(this);
|
||||
provide_string_printer<char const *>(this);
|
||||
provide_string_printer<std::string>(this);
|
||||
provide_string_printer<std::string_view>(this);
|
||||
|
||||
provide_utc_nanos_printer(this);
|
||||
} /*provide_std_printers*/
|
||||
|
||||
rp<PrintJson>
|
||||
PrintJsonSingleton::s_instance;
|
||||
|
||||
rp<PrintJson>
|
||||
PrintJsonSingleton::instance()
|
||||
{
|
||||
if (!s_instance)
|
||||
s_instance = new PrintJson();
|
||||
|
||||
return s_instance;
|
||||
} /*instance*/
|
||||
|
||||
} /*namespace json*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end JsonPrinter.cpp */
|
||||
36
xo-printjson/src/printjson/init_printjson.cpp
Normal file
36
xo-printjson/src/printjson/init_printjson.cpp
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
/* file init_printjson.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Sep 2022
|
||||
*/
|
||||
|
||||
#include "init_printjson.hpp"
|
||||
#include "PrintJson.hpp"
|
||||
#include "xo/reflect/init_reflect.hpp"
|
||||
#include "xo/subsys/Subsystem.hpp"
|
||||
|
||||
namespace xo {
|
||||
using xo::json::PrintJsonSingleton;
|
||||
|
||||
void
|
||||
InitSubsys<S_printjson_tag>::init()
|
||||
{
|
||||
/* create singleton */
|
||||
PrintJsonSingleton::instance();
|
||||
} /*init*/
|
||||
|
||||
InitEvidence
|
||||
InitSubsys<S_printjson_tag>::require()
|
||||
{
|
||||
InitEvidence retval;
|
||||
|
||||
/* subsystem dependencies for printjson/ */
|
||||
retval ^= InitSubsys<S_reflect_tag>::require();
|
||||
|
||||
/* printjson/'s own initialization code */
|
||||
retval ^= Subsystem::provide<S_printjson_tag>("printjson", &init);
|
||||
|
||||
return retval;
|
||||
} /*require*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end init_printjson.cpp */
|
||||
10
xo-printjson/utest/CMakeLists.txt
Normal file
10
xo-printjson/utest/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# build unittest printjson/utest
|
||||
|
||||
set(SELF_EXE utest.printjson)
|
||||
set(SELF_SRCS printjson_utest_main.cpp PrintJson.test.cpp)
|
||||
|
||||
xo_add_utest_executable(${SELF_EXE} ${SELF_SRCS})
|
||||
xo_self_dependency(${SELF_EXE} printjson)
|
||||
xo_external_target_dependency(${SELF_EXE} Catch2 Catch2::Catch2)
|
||||
|
||||
# end CMakeLists.txt
|
||||
55
xo-printjson/utest/CMakeLists.txt.safe
Normal file
55
xo-printjson/utest/CMakeLists.txt.safe
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# build unittest printjson/utest
|
||||
|
||||
set(SELF_EXECUTABLE_NAME utest.printjson)
|
||||
set(SELF_SOURCE_FILES printjson_utest_main.cpp PrintJson.test.cpp)
|
||||
|
||||
add_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES})
|
||||
|
||||
add_test(NAME ${SELF_EXECUTABLE_NAME} COMMAND ${SELF_EXECUTABLE_NAME})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# generic project dependency
|
||||
|
||||
# PROJECT_SOURCE_DIR:
|
||||
# so we can for example write
|
||||
# #include "indentlog/scope.hpp"
|
||||
# from anywhere in the project
|
||||
# PROJECT_BINARY_DIR:
|
||||
# since version file will be in build directory, need that directory
|
||||
# to also be included in compiler's include path
|
||||
#
|
||||
target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC
|
||||
${PROJECT_SOURCE_DIR}
|
||||
${PROJECT_BINARY_DIR})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# internal dependencies: logutil, ...
|
||||
|
||||
target_link_libraries(${SELF_EXECUTABLE_NAME} PUBLIC printjson)
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# 3rd part dependency: catch2:
|
||||
|
||||
find_package(Catch2 2 REQUIRED)
|
||||
|
||||
# need this so that catch2/include appears in compile_commands.json,
|
||||
# on which lsp integration relies.
|
||||
#
|
||||
# See also /nix/store/*-catch2-*/lib/cmake/Catch2/ParseAndAddCatchTests.cmake;
|
||||
# commands here derived from ^ .cmake file
|
||||
#
|
||||
find_path(CATCH_INCLUDE_DIR "catch2/catch.hpp")
|
||||
target_include_directories(${SELF_EXECUTABLE_NAME} PUBLIC ${CATCH_INCLUDE_DIR})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# make standard directories for std:: includes explicit
|
||||
# so that
|
||||
# (1) they appear in compile_commands.json.
|
||||
# (2) clangd (run from emacs lsp-mode) can find them
|
||||
#
|
||||
if(CMAKE_EXPORT_COMPILE_COMMANDS)
|
||||
set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES
|
||||
${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
|
||||
endif()
|
||||
|
||||
# end CMakeLists.txt
|
||||
124
xo-printjson/utest/PrintJson.test.cpp
Normal file
124
xo-printjson/utest/PrintJson.test.cpp
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/* file PrintJson.test.cpp
|
||||
*
|
||||
* author: Roland Conybeare, Aug 2022
|
||||
*/
|
||||
|
||||
#include "xo/printjson/PrintJson.hpp"
|
||||
#include "xo/printjson/init_printjson.hpp"
|
||||
#include "xo/reflect/Reflect.hpp"
|
||||
#include "xo/reflect/StructReflector.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
//#define STRINGIFY(x) #x
|
||||
|
||||
namespace xo {
|
||||
using xo::json::PrintJson;
|
||||
using xo::reflect::Reflect;
|
||||
using xo::reflect::StructReflector;
|
||||
using xo::reflect::TaggedPtr;
|
||||
|
||||
namespace ut {
|
||||
InitEvidence s_init_evidence = InitSubsys<S_printjson_tag>::require();
|
||||
|
||||
namespace {
|
||||
struct TestStruct0 {};
|
||||
}
|
||||
|
||||
TEST_CASE("print-json-empty-struct", "[printjson]") {
|
||||
INFO(tag("s_init_evidence", s_init_evidence));
|
||||
|
||||
StructReflector<TestStruct0> sr;
|
||||
|
||||
sr.require_complete();
|
||||
|
||||
TestStruct0 recd0;
|
||||
|
||||
PrintJson print_json;
|
||||
|
||||
TaggedPtr tp = Reflect::make_tp(&recd0);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
print_json.print(tp, &ss);
|
||||
|
||||
REQUIRE(ss.str() == std::string("{\"_name_\": \"TestStruct0\"}"));
|
||||
} /*TEST_CASE(print-json-empty-struct)*/
|
||||
|
||||
namespace {
|
||||
struct TestStruct1 {
|
||||
std::int16_t i16_; std::uint16_t u16_;
|
||||
std::int32_t i32_; std::uint32_t u32_;
|
||||
std::int64_t i64_; std::uint64_t u64_;
|
||||
float f32_; double f64_;
|
||||
std::string s_;
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("print-json-s1", "[printjson]") {
|
||||
INFO(tag("s_init_evidence", s_init_evidence));
|
||||
|
||||
StructReflector<TestStruct1> sr;
|
||||
{
|
||||
REFLECT_MEMBER(sr, i16);
|
||||
REFLECT_MEMBER(sr, u16);
|
||||
REFLECT_MEMBER(sr, i32);
|
||||
REFLECT_MEMBER(sr, u32);
|
||||
REFLECT_MEMBER(sr, i64);
|
||||
REFLECT_MEMBER(sr, u64);
|
||||
REFLECT_MEMBER(sr, f32);
|
||||
REFLECT_MEMBER(sr, f64);
|
||||
REFLECT_MEMBER(sr, s);
|
||||
|
||||
sr.require_complete();
|
||||
}
|
||||
|
||||
TestStruct1 recd1{-1, 2, -3, 4, -5, 6, 1.23f, 4.56, "hello, world"};
|
||||
|
||||
PrintJson print_json;
|
||||
|
||||
TaggedPtr tp = Reflect::make_tp(&recd1);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
print_json.print(tp, &ss);
|
||||
|
||||
REQUIRE(ss.str() == std::string("{\"_name_\": \"TestStruct1\""
|
||||
", \"i16\": -1"
|
||||
", \"u16\": 2"
|
||||
", \"i32\": -3"
|
||||
", \"u32\": 4"
|
||||
", \"i64\": -5"
|
||||
", \"u64\": 6"
|
||||
", \"f32\": 1.23"
|
||||
", \"f64\": 4.56"
|
||||
", \"s\": \"hello, world\"}"));
|
||||
} /*TEST_CASE(print-json-s1)*/
|
||||
|
||||
TEST_CASE("print-json-v1", "[printjson]") {
|
||||
INFO(tag("s_init_evidence", s_init_evidence));
|
||||
|
||||
std::vector<double> v1{1, 2, 3};
|
||||
|
||||
PrintJson print_json;
|
||||
|
||||
TaggedPtr tp = Reflect::make_tp(&v1);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
print_json.print(tp, &ss);
|
||||
|
||||
REQUIRE(ss.str() == std::string("[1, 2, 3]"));
|
||||
} /*TEST_CASE(print-json-v1)*/
|
||||
|
||||
/* also see tests:
|
||||
* [option_util/utest/Px2.test.cpp]
|
||||
* [option_util/utest/Size2.test.cpp]
|
||||
* [option_util/utest/PxSize2.test.cpp]
|
||||
*/
|
||||
} /*namespace ut */
|
||||
} /*namespace xo*/
|
||||
|
||||
|
||||
/* end StructReflector.test.cpp */
|
||||
6
xo-printjson/utest/printjson_utest_main.cpp
Normal file
6
xo-printjson/utest/printjson_utest_main.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/* file printjson_utest_main.cpp */
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
/* end printjson_utest_main.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue