mirror of
https://github.com/boostorg/exception.git
synced 2026-07-04 23:51:38 +02:00
Serialization for error info objects to Boost JSON and nlohmann/json
This commit is contained in:
@@ -238,6 +238,10 @@ jobs:
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
git submodule update --init tools/boostdep
|
||||
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
|
||||
cd libs/throw_exception
|
||||
git fetch origin feature/serialization
|
||||
git checkout feature/serialization
|
||||
cd ../..
|
||||
./bootstrap.sh
|
||||
./b2 -d0 headers
|
||||
|
||||
@@ -246,6 +250,11 @@ jobs:
|
||||
run: |
|
||||
echo "using ${{matrix.toolset}} : : ${{matrix.compiler}} ;" > ~/user-config.jam
|
||||
|
||||
- name: Download nlohmann/json
|
||||
run: |
|
||||
cd ../boost-root/libs/$LIBRARY
|
||||
python3 scripts/download_nlohmann_json.py
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
cd ../boost-root
|
||||
@@ -293,9 +302,19 @@ jobs:
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
|
||||
cd libs\throw_exception
|
||||
git fetch origin feature/serialization
|
||||
git checkout feature/serialization
|
||||
cd ..\..
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
- name: Download nlohmann/json
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root/libs/%LIBRARY%
|
||||
python3 scripts/download_nlohmann_json.py
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
/.vscode/settings.json
|
||||
.DS_Store
|
||||
doc/html/index.html
|
||||
/test/nlohmann/
|
||||
|
||||
Vendored
+101
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Download nlohmann/json.hpp",
|
||||
"type": "shell",
|
||||
"command": "python scripts/download_nlohmann_json.py",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "b2: Run all tests (default)",
|
||||
"type": "shell",
|
||||
"dependsOn": ["Download nlohmann/json.hpp"],
|
||||
"command": "../../b2 test",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": "test",
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
},
|
||||
"windows": {
|
||||
"command": "..\\..\\b2 test",
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "b2: Run all tests (release)",
|
||||
"type": "shell",
|
||||
"dependsOn": ["Download nlohmann/json.hpp"],
|
||||
"command": "../../b2 test variant=release",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": "test",
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
},
|
||||
"windows": {
|
||||
"command": "..\\..\\b2 test variant=release",
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "b2: Run all tests (all configs)",
|
||||
"type": "shell",
|
||||
"dependsOn": ["Download nlohmann/json.hpp"],
|
||||
"command": "../../b2 test exception-handling=on,off rtti=on,off variant=debug,release link=static,shared",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": "test",
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
},
|
||||
"windows": {
|
||||
"command": "..\\..\\b2 test exception-handling=on,off rtti=on,off variant=debug,release link=static,shared",
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"label": "b2: Run test for current editor file",
|
||||
"type": "shell",
|
||||
"dependsOn": ["Download nlohmann/json.hpp"],
|
||||
"command": "../../b2 test ${fileBasenameNoExtension}.test",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": {
|
||||
"base": "$gcc",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
},
|
||||
"windows": {
|
||||
"command": "..\\..\\b2 test ${fileBasenameNoExtension}.test",
|
||||
"problemMatcher": {
|
||||
"base": "$msCompile",
|
||||
"fileLocation": ["relative", "${workspaceFolder}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+400
-46
@@ -453,6 +453,164 @@ std::exception::what: example_io error
|
||||
[struct boost::errinfo_file_open_mode_ *] = rb
|
||||
----
|
||||
|
||||
[[tutorial_serialization]]
|
||||
=== Serialization
|
||||
|
||||
Boost Exception provides a serialization API that enables exporting diagnostic information into different formats, such as JSON. This is useful for structured logging, remote debugging, or integrating with monitoring systems.
|
||||
|
||||
To serialize diagnostic information, use the following functions:
|
||||
|
||||
* `<<serialize_diagnostic_information_to,serialize_diagnostic_information_to>>` -- serializes diagnostic information for a given exception.
|
||||
* `<<serialize_current_exception_diagnostic_information_to,serialize_current_exception_diagnostic_information_to>>` -- serializes diagnostic information for the current exception.
|
||||
|
||||
The serialization system uses `output` and `output_at` functions found via ADL:
|
||||
|
||||
* `output(enc, x)` serializes value `x` directly to encoder `enc`.
|
||||
* `output_at(enc, x, name)` serializes value `x` to encoder `enc` as a named field.
|
||||
|
||||
[[custom-encoders]]
|
||||
==== Custom Encoders
|
||||
|
||||
To support exporting to a specific format, users define an encoder class with associated `output` and `output_at` function templates:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
struct my_encoder
|
||||
{
|
||||
template <class T>
|
||||
friend void output(my_encoder & enc, T const & x)
|
||||
{
|
||||
// output value x to enc
|
||||
}
|
||||
|
||||
template <class T>
|
||||
friend void output_at(my_encoder & enc, T const & x, char const * name)
|
||||
{
|
||||
// output x to enc as a named field
|
||||
}
|
||||
};
|
||||
----
|
||||
|
||||
The `output_at` function typically creates a nested scope (e.g. a JSON object) and then calls `output` to serialize the value.
|
||||
|
||||
To enable serialization to a custom encoder type, define a `<<serialize,serialize>>` function template in the `boost::exception_serialization` namespace:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
template <class Handle, class T>
|
||||
void serialize(Handle & h, T const & x, char const * name)
|
||||
{
|
||||
h.dispatch([&](my_encoder & enc) {
|
||||
output_at(enc, x, name);
|
||||
});
|
||||
}
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
The `<<serialize,serialize>>` function template takes a handle reference `h` (of unspecified type) that holds an encoder, the object to be serialized, and its type name. Call `h.dispatch` with a single-argument function F to detect the encoder type based on F's argument type; F is called only if the handle contains an encoder of that type.
|
||||
|
||||
To support multiple output formats, pass multiple functions to `h.dispatch`:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
h.dispatch(
|
||||
[&](json_encoder & enc) { output_at(enc, x, name); },
|
||||
[&](xml_encoder & enc) { output_at(enc, x, name); }
|
||||
);
|
||||
----
|
||||
|
||||
==== JSON Serialization
|
||||
|
||||
Boost Exception provides two JSON encoders:
|
||||
|
||||
* `<<boost_json_encoder,boost_json_encoder>>` for https://www.boost.org/doc/libs/release/libs/json/[Boost.JSON]
|
||||
* `<<nlohmann_json_encoder,nlohmann_json_encoder>>` based on ADL calls to `to_json` (compatible with https://github.com/nlohmann/json[nlohmann/json])
|
||||
|
||||
Below is an example using `nlohmann_json_encoder` with nlohmann/json. We just need to define the required `<<serialize,serialize>>` function template (see <<custom-encoders>>):
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
using nlohmann_json_encoder = boost::exception_serialization::nlohmann_json_encoder<nlohmann::json>;
|
||||
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
template <class Handle, class T>
|
||||
void serialize(Handle & h, T const & x, char const * name)
|
||||
{
|
||||
h.dispatch([&](nlohmann_json_encoder & enc) {
|
||||
output_at(enc, x, name);
|
||||
});
|
||||
}
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
With this in place, we can output diagnostic information to JSON:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
#include <boost/exception/diagnostic_information.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct api_response
|
||||
{
|
||||
int status;
|
||||
std::string message;
|
||||
|
||||
template <class Json>
|
||||
friend void to_json(Json & j, api_response const & e)
|
||||
{
|
||||
j["status"] = e.status;
|
||||
j["message"] = e.message;
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::error_info<struct errinfo_api_response_, api_response> errinfo_api_response;
|
||||
typedef boost::error_info<struct errinfo_request_url_, std::string> errinfo_request_url;
|
||||
|
||||
struct api_error : virtual boost::exception, virtual std::exception { };
|
||||
|
||||
....
|
||||
|
||||
nlohmann::json j;
|
||||
try
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(api_error()
|
||||
<< errinfo_api_response({403, "Access denied"})
|
||||
<< errinfo_request_url("/api/admin/settings"));
|
||||
}
|
||||
catch(boost::exception & e)
|
||||
{
|
||||
nlohmann_json_encoder enc{j};
|
||||
boost::serialize_diagnostic_information_to(enc, e);
|
||||
}
|
||||
std::cout << j.dump(2) << std::endl;
|
||||
----
|
||||
|
||||
.Output:
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"errinfo_api_response_": {
|
||||
"status": 403,
|
||||
"message": "Access denied"
|
||||
},
|
||||
"errinfo_request_url_": "/api/admin/settings"
|
||||
}
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
<<serialize_diagnostic_information_to>> | <<nlohmann_json_encoder>>
|
||||
|
||||
NOTE: In the example above, `api_response` uses an unqualified call to `to_json` for serialization. This is to demonstrate that `nlohmann_json_encoder` handles third party types with suitable `to_json` overloads automatically. If instead we defined a function `output` compatible with the Boost Exception serialization API, it would make `api_response` compatible with any Boost Exception encoder.
|
||||
|
||||
[[synopsis]]
|
||||
== Synopsis
|
||||
|
||||
@@ -604,11 +762,17 @@ namespace boost
|
||||
char const * diagnostic_information_what( boost::exception const & e, bool verbose=true ) throw();
|
||||
|
||||
std::string current_exception_diagnostic_information();
|
||||
|
||||
template <class Encoder, class E>
|
||||
void serialize_diagnostic_information_to( Encoder & enc, E const & e );
|
||||
|
||||
template <class Encoder>
|
||||
void serialize_current_exception_diagnostic_information_to( Encoder & enc );
|
||||
}
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
Reference: <<diagnostic_information>> | <<diagnostic_information_what>> | <<current_exception_diagnostic_information>>
|
||||
Reference: <<diagnostic_information>> | <<diagnostic_information_what>> | <<current_exception_diagnostic_information>> | <<serialize_diagnostic_information_to>> | <<serialize_current_exception_diagnostic_information_to>>
|
||||
====
|
||||
|
||||
[[synopsis-current_exception_cast]]
|
||||
@@ -904,6 +1068,67 @@ Reference: <<errinfo_type_info_name>>
|
||||
This header includes all Boost Exception headers except `<<synopsis-exception_ptr,boost/exception_ptr.hpp>>` (unless BOOST_NO_EXCEPTIONS is defined.)
|
||||
====
|
||||
|
||||
[[synopsis-serialization]]
|
||||
=== Serialization
|
||||
|
||||
[[synopsis-boost_json_encoder]]
|
||||
==== `boost_json_encoder.hpp`
|
||||
|
||||
====
|
||||
.#include <boost/exception/serialization/boost_json_encoder.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
struct boost_json_encoder
|
||||
{
|
||||
boost::json::value & v_;
|
||||
|
||||
// Enabled if x is assignable to boost::json::value, or
|
||||
// if tag_invoke is defined for boost::json::value_from_tag.
|
||||
template <class T>
|
||||
friend void output( boost_json_encoder &, T const & x );
|
||||
|
||||
template <class T>
|
||||
friend void output_at( boost_json_encoder &, T const &, char const * name );
|
||||
};
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
Reference: <<boost_json_encoder>>
|
||||
====
|
||||
|
||||
[[synopsis-nlohmann_json_encoder]]
|
||||
==== `nlohmann_json_encoder.hpp`
|
||||
|
||||
====
|
||||
.#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
template <class Json>
|
||||
struct nlohmann_json_encoder
|
||||
{
|
||||
Json & j_;
|
||||
|
||||
// Enabled if to_json is available for Json and T.
|
||||
template <class T>
|
||||
friend void output( nlohmann_json_encoder &, T const & x );
|
||||
|
||||
template <class T>
|
||||
friend void output_at( nlohmann_json_encoder &, T const &, char const * name );
|
||||
};
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
[.text-right]
|
||||
Reference: <<nlohmann_json_encoder>>
|
||||
====
|
||||
|
||||
[[reference]]
|
||||
== Reference
|
||||
|
||||
@@ -919,60 +1144,36 @@ endif::[]
|
||||
[[types]]
|
||||
=== Types
|
||||
|
||||
[[exception]]
|
||||
==== `exception`
|
||||
[[boost_json_encoder]]
|
||||
==== `boost_json_encoder`
|
||||
|
||||
.#include <boost/exception/exception.hpp>
|
||||
.#include <boost/exception/serialization/boost_json_encoder.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
struct boost_json_encoder
|
||||
{
|
||||
class exception
|
||||
{
|
||||
protected:
|
||||
boost::json::value & v_;
|
||||
|
||||
exception();
|
||||
exception( exception const & x );
|
||||
~exception();
|
||||
};
|
||||
}
|
||||
// Enabled if x is assignable to boost::json::value, or
|
||||
// if tag_invoke is defined for boost::json::value_from_tag.
|
||||
template <class T>
|
||||
friend void output( boost_json_encoder &, T const & x );
|
||||
|
||||
template <class T>
|
||||
friend void output_at( boost_json_encoder &, T const &, char const * name );
|
||||
};
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
Class `boost::exception` is designed to be used as a universal base for user-defined exception types.
|
||||
The `boost_json_encoder` type serializes objects to JSON format using https://www.boost.org/doc/libs/release/libs/json/[Boost.JSON]. The `output` function is enabled for:
|
||||
|
||||
An object of any type deriving from `boost::exception` can store data of arbitrary types, using the `<<error_info,error_info>>` wrapper and `<<exception_operator_shl,operator<<>>`.
|
||||
* Types directly assignable to `boost::json::value`
|
||||
* Types for which a `tag_invoke` overload for `value_from_tag` can be found via ADL
|
||||
|
||||
To retrieve data from a `boost::exception` object, use the `<<get_error_info,get_error_info>>` function template.
|
||||
|
||||
[[exception_constructors]]
|
||||
===== `exception::exception`
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
exception();
|
||||
exception( exception const & x );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
--
|
||||
* Default constructor: initializes an empty `boost::exception` object.
|
||||
* Copy constructor: initializes a `boost::exception` object which shares with x the pointers to all currently stored data. Subsequently, data can be added to or retrieved from both exception objects interchangeably, however doing so concurrently from multiple threads is undefined behavior.
|
||||
--
|
||||
|
||||
Throws: :: Nothing.
|
||||
|
||||
[[exception_destructor]]
|
||||
===== `exception::~exception`
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
~exception();
|
||||
----
|
||||
|
||||
Effects: :: Releases all resources associated with the `boost::exception` object.
|
||||
|
||||
Throws: :: Nothing.
|
||||
See <<tutorial_serialization>>.
|
||||
|
||||
'''
|
||||
|
||||
@@ -1288,6 +1489,63 @@ This type is designed to be used as a standard `<<error_info,error_info>>` insta
|
||||
|
||||
'''
|
||||
|
||||
[[exception]]
|
||||
==== `exception`
|
||||
|
||||
.#include <boost/exception/exception.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
class exception
|
||||
{
|
||||
protected:
|
||||
|
||||
exception();
|
||||
exception( exception const & x );
|
||||
~exception();
|
||||
};
|
||||
}
|
||||
----
|
||||
|
||||
Class `boost::exception` is designed to be used as a universal base for user-defined exception types.
|
||||
|
||||
An object of any type deriving from `boost::exception` can store data of arbitrary types, using the `<<error_info,error_info>>` wrapper and `<<exception_operator_shl,operator<<>>`.
|
||||
|
||||
To retrieve data from a `boost::exception` object, use the `<<get_error_info,get_error_info>>` function template.
|
||||
|
||||
[[exception_constructors]]
|
||||
===== `exception::exception`
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
exception();
|
||||
exception( exception const & x );
|
||||
----
|
||||
|
||||
Effects: ::
|
||||
+
|
||||
--
|
||||
* Default constructor: initializes an empty `boost::exception` object.
|
||||
* Copy constructor: initializes a `boost::exception` object which shares with x the pointers to all currently stored data. Subsequently, data can be added to or retrieved from both exception objects interchangeably, however doing so concurrently from multiple threads is undefined behavior.
|
||||
--
|
||||
|
||||
Throws: :: Nothing.
|
||||
|
||||
[[exception_destructor]]
|
||||
===== `exception::~exception`
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
~exception();
|
||||
----
|
||||
|
||||
Effects: :: Releases all resources associated with the `boost::exception` object.
|
||||
|
||||
Throws: :: Nothing.
|
||||
|
||||
'''
|
||||
|
||||
[[exception_ptr]]
|
||||
==== `exception_ptr`
|
||||
|
||||
@@ -1321,6 +1579,34 @@ Nesting of exceptions: :: An `exception_ptr` can be added as `<<error_info,error
|
||||
|
||||
'''
|
||||
|
||||
[[nlohmann_json_encoder]]
|
||||
==== `nlohmann_json_encoder`
|
||||
|
||||
.#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
template <class Json>
|
||||
struct nlohmann_json_encoder
|
||||
{
|
||||
Json & j_;
|
||||
|
||||
// Enabled if to_json is available for Json and T.
|
||||
template <class T>
|
||||
friend void output( nlohmann_json_encoder &, T const & x );
|
||||
|
||||
template <class T>
|
||||
friend void output_at( nlohmann_json_encoder &, T const &, char const * name );
|
||||
};
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
The `nlohmann_json_encoder` type serializes objects to JSON format based on ADL calls to `to_json`. This is compatible with https://github.com/nlohmann/json[nlohmann/json]. See <<tutorial_serialization>>.
|
||||
|
||||
'''
|
||||
|
||||
[[original_exception_type]]
|
||||
==== `original_exception_type`
|
||||
|
||||
@@ -1720,6 +2006,74 @@ Throws: :: The exception to which ep refers.
|
||||
|
||||
'''
|
||||
|
||||
[[serialize]]
|
||||
==== `serialize`
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost { namespace exception_serialization {
|
||||
|
||||
template <class Handle, class E>
|
||||
void serialize( Handle & h, E const & x, char const * name );
|
||||
|
||||
} }
|
||||
----
|
||||
|
||||
The `serialize` function template is a user-defined customization point. If provided, it is called by the serialization system to output objects to an encoder; see <<custom-encoders>>.
|
||||
|
||||
'''
|
||||
|
||||
[[serialize_current_exception_diagnostic_information_to]]
|
||||
==== `serialize_current_exception_diagnostic_information_to`
|
||||
|
||||
.#include <boost/exception/diagnostic_information.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
template <class Encoder>
|
||||
void serialize_current_exception_diagnostic_information_to( Encoder & enc );
|
||||
}
|
||||
----
|
||||
|
||||
Requirements: :: This function must not be called outside of a catch block.
|
||||
|
||||
Effects: :: Serializes diagnostic information for the current exception to the encoder `enc`. Equivalent to calling `<<serialize_diagnostic_information_to,serialize_diagnostic_information_to>>` with the current exception object.
|
||||
|
||||
See <<tutorial_serialization>>.
|
||||
|
||||
'''
|
||||
|
||||
[[serialize_diagnostic_information_to]]
|
||||
==== `serialize_diagnostic_information_to`
|
||||
|
||||
.#include <boost/exception/diagnostic_information.hpp>
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost
|
||||
{
|
||||
template <class Encoder, class E>
|
||||
void serialize_diagnostic_information_to( Encoder & enc, E const & e );
|
||||
}
|
||||
----
|
||||
|
||||
Serializes diagnostic information for the exception `e` to the encoder `enc`.
|
||||
|
||||
Requirements: :: E must be convertible to either `boost::<<exception,exception>> const &` or `std::exception const &`.
|
||||
|
||||
Effects: :: Outputs diagnostic information about the exception to the encoder, including:
|
||||
+
|
||||
--
|
||||
* Throw location (file, line, function) if available
|
||||
* Dynamic exception type (if RTTI is enabled)
|
||||
* `std::exception::what()` if available
|
||||
* All `<<error_info,error_info>>` objects stored in the exception
|
||||
--
|
||||
|
||||
See <<tutorial_serialization>>.
|
||||
|
||||
'''
|
||||
|
||||
[[throw_exception]]
|
||||
==== `throw_exception`
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
//Copyright (c) 2006-2026 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
//Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_EXCEPTION_DETAIL_ENCODER_HPP_INCLUDED
|
||||
#define BOOST_EXCEPTION_DETAIL_ENCODER_HPP_INCLUDED
|
||||
|
||||
#include <boost/exception/detail/type_info.hpp>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
boost
|
||||
{
|
||||
template <class Tag, class T> class error_info;
|
||||
|
||||
namespace
|
||||
exception_serialization
|
||||
{
|
||||
struct encoder_adl {};
|
||||
}
|
||||
|
||||
namespace
|
||||
exception_detail
|
||||
{
|
||||
template <class T>
|
||||
struct first_arg;
|
||||
|
||||
template <class C, class R, class A1, class... A>
|
||||
struct
|
||||
first_arg<R(C::*)(A1, A...)>
|
||||
{
|
||||
using type = A1;
|
||||
};
|
||||
|
||||
template <class C, class R, class A1, class... A>
|
||||
struct
|
||||
first_arg<R(C::*)(A1, A...) const>
|
||||
{
|
||||
using type = A1;
|
||||
};
|
||||
|
||||
class
|
||||
encoder:
|
||||
exception_serialization::encoder_adl
|
||||
{
|
||||
encoder(encoder const &) = delete;
|
||||
encoder & operator=(encoder const &) = delete;
|
||||
|
||||
core::typeinfo const * type_;
|
||||
void * e_;
|
||||
|
||||
bool
|
||||
dispatch_()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class F1, class... Fn>
|
||||
bool
|
||||
dispatch_(F1 && f1, Fn && ... fn)
|
||||
{
|
||||
using encoder_type = typename std::decay<typename first_arg<decltype(&std::decay<F1>::type::operator())>::type>::type;
|
||||
if (encoder_type * e = get<encoder_type>())
|
||||
{
|
||||
std::forward<F1>(f1)(*e);
|
||||
return true;
|
||||
}
|
||||
return dispatch_(std::forward<Fn>(fn)...);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
template <class Encoder>
|
||||
explicit
|
||||
encoder(Encoder * e) noexcept:
|
||||
type_(&BOOST_CORE_TYPEID(Encoder)),
|
||||
e_(e)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
template <class Encoder>
|
||||
Encoder *
|
||||
get() noexcept
|
||||
{
|
||||
return *type_ == BOOST_CORE_TYPEID(Encoder) ? static_cast<Encoder *>(e_) : nullptr;
|
||||
}
|
||||
|
||||
template <class... Fn>
|
||||
bool
|
||||
dispatch(Fn && ... fn)
|
||||
{
|
||||
return dispatch_(std::forward<Fn>(fn)...);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Encoder>
|
||||
struct
|
||||
encoder_adaptor:
|
||||
encoder
|
||||
{
|
||||
explicit
|
||||
encoder_adaptor(Encoder & e) noexcept:
|
||||
encoder(&e)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -13,6 +13,8 @@
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
namespace boost { namespace exception_detail { class encoder; } }
|
||||
|
||||
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
|
||||
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
|
||||
#pragma GCC system_header
|
||||
@@ -38,6 +40,7 @@ boost
|
||||
|
||||
virtual std::string name_value_string() const = 0;
|
||||
virtual error_info_base * clone() const = 0;
|
||||
virtual void serialize_to(encoder &) const = 0;
|
||||
|
||||
virtual
|
||||
~error_info_base() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
@@ -97,6 +100,7 @@ boost
|
||||
error_info & operator=( error_info && x );
|
||||
#endif
|
||||
std::string name_value_string() const;
|
||||
void serialize_to(exception_detail::encoder &) const;
|
||||
value_type v_;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -21,4 +21,4 @@ BOOST_PRAGMA_MESSAGE("C++03 support was deprecated in Boost.Exception 1.85 and w
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,17 @@
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <ostream>
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
|
||||
#ifndef BOOST_EXCEPTION_PRETTY_FUNCTION
|
||||
# if defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
|
||||
# define BOOST_EXCEPTION_PRETTY_FUNCTION __FUNCSIG__
|
||||
# else
|
||||
# define BOOST_EXCEPTION_PRETTY_FUNCTION __PRETTY_FUNCTION__
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
|
||||
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
|
||||
@@ -73,6 +83,206 @@ boost
|
||||
return a.type_!=b.type_ && strcmp(a.type_->name(), b.type_->name()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2, int I, bool = (S1 >= S2)>
|
||||
struct
|
||||
cpp11_prefix
|
||||
{
|
||||
BOOST_FORCEINLINE static constexpr
|
||||
bool
|
||||
check(char const (&)[S1], char const (&)[S2]) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2, int I>
|
||||
struct
|
||||
cpp11_prefix<S1, S2, I, true>
|
||||
{
|
||||
BOOST_FORCEINLINE static constexpr
|
||||
bool
|
||||
check(char const (&str)[S1], char const (&prefix)[S2]) noexcept
|
||||
{
|
||||
return str[I] == prefix[I] && cpp11_prefix<S1, S2, I - 1>::check(str, prefix);
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2>
|
||||
struct
|
||||
cpp11_prefix<S1, S2, 0, true>
|
||||
{
|
||||
BOOST_FORCEINLINE static constexpr
|
||||
bool
|
||||
check(char const (&str)[S1], char const (&prefix)[S2]) noexcept
|
||||
{
|
||||
return str[0] == prefix[0];
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2>
|
||||
BOOST_FORCEINLINE constexpr
|
||||
int
|
||||
check_prefix(char const (&str)[S1], char const (&prefix)[S2]) noexcept
|
||||
{
|
||||
return cpp11_prefix<S1, S2, S2 - 2>::check(str, prefix) ? S2 - 1 : 0;
|
||||
}
|
||||
|
||||
template <int S1, int S2, int I1, int I2, bool = (S1 >= S2)>
|
||||
struct
|
||||
cpp11_suffix
|
||||
{
|
||||
BOOST_FORCEINLINE static constexpr
|
||||
bool
|
||||
check(char const (&)[S1], char const (&)[S2]) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2, int I1, int I2>
|
||||
struct
|
||||
cpp11_suffix<S1, S2, I1, I2, true>
|
||||
{
|
||||
BOOST_FORCEINLINE static constexpr
|
||||
bool
|
||||
check(char const (&str)[S1], char const (&suffix)[S2]) noexcept
|
||||
{
|
||||
return str[I1] == suffix[I2] && cpp11_suffix<S1, S2, I1 - 1, I2 - 1>::check(str, suffix);
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2, int I1>
|
||||
struct
|
||||
cpp11_suffix<S1, S2, I1, 0, true>
|
||||
{
|
||||
BOOST_FORCEINLINE static constexpr
|
||||
bool
|
||||
check(char const (&str)[S1], char const (&suffix)[S2]) noexcept
|
||||
{
|
||||
return str[I1] == suffix[0];
|
||||
}
|
||||
};
|
||||
|
||||
template <int S1, int S2>
|
||||
BOOST_FORCEINLINE constexpr
|
||||
int
|
||||
check_suffix(char const (&str)[S1], char const (&suffix)[S2]) noexcept
|
||||
{
|
||||
return cpp11_suffix<S1, S2, S1 - 2, S2 - 2>::check(str, suffix) ? S1 - S2 : 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
n
|
||||
{
|
||||
struct
|
||||
r
|
||||
{
|
||||
char const * name_not_zero_terminated_at_length;
|
||||
std::size_t length;
|
||||
};
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define BOOST_EXCEPTION_CDECL __cdecl
|
||||
#else
|
||||
# define BOOST_EXCEPTION_CDECL
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
BOOST_FORCEINLINE
|
||||
r
|
||||
BOOST_EXCEPTION_CDECL
|
||||
p()
|
||||
{
|
||||
#define BOOST_EXCEPTION_P(P) (sizeof(char[1 + exception_detail::check_prefix(BOOST_EXCEPTION_PRETTY_FUNCTION, P)]) - 1)
|
||||
// clang style:
|
||||
std::size_t const p01 = BOOST_EXCEPTION_P("r boost::n::p() [T = ");
|
||||
std::size_t const p02 = BOOST_EXCEPTION_P("r __cdecl boost::n::p(void) [T = ");
|
||||
// old clang style:
|
||||
std::size_t const p03 = BOOST_EXCEPTION_P("boost::n::r boost::n::p() [T = ");
|
||||
std::size_t const p04 = BOOST_EXCEPTION_P("boost::n::r __cdecl boost::n::p(void) [T = ");
|
||||
// gcc style:
|
||||
std::size_t const p05 = BOOST_EXCEPTION_P("boost::n::r boost::n::p() [with T = ");
|
||||
std::size_t const p06 = BOOST_EXCEPTION_P("boost::n::r __cdecl boost::n::p() [with T = ");
|
||||
// msvc style, struct:
|
||||
std::size_t const p07 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<struct ");
|
||||
// msvc style, class:
|
||||
std::size_t const p08 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<class ");
|
||||
// msvc style, enum:
|
||||
std::size_t const p09 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<enum ");
|
||||
// msvc style, built-in type:
|
||||
std::size_t const p10 = BOOST_EXCEPTION_P("struct boost::n::r __cdecl boost::n::p<");
|
||||
#undef BOOST_EXCEPTION_P
|
||||
|
||||
#define BOOST_EXCEPTION_S(S) (sizeof(char[1 + exception_detail::check_suffix(BOOST_EXCEPTION_PRETTY_FUNCTION, S)]) - 1)
|
||||
// clang/gcc style:
|
||||
std::size_t const s01 = BOOST_EXCEPTION_S("]");
|
||||
// msvc style:
|
||||
std::size_t const s02 = BOOST_EXCEPTION_S(">(void)");
|
||||
#undef BOOST_EXCEPTION_S
|
||||
|
||||
char static_assert_unrecognized_pretty_function_format_please_file_github_issue[sizeof(
|
||||
char[
|
||||
(s01 && (1 == (!!p01 + !!p02 + !!p03 + !!p04 + !!p05 + !!p06)))
|
||||
||
|
||||
(s02 && (1 == (!!p07 + !!p08 + !!p09)))
|
||||
||
|
||||
(s02 && !!p10)
|
||||
]
|
||||
) * 2 - 1];
|
||||
(void) static_assert_unrecognized_pretty_function_format_please_file_github_issue;
|
||||
|
||||
if( std::size_t const p = sizeof(char[1 + !!s01 * (p01 + p02 + p03 + p04 + p05 + p06)]) - 1 )
|
||||
return { BOOST_EXCEPTION_PRETTY_FUNCTION + p, s01 - p };
|
||||
|
||||
if( std::size_t const p = sizeof(char[1 + !!s02 * (p07 + p08 + p09)]) - 1 )
|
||||
return { BOOST_EXCEPTION_PRETTY_FUNCTION + p, s02 - p };
|
||||
|
||||
std::size_t const p = sizeof(char[1 + !!s02 * p10]) - 1;
|
||||
return { BOOST_EXCEPTION_PRETTY_FUNCTION + p, s02 - p };
|
||||
}
|
||||
|
||||
#undef BOOST_EXCEPTION_CDECL
|
||||
}
|
||||
|
||||
namespace
|
||||
exception_detail
|
||||
{
|
||||
struct
|
||||
pretty_type_name
|
||||
{
|
||||
char const * name_not_zero_terminated_at_length;
|
||||
std::size_t length;
|
||||
|
||||
template <class CharT, class Traits>
|
||||
friend
|
||||
std::basic_ostream<CharT, Traits> &
|
||||
operator<<(std::basic_ostream<CharT, Traits> & os, pretty_type_name const & x)
|
||||
{
|
||||
return os.write(x.name_not_zero_terminated_at_length, x.length);
|
||||
}
|
||||
|
||||
template <std::size_t S>
|
||||
friend
|
||||
char *
|
||||
to_zstr(char (&zstr)[S], pretty_type_name const & x) noexcept
|
||||
{
|
||||
std::size_t n = x.length < S - 1 ? x.length : S - 1;
|
||||
std::memcpy(zstr, x.name_not_zero_terminated_at_length, n);
|
||||
zstr[n] = 0;
|
||||
return zstr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
pretty_type_name
|
||||
get_pretty_tag_type_name()
|
||||
{
|
||||
n::r parsed = n::p<T>();
|
||||
return { parsed.name_not_zero_terminated_at_length, parsed.length };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -205,6 +205,65 @@ boost
|
||||
#endif
|
||||
return w;
|
||||
}
|
||||
|
||||
namespace
|
||||
exception_detail
|
||||
{
|
||||
template <class Encoder>
|
||||
void
|
||||
serialize_diagnostic_information_to_impl_( boost::exception const * be, std::exception const * se, Encoder & e )
|
||||
{
|
||||
if( !be && !se )
|
||||
return;
|
||||
#ifndef BOOST_NO_RTTI
|
||||
if( !be )
|
||||
be=dynamic_cast<boost::exception const *>(se);
|
||||
if( !se )
|
||||
se=dynamic_cast<std::exception const *>(be);
|
||||
#endif
|
||||
if( be )
|
||||
{
|
||||
if( char const * const * f=get_error_info<throw_file>(*be) )
|
||||
output_at(e, *f, "throw_file");
|
||||
if( int const * l=get_error_info<throw_line>(*be) )
|
||||
output_at(e, *l, "throw_line");
|
||||
if( char const * const * fn=get_error_info<throw_function>(*be) )
|
||||
output_at(e, *fn, "throw_function");
|
||||
}
|
||||
#ifndef BOOST_NO_RTTI
|
||||
if( be || se )
|
||||
output_at(e, core::demangle((be?(BOOST_EXCEPTION_DYNAMIC_TYPEID(*be)):(BOOST_EXCEPTION_DYNAMIC_TYPEID(*se))).type_->name()).c_str(), "dynamic_exception_type");
|
||||
#endif
|
||||
if( se )
|
||||
if( char const * wh = se->what() )
|
||||
output_at(e, wh, "std::exception::what");
|
||||
if( be )
|
||||
if( error_info_container * c = be->data_.get() )
|
||||
{
|
||||
encoder_adaptor<Encoder> ea(e);
|
||||
c->serialize_to(ea);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Encoder>
|
||||
void
|
||||
serialize_diagnostic_information_to( T const & e, Encoder & enc )
|
||||
{
|
||||
exception_detail::serialize_diagnostic_information_to_impl_(exception_detail::get_boost_exception(&e),exception_detail::get_std_exception(&e),enc);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
template <class Encoder>
|
||||
void
|
||||
serialize_current_exception_diagnostic_information_to( Encoder & e )
|
||||
{
|
||||
boost::exception const * be=current_exception_cast<boost::exception const>();
|
||||
std::exception const * se=current_exception_cast<std::exception const>();
|
||||
if( be || se )
|
||||
exception_detail::serialize_diagnostic_information_to_impl_(be,se,e);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include <boost/exception/to_string_stub.hpp>
|
||||
#include <boost/exception/detail/error_info_impl.hpp>
|
||||
#include <boost/exception/detail/shared_ptr.hpp>
|
||||
#include <boost/exception/detail/encoder.hpp>
|
||||
#include <map>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
|
||||
#if defined(__GNUC__) && __GNUC__*100+__GNUC_MINOR__>301
|
||||
@@ -28,6 +30,17 @@
|
||||
namespace
|
||||
boost
|
||||
{
|
||||
namespace
|
||||
exception_serialization
|
||||
{
|
||||
// Stub
|
||||
template <class Encoder, class T, class... Deprioritize>
|
||||
typename std::enable_if<std::is_base_of<exception_detail::encoder, Encoder>::value>::type
|
||||
serialize(Encoder &, T const &, char const *, Deprioritize...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
template <class Tag,class T>
|
||||
inline
|
||||
std::string
|
||||
@@ -53,6 +66,17 @@ boost
|
||||
return to_string_stub(*this);
|
||||
}
|
||||
|
||||
template <class Tag,class T>
|
||||
inline
|
||||
void
|
||||
error_info<Tag,T>::
|
||||
serialize_to(exception_detail::encoder & e) const
|
||||
{
|
||||
char buf[256];
|
||||
using namespace exception_serialization;
|
||||
serialize(e, value(), to_zstr(buf, exception_detail::get_pretty_tag_type_name<Tag>()));
|
||||
}
|
||||
|
||||
namespace
|
||||
exception_detail
|
||||
{
|
||||
@@ -108,6 +132,16 @@ boost
|
||||
return diagnostic_info_str_.c_str();
|
||||
}
|
||||
|
||||
void
|
||||
serialize_to( encoder & e ) const
|
||||
{
|
||||
for( error_info_map::const_iterator i=info_.begin(),end=info_.end(); i!=end; ++i )
|
||||
{
|
||||
error_info_base const & x = *i->second;
|
||||
x.serialize_to(e);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
friend class boost::exception;
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
//Copyright (c) 2006-2026 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
//Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_EXCEPTION_SERIALIZATION_BOOST_JSON_ENCODER_HPP_INCLUDED
|
||||
#define BOOST_EXCEPTION_SERIALIZATION_BOOST_JSON_ENCODER_HPP_INCLUDED
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
boost
|
||||
{
|
||||
namespace
|
||||
json
|
||||
{
|
||||
class value;
|
||||
struct value_from_tag;
|
||||
}
|
||||
|
||||
namespace
|
||||
exception_serialization
|
||||
{
|
||||
// Baast.JSON does not provide ADL interface for serializing user-defined types.
|
||||
// This limits the functionality of boost_json_encoder to only types that provide tag_invoke.
|
||||
template <class Value = boost::json::value, class ValueFromTag = boost::json::value_from_tag>
|
||||
struct
|
||||
boost_json_encoder_
|
||||
{
|
||||
Value & v_;
|
||||
|
||||
template <class T>
|
||||
friend
|
||||
auto
|
||||
output(boost_json_encoder_ & e, T const & x) -> decltype(std::declval<Value &>() = x, void())
|
||||
{
|
||||
e.v_ = x;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
friend
|
||||
auto
|
||||
output(boost_json_encoder_ & e, T const & x) -> decltype(tag_invoke(std::declval<ValueFromTag>(), std::declval<Value &>(), x), void())
|
||||
{
|
||||
tag_invoke(ValueFromTag{}, e.v_, x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
friend
|
||||
void
|
||||
output_at(boost_json_encoder_ & e, T const & x, char const * name)
|
||||
{
|
||||
if( e.v_.is_null() )
|
||||
e.v_.emplace_object();
|
||||
boost_json_encoder_ nested{e.v_.as_object()[name]};
|
||||
output(nested, x);
|
||||
}
|
||||
};
|
||||
|
||||
using boost_json_encoder = boost_json_encoder_<>;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
//Copyright (c) 2006-2026 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
//Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_EXCEPTION_SERIALIZATION_NLOHMANN_JSON_ENCODER_HPP_INCLUDED
|
||||
#define BOOST_EXCEPTION_SERIALIZATION_NLOHMANN_JSON_ENCODER_HPP_INCLUDED
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace
|
||||
boost
|
||||
{
|
||||
namespace
|
||||
exception_serialization
|
||||
{
|
||||
template <class Json>
|
||||
struct
|
||||
nlohmann_json_encoder
|
||||
{
|
||||
Json & j_;
|
||||
|
||||
template <class T>
|
||||
friend
|
||||
auto
|
||||
output(nlohmann_json_encoder & e, T const & x) -> decltype(to_json(std::declval<Json &>(), x))
|
||||
{
|
||||
to_json(e.j_, x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
friend
|
||||
void
|
||||
output_at(nlohmann_json_encoder & e, T const & x, char const * name)
|
||||
{
|
||||
nlohmann_json_encoder nested{e.j_[name]};
|
||||
output(nested, x);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
|
||||
Copyright 2018-2026 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
This program downloads the nlohmann/json single header distribution.
|
||||
|
||||
Usage:
|
||||
|
||||
python3 download_nlohmann_json.py
|
||||
|
||||
"""
|
||||
|
||||
import urllib.request
|
||||
import os
|
||||
|
||||
url = "https://github.com/nlohmann/json/releases/download/v3.11.3/json.hpp"
|
||||
output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "test", "nlohmann")
|
||||
output_file = os.path.join(output_dir, "json.hpp")
|
||||
|
||||
def _main():
|
||||
if os.path.exists(output_file):
|
||||
print(f"{output_file} already exists, skipping download")
|
||||
return
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
print(f"Downloading {url}...")
|
||||
urllib.request.urlretrieve(url, output_file)
|
||||
print(f"Saved to {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
_main()
|
||||
+25
-22
@@ -11,10 +11,11 @@ project : requirements <library>/boost/exception//boost_exception ;
|
||||
|
||||
#to_string
|
||||
|
||||
run is_output_streamable_test.cpp ;
|
||||
run has_to_string_test.cpp ;
|
||||
run to_string_test.cpp ;
|
||||
run is_output_streamable_test.cpp ;
|
||||
run to_string_stub_test.cpp ;
|
||||
run to_string_test.cpp ;
|
||||
|
||||
compile-fail to_string_fail.cpp ;
|
||||
|
||||
#exception
|
||||
@@ -23,47 +24,42 @@ run 1-throw_exception_test.cpp : : : <exception-handling>on ;
|
||||
run 2-throw_exception_no_exceptions_test.cpp : : : <exception-handling>off ;
|
||||
run 3-throw_exception_no_integration_test.cpp : : : <exception-handling>on ;
|
||||
run 4-throw_exception_no_both_test.cpp : : : <exception-handling>off ;
|
||||
run boost_json_test.cpp /boost/json//boost_json : : : <exception-handling>on ;
|
||||
run cloning_test.cpp : : : <exception-handling>on ;
|
||||
run copy_exception_test.cpp ../../thread/src/tss_null.cpp /boost/thread//boost_thread : : : <threading>multi <exception-handling>on ;
|
||||
run copy_exception_no_exceptions_test.cpp : : : <exception-handling>off <rtti>on ;
|
||||
run unknown_exception_test.cpp : : : <exception-handling>on ;
|
||||
run exception_test.cpp : : : <exception-handling>on ;
|
||||
run copy_exception_test.cpp ../../thread/src/tss_null.cpp /boost/thread//boost_thread : : : <threading>multi <exception-handling>on ;
|
||||
run current_exception_cast_test.cpp : : : <exception-handling>on ;
|
||||
run diagnostic_information_test.cpp : : : <exception-handling>on ;
|
||||
run enable_error_info_test.cpp helper1.cpp : : : <exception-handling>on ;
|
||||
run throw_exception_test.cpp helper2.cpp : : : <exception-handling>on ;
|
||||
run errno_test.cpp : : : <exception-handling>on ;
|
||||
run error_info_basic_test.cpp : : : <exception-handling>on ;
|
||||
run error_info_lv_test.cpp : : : <exception-handling>on ;
|
||||
run error_info_lv_const_test.cpp : : : <exception-handling>on ;
|
||||
run error_info_rv_test.cpp : : : <exception-handling>on ;
|
||||
run error_info_lv_test.cpp : : : <exception-handling>on ;
|
||||
run error_info_rv_const_test.cpp : : : <exception-handling>on ;
|
||||
run diagnostic_information_test.cpp : : : <exception-handling>on ;
|
||||
run refcount_ptr_test.cpp ;
|
||||
run current_exception_cast_test.cpp : : : <exception-handling>on ;
|
||||
run no_exceptions_test.cpp : : : <exception-handling>off ;
|
||||
run error_info_rv_test.cpp : : : <exception-handling>on ;
|
||||
run errinfos_test.cpp : : : <exception-handling>on ;
|
||||
run exception_ptr_test.cpp/<define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR ../../thread/src/tss_null.cpp /boost/exception//boost_exception /boost/thread//boost_thread : : : <threading>multi <exception-handling>on : non_intrusive_exception_ptr_test ;
|
||||
run exception_ptr_test.cpp ../../thread/src/tss_null.cpp /boost/thread//boost_thread : : : <threading>multi <exception-handling>on ;
|
||||
run exception_ptr_test.cpp/<define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR ../../thread/src/tss_null.cpp /boost/exception//boost_exception /boost/thread//boost_thread : : : <threading>multi <exception-handling>on : non_intrusive_exception_ptr_test ;
|
||||
run exception_ptr_test2.cpp ;
|
||||
run exception_test.cpp : : : <exception-handling>on ;
|
||||
run nlohmann_json_test.cpp : : : <exception-handling>on <toolset>clang,<target-os>linux,<cxxstd>2b:<build>no <toolset>clang,<target-os>linux,<cxxstd>23:<build>no ;
|
||||
run no_exceptions_test.cpp : : : <exception-handling>off ;
|
||||
run refcount_ptr_test.cpp ;
|
||||
run throw_exception_test.cpp helper2.cpp : : : <exception-handling>on ;
|
||||
run unknown_exception_test.cpp : : : <exception-handling>on ;
|
||||
|
||||
lib visibility_test_lib : visibility_test_lib.cpp : <visibility>hidden <exception-handling>on ;
|
||||
run visibility_test.cpp visibility_test_lib/<link>shared : : : <visibility>hidden <exception-handling>on ;
|
||||
|
||||
compile-fail error_info_const_fail.cpp ;
|
||||
compile-fail exception_fail.cpp ;
|
||||
compile-fail throw_exception_fail.cpp ;
|
||||
compile-fail error_info_const_fail.cpp ;
|
||||
|
||||
#headers
|
||||
|
||||
compile exception_ptr_hpp_test.cpp ;
|
||||
compile diagnostic_information_hpp_test.cpp ;
|
||||
compile error_info_hpp_test.cpp ;
|
||||
compile get_error_info_hpp_test.cpp ;
|
||||
compile info_hpp_test.cpp ;
|
||||
compile info_tuple_hpp_test.cpp ;
|
||||
compile to_string_hpp_test.cpp ;
|
||||
compile to_string_stub_hpp_test.cpp ;
|
||||
compile all_hpp_test.cpp ;
|
||||
compile current_exception_cast_hpp_test.cpp ;
|
||||
compile diagnostic_information_hpp_test.cpp ;
|
||||
compile errinfo_api_function_hpp_test.cpp ;
|
||||
compile errinfo_at_line_hpp_test.cpp ;
|
||||
compile errinfo_errno_hpp_test.cpp ;
|
||||
@@ -72,3 +68,10 @@ compile errinfo_file_name_hpp_test.cpp ;
|
||||
compile errinfo_file_open_mode_hpp_test.cpp ;
|
||||
compile errinfo_nested_exception_hpp_test.cpp ;
|
||||
compile errinfo_type_info_name_hpp_test.cpp ;
|
||||
compile error_info_hpp_test.cpp ;
|
||||
compile exception_ptr_hpp_test.cpp ;
|
||||
compile get_error_info_hpp_test.cpp ;
|
||||
compile info_hpp_test.cpp ;
|
||||
compile info_tuple_hpp_test.cpp ;
|
||||
compile to_string_hpp_test.cpp ;
|
||||
compile to_string_stub_hpp_test.cpp ;
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
//Copyright (c) 2006-2026 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
//Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined( BOOST_NO_EXCEPTIONS )
|
||||
# error This program requires exception handling.
|
||||
#endif
|
||||
|
||||
#include <boost/exception/diagnostic_information.hpp>
|
||||
#include <boost/exception/serialization/boost_json_encoder.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
using output_encoder = boost::exception_serialization::boost_json_encoder;
|
||||
|
||||
namespace
|
||||
boost
|
||||
{
|
||||
namespace
|
||||
exception_serialization
|
||||
{
|
||||
template <class Handle, class E>
|
||||
void
|
||||
serialize(Handle & h, E const & e, char const * name)
|
||||
{
|
||||
h.dispatch(
|
||||
[&](boost_json_encoder & enc) { output_at(enc, e, name); } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef boost::error_info<struct my_error1_, int> my_error1;
|
||||
typedef boost::error_info<struct my_error2_, std::string> my_error2;
|
||||
|
||||
struct
|
||||
my_info
|
||||
{
|
||||
int code;
|
||||
char const * message;
|
||||
|
||||
friend
|
||||
void
|
||||
tag_invoke(boost::json::value_from_tag, boost::json::value & v, my_info const & e)
|
||||
{
|
||||
v = {
|
||||
{"code", e.code},
|
||||
{"message", e.message}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::error_info<struct my_error3_, my_info> my_error3;
|
||||
|
||||
struct
|
||||
test_exception:
|
||||
virtual boost::exception,
|
||||
virtual std::exception
|
||||
{
|
||||
char const *
|
||||
what() const noexcept override
|
||||
{
|
||||
return "test_exception::what";
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
check_output(boost::json::value const & j, bool has_source_location)
|
||||
{
|
||||
auto const & obj = j.as_object();
|
||||
if( has_source_location )
|
||||
{
|
||||
BOOST_TEST(obj.contains("throw_file"));
|
||||
BOOST_TEST(obj.contains("throw_line"));
|
||||
BOOST_TEST(obj.contains("throw_function"));
|
||||
}
|
||||
#ifndef BOOST_NO_RTTI
|
||||
BOOST_TEST(obj.contains("dynamic_exception_type"));
|
||||
#endif
|
||||
BOOST_TEST(obj.contains("std::exception::what"));
|
||||
BOOST_TEST_EQ(obj.at("std::exception::what").as_string(), "test_exception::what");
|
||||
|
||||
BOOST_TEST(obj.contains("my_error1_"));
|
||||
BOOST_TEST_EQ(obj.at("my_error1_").as_int64(), 42);
|
||||
|
||||
BOOST_TEST(obj.contains("my_error2_"));
|
||||
BOOST_TEST_EQ(obj.at("my_error2_").as_string(), "hello");
|
||||
|
||||
BOOST_TEST(obj.contains("my_error3_"));
|
||||
auto const & mij = obj.at("my_error3_").as_object();
|
||||
BOOST_TEST_EQ(mij.at("code").as_int64(), 1);
|
||||
BOOST_TEST_EQ(mij.at("message").as_string(), "error one");
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
{
|
||||
std::cout << "Testing serialize_diagnostic_information_to:\n";
|
||||
boost::json::value j;
|
||||
try
|
||||
{
|
||||
test_exception e;
|
||||
e <<
|
||||
my_error1(42) <<
|
||||
my_error2("hello") <<
|
||||
my_error3({1, "error one"});
|
||||
BOOST_THROW_EXCEPTION(e);
|
||||
}
|
||||
catch( test_exception & e )
|
||||
{
|
||||
output_encoder enc{j};
|
||||
boost::serialize_diagnostic_information_to(e, enc);
|
||||
}
|
||||
std::cout << j << std::endl;
|
||||
check_output(j, true);
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "\nTesting serialize_current_exception_diagnostic_information_to:\n";
|
||||
boost::json::value j;
|
||||
try
|
||||
{
|
||||
test_exception e;
|
||||
e <<
|
||||
my_error1(42) <<
|
||||
my_error2("hello") <<
|
||||
my_error3({1, "error one"});
|
||||
BOOST_THROW_EXCEPTION(e);
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
output_encoder enc{j};
|
||||
boost::serialize_current_exception_diagnostic_information_to(enc);
|
||||
}
|
||||
std::cout << j << std::endl;
|
||||
check_output(j, true);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <boost/exception/info.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_CODEGEARC, BOOST_TESTED_AT(0x610))
|
||||
struct test_tag1 {};
|
||||
@@ -141,9 +142,11 @@ main()
|
||||
catch(
|
||||
error1 & x )
|
||||
{
|
||||
std::string di1=boost::diagnostic_information(x);
|
||||
std::string di1 = diagnostic_information(x);
|
||||
std::cout << __LINE__ << " ------------------\n" << di1;
|
||||
x << tagged_int1(2) << tagged_int2(2);
|
||||
std::string di2 = diagnostic_information(x);
|
||||
std::cout << "\n" << di2 << std::endl;
|
||||
test1(di1,di2);
|
||||
}
|
||||
try
|
||||
@@ -155,9 +158,11 @@ main()
|
||||
catch(
|
||||
error1 & x )
|
||||
{
|
||||
std::string di1=boost::current_exception_diagnostic_information();
|
||||
std::string di1 = current_exception_diagnostic_information();
|
||||
std::cout << __LINE__ << " ------------------\n" << di1;
|
||||
x << tagged_int1(2) << tagged_int2(2);
|
||||
std::string di2 = current_exception_diagnostic_information();
|
||||
std::cout << "\n" << di2 << std::endl;
|
||||
test1(di1,di2);
|
||||
}
|
||||
try
|
||||
@@ -170,8 +175,10 @@ main()
|
||||
error2 & x )
|
||||
{
|
||||
std::string di1 = diagnostic_information(x);
|
||||
std::cout << __LINE__ << " ------------------\n" << di1;
|
||||
x << tagged_int1(2) << tagged_int2(2);
|
||||
std::string di2 = diagnostic_information(x);
|
||||
std::cout << "\n" << di2 << std::endl;
|
||||
test2(di1,di2);
|
||||
}
|
||||
try
|
||||
@@ -184,23 +191,27 @@ main()
|
||||
error2 & x )
|
||||
{
|
||||
std::string di1 = current_exception_diagnostic_information();
|
||||
BOOST_TEST(di1==boost::diagnostic_information_what(x));
|
||||
std::cout << __LINE__ << " ------------------\n" << di1;
|
||||
BOOST_TEST(di1 == diagnostic_information_what(x));
|
||||
x << tagged_int1(2) << tagged_int2(2);
|
||||
std::string di2 = current_exception_diagnostic_information();
|
||||
BOOST_TEST(di2==boost::diagnostic_information_what(x));
|
||||
std::cout << "\n" << di2 << std::endl;
|
||||
BOOST_TEST(di2 == diagnostic_information_what(x));
|
||||
test2(di1,di2);
|
||||
}
|
||||
try
|
||||
{
|
||||
error3 x;
|
||||
std::string di=diagnostic_information(x);
|
||||
std::string di = diagnostic_information(x);
|
||||
std::cout << __LINE__ << " ------------------\n" << di << std::endl;
|
||||
test3(di);
|
||||
throw x;
|
||||
}
|
||||
catch(
|
||||
... )
|
||||
{
|
||||
std::string di=current_exception_diagnostic_information();
|
||||
std::string di = current_exception_diagnostic_information();
|
||||
std::cout << __LINE__ << " ------------------\n" << di << std::endl;
|
||||
test3(di);
|
||||
}
|
||||
try
|
||||
@@ -210,9 +221,10 @@ main()
|
||||
catch(
|
||||
error4 & x )
|
||||
{
|
||||
std::string di1=boost::diagnostic_information(x);
|
||||
std::string wh1=x.what();
|
||||
BOOST_TEST(wh1==di1);
|
||||
std::string di1 = diagnostic_information(x);
|
||||
std::cout << __LINE__ << " ------------------\n" << di1 << std::endl;
|
||||
std::string wh1 = x.what();
|
||||
BOOST_TEST(wh1 == di1);
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -222,13 +234,15 @@ main()
|
||||
catch(
|
||||
error4 & x )
|
||||
{
|
||||
std::string di1=boost::diagnostic_information(x);
|
||||
std::string wh1=x.what();
|
||||
BOOST_TEST(wh1==di1);
|
||||
std::string di1 = diagnostic_information(x);
|
||||
std::cout << __LINE__ << " ------------------\n" << di1;
|
||||
std::string wh1 = x.what();
|
||||
BOOST_TEST(wh1 == di1);
|
||||
x << tagged_int1(2) << tagged_int2(2);
|
||||
std::string di2 = diagnostic_information(x);
|
||||
std::string wh2=x.what();
|
||||
BOOST_TEST(wh2==di2);
|
||||
std::cout << "\n" << di2 << std::endl;
|
||||
std::string wh2 = x.what();
|
||||
BOOST_TEST(wh2 == di2);
|
||||
test4(di1,di2);
|
||||
}
|
||||
try
|
||||
@@ -239,13 +253,15 @@ main()
|
||||
catch(
|
||||
error4 & x )
|
||||
{
|
||||
std::string di1=boost::current_exception_diagnostic_information();
|
||||
std::string wh1=x.what();
|
||||
BOOST_TEST(wh1==di1);
|
||||
std::string di1 = current_exception_diagnostic_information();
|
||||
std::cout << __LINE__ << " ------------------\n" << di1;
|
||||
std::string wh1 = x.what();
|
||||
BOOST_TEST(wh1 == di1);
|
||||
x << tagged_int1(2) << tagged_int2(2);
|
||||
std::string di2 = current_exception_diagnostic_information();
|
||||
std::string wh2=x.what();
|
||||
BOOST_TEST(wh2==di2);
|
||||
std::cout << "\n" << di2 << std::endl;
|
||||
std::string wh2 = x.what();
|
||||
BOOST_TEST(wh2 == di2);
|
||||
test4(di1,di2);
|
||||
}
|
||||
return boost::report_errors();
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
//Copyright (c) 2006-2026 Emil Dotchevski and Reverge Studios, Inc.
|
||||
|
||||
//Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined( BOOST_NO_EXCEPTIONS )
|
||||
# error This program requires exception handling.
|
||||
#endif
|
||||
|
||||
#include <boost/exception/diagnostic_information.hpp>
|
||||
#include <boost/exception/serialization/nlohmann_json_encoder.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
|
||||
using output_encoder = boost::exception_serialization::nlohmann_json_encoder<nlohmann::ordered_json>;
|
||||
|
||||
namespace
|
||||
boost
|
||||
{
|
||||
namespace
|
||||
exception_serialization
|
||||
{
|
||||
template <class Handle, class E>
|
||||
void
|
||||
serialize(Handle & h, E const & e, char const * name)
|
||||
{
|
||||
h.dispatch(
|
||||
[&](nlohmann_json_encoder<nlohmann::json> & enc) { output_at(enc, e, name); },
|
||||
[&](nlohmann_json_encoder<nlohmann::ordered_json> & enc) { output_at(enc, e, name); } );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef boost::error_info<struct my_error1_, int> my_error1;
|
||||
typedef boost::error_info<struct my_error2_, std::string> my_error2;
|
||||
typedef boost::error_info<struct my_error4_, std::vector<int>> my_error4;
|
||||
|
||||
struct
|
||||
my_info
|
||||
{
|
||||
int code;
|
||||
char const * message;
|
||||
|
||||
template <class Json>
|
||||
friend
|
||||
void
|
||||
to_json(Json & j, my_info const & e)
|
||||
{
|
||||
j["code"] = e.code;
|
||||
j["message"] = e.message;
|
||||
}
|
||||
};
|
||||
|
||||
typedef boost::error_info<struct my_error3_, my_info> my_error3;
|
||||
|
||||
struct
|
||||
test_exception:
|
||||
virtual boost::exception,
|
||||
virtual std::exception
|
||||
{
|
||||
char const *
|
||||
what() const noexcept override
|
||||
{
|
||||
return "test_exception::what";
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
check_output(nlohmann::ordered_json const & j, bool has_source_location)
|
||||
{
|
||||
if( has_source_location )
|
||||
{
|
||||
BOOST_TEST(j.contains("throw_file"));
|
||||
BOOST_TEST(j.contains("throw_line"));
|
||||
BOOST_TEST(j.contains("throw_function"));
|
||||
}
|
||||
#ifndef BOOST_NO_RTTI
|
||||
BOOST_TEST(j.contains("dynamic_exception_type"));
|
||||
#endif
|
||||
BOOST_TEST(j.contains("std::exception::what"));
|
||||
BOOST_TEST_EQ(j["std::exception::what"].get<std::string>(), "test_exception::what");
|
||||
|
||||
BOOST_TEST(j.contains("my_error1_"));
|
||||
BOOST_TEST_EQ(j["my_error1_"].get<int>(), 42);
|
||||
|
||||
BOOST_TEST(j.contains("my_error2_"));
|
||||
BOOST_TEST_EQ(j["my_error2_"].get<std::string>(), "hello");
|
||||
|
||||
BOOST_TEST(j.contains("my_error3_"));
|
||||
auto const & mij = j["my_error3_"];
|
||||
BOOST_TEST_EQ(mij["code"].get<int>(), 1);
|
||||
BOOST_TEST_EQ(mij["message"].get<std::string>(), "error one");
|
||||
|
||||
BOOST_TEST(j.contains("my_error4_"));
|
||||
auto const & vec = j["my_error4_"];
|
||||
BOOST_TEST_EQ(vec.size(), 3u);
|
||||
BOOST_TEST_EQ(vec[0].get<int>(), 1);
|
||||
BOOST_TEST_EQ(vec[1].get<int>(), 2);
|
||||
BOOST_TEST_EQ(vec[2].get<int>(), 3);
|
||||
}
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
{
|
||||
std::cout << "Testing serialize_diagnostic_information_to:\n";
|
||||
nlohmann::ordered_json j;
|
||||
try
|
||||
{
|
||||
test_exception e;
|
||||
e <<
|
||||
my_error1(42) <<
|
||||
my_error2("hello") <<
|
||||
my_error3({1, "error one"}) <<
|
||||
my_error4({1, 2, 3});
|
||||
BOOST_THROW_EXCEPTION(e);
|
||||
}
|
||||
catch( test_exception & e )
|
||||
{
|
||||
output_encoder enc{j};
|
||||
boost::serialize_diagnostic_information_to(e, enc);
|
||||
}
|
||||
std::cout << std::setw(2) << j << std::endl;
|
||||
check_output(j, true);
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "\nTesting serialize_current_exception_diagnostic_information_to:\n";
|
||||
nlohmann::ordered_json j;
|
||||
try
|
||||
{
|
||||
test_exception e;
|
||||
e <<
|
||||
my_error1(42) <<
|
||||
my_error2("hello") <<
|
||||
my_error3({1, "error one"}) <<
|
||||
my_error4({1, 2, 3});
|
||||
BOOST_THROW_EXCEPTION(e);
|
||||
}
|
||||
catch( ... )
|
||||
{
|
||||
output_encoder enc{j};
|
||||
boost::serialize_current_exception_diagnostic_information_to(enc);
|
||||
}
|
||||
std::cout << std::setw(2) << j << std::endl;
|
||||
check_output(j, true);
|
||||
}
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
Reference in New Issue
Block a user