mirror of
https://github.com/corda/corda.git
synced 2025-06-13 04:38:19 +00:00
NOTICK - Initial work on a non JVM (C++) serialiser (#5368)
Currently, it's more of a blob inspector than a full-blown implementation, but this code does have the ability to understand a Corda serialized blob and build a set of deserialisers to handle a blob. It does this in the same way the native java implementation works by interrogating the types (as per the definition in the envelope) and building recursive type readers that are able to pull the relevant information out of the byte stream. Lots of future work to undertake, but as a starting point its a little bit useful with the scope it could be made much more useful with some work.
This commit is contained in:
15
experimental/cpp-serializer/src/amqp/AMQPDescribed.h
Normal file
15
experimental/cpp-serializer/src/amqp/AMQPDescribed.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class AMQPDescribed {
|
||||
public :
|
||||
virtual ~AMQPDescribed() { }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
54
experimental/cpp-serializer/src/amqp/AMQPDescriptor.h
Normal file
54
experimental/cpp-serializer/src/amqp/AMQPDescriptor.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "AMQPDescribed.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Forward type declarations
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct pn_data_t;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::AMQPDescriptor
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class AMQPDescriptor {
|
||||
protected :
|
||||
std::string m_symbol;
|
||||
int32_t m_val;
|
||||
|
||||
public :
|
||||
AMQPDescriptor()
|
||||
: m_symbol ("ERROR")
|
||||
, m_val (-1)
|
||||
{ }
|
||||
|
||||
AMQPDescriptor(std::string symbol_, int val_)
|
||||
: m_symbol (std::move (symbol_))
|
||||
, m_val (val_)
|
||||
{ }
|
||||
|
||||
virtual ~AMQPDescriptor() = default;
|
||||
|
||||
const std::string & symbol() const { return m_symbol; }
|
||||
|
||||
void validateAndNext (pn_data_t *) const;
|
||||
|
||||
virtual std::unique_ptr<AMQPDescribed> build (pn_data_t * data_) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
26
experimental/cpp-serializer/src/amqp/CMakeLists.txt
Normal file
26
experimental/cpp-serializer/src/amqp/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
||||
include_directories (descriptors)
|
||||
include_directories (schema)
|
||||
include_directories (consumer)
|
||||
include_directories (.)
|
||||
|
||||
set (amqp_sources
|
||||
descriptors/AMQPDescriptors.cxx
|
||||
descriptors/AMQPDescriptorRegistory.cxx
|
||||
schema/Schema.cxx
|
||||
schema/Field.cxx
|
||||
schema/Envelope.cxx
|
||||
schema/Composite.cxx
|
||||
schema/Descriptor.cxx
|
||||
schema/restricted-types/Restricted.cxx
|
||||
schema/restricted-types/List.cxx
|
||||
schema/AMQPTypeNotation.cxx
|
||||
consumer/Reader.cxx
|
||||
consumer/PropertyReader.cxx
|
||||
consumer/RestrictedReader.cxx
|
||||
consumer/CompositeReader.cxx
|
||||
CompositeFactory.cxx
|
||||
)
|
||||
|
||||
ADD_LIBRARY ( amqp ${amqp_sources} )
|
||||
|
||||
ADD_SUBDIRECTORY (test)
|
212
experimental/cpp-serializer/src/amqp/CompositeFactory.cxx
Normal file
212
experimental/cpp-serializer/src/amqp/CompositeFactory.cxx
Normal file
@ -0,0 +1,212 @@
|
||||
#include "CompositeFactory.h"
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include "consumer/Reader.h"
|
||||
#include "consumer/PropertyReader.h"
|
||||
#include "consumer/CompositeReader.h"
|
||||
#include "consumer/RestrictedReader.h"
|
||||
|
||||
#include "schema/restricted-types/List.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template <typename T>
|
||||
std::shared_ptr<T> &
|
||||
computeIfAbsent (
|
||||
spStrMap_t<T> & map_,
|
||||
const std::string & k_,
|
||||
std::function<std::shared_ptr<T>(void)> f_
|
||||
) {
|
||||
auto it = map_.find (k_);
|
||||
|
||||
if (it == map_.end()) {
|
||||
DBG ("ComputeIfAbsent \"" << k_ << "\" - missing" << std::endl); // NOLINT
|
||||
map_[k_] = std::move (f_());
|
||||
DBG (" \"" << k_ << "\" - RTN: " << map_[k_]->name() << " : " << map_[k_]->type() << std::endl); // NOLINT
|
||||
assert (map_[k_]);
|
||||
assert (map_[k_] != nullptr);
|
||||
assert (k_ == map_[k_]->type());
|
||||
|
||||
return map_[k_];
|
||||
}
|
||||
else {
|
||||
DBG ("ComputeIfAbsent \"" << k_ << "\" - found it" << std::endl); // NOLINT
|
||||
DBG (" \"" << k_ << "\" - RTN: " << map_[k_]->name() << std::endl); // NOLINT
|
||||
|
||||
assert (it->second != nullptr);
|
||||
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* CompositeFactory
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
* Walk through the types in a Schema and produce readers for them.
|
||||
*
|
||||
* We are making the large assumption that the contents of [schema_]
|
||||
* are strictly ordered by dependency so we can construct types
|
||||
* as we go without needing to provide look ahead for types
|
||||
* we haven't built yet
|
||||
*
|
||||
*/
|
||||
void
|
||||
CompositeFactory::process (const SchemaPtr & schema_) {
|
||||
for (auto i = schema_->begin() ; i != schema_->end() ; ++i) {
|
||||
for (const auto & j : *i) {
|
||||
process(*j);
|
||||
m_readersByDescriptor[j->descriptor()] = m_readersByType[j->name()];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::shared_ptr<amqp::Reader>
|
||||
CompositeFactory::process(
|
||||
const amqp::internal::schema::AMQPTypeNotation & schema_)
|
||||
{
|
||||
return computeIfAbsent<amqp::Reader> (
|
||||
m_readersByType,
|
||||
schema_.name(),
|
||||
[& schema_, this] () -> std::shared_ptr<amqp::Reader> {
|
||||
switch (schema_.type()) {
|
||||
case amqp::internal::schema::AMQPTypeNotation::Composite : {
|
||||
return processComposite(schema_);
|
||||
}
|
||||
case amqp::internal::schema::AMQPTypeNotation::Restricted : {
|
||||
return processRestricted(schema_);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::shared_ptr<amqp::Reader>
|
||||
CompositeFactory::processComposite (
|
||||
const amqp::internal::schema::AMQPTypeNotation & type_)
|
||||
{
|
||||
std::vector<std::weak_ptr<amqp::Reader>> readers;
|
||||
|
||||
const auto & fields = dynamic_cast<const amqp::internal::schema::Composite &> (
|
||||
type_).fields();
|
||||
|
||||
readers.reserve(fields.size());
|
||||
|
||||
for (const auto & field : fields) {
|
||||
DBG (" Field: " << field->name() << ": " << field->type() << std::endl); // NOLINT
|
||||
|
||||
switch (field->fieldType()) {
|
||||
case amqp::internal::schema::FieldType::PrimitiveProperty : {
|
||||
auto reader = computeIfAbsent<amqp::Reader>(
|
||||
m_readersByType,
|
||||
field->type(),
|
||||
[&field]() -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return amqp::PropertyReader::make(field);
|
||||
});
|
||||
|
||||
assert (reader);
|
||||
readers.emplace_back(reader);
|
||||
assert (readers.back().lock());
|
||||
break;
|
||||
}
|
||||
case amqp::internal::schema::FieldType::CompositeProperty : {
|
||||
auto reader = m_readersByType[field->type()];
|
||||
|
||||
assert (reader);
|
||||
readers.emplace_back(reader);
|
||||
assert (readers.back().lock());
|
||||
break;
|
||||
}
|
||||
case amqp::internal::schema::FieldType::RestrictedProperty : {
|
||||
auto reader = m_readersByType[field->requires().front()];
|
||||
|
||||
assert (reader);
|
||||
readers.emplace_back(reader);
|
||||
assert (readers.back().lock());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert (readers.back().lock());
|
||||
}
|
||||
|
||||
return std::make_shared<amqp::CompositeReader> (type_.name(), readers);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::shared_ptr<amqp::Reader>
|
||||
CompositeFactory::processRestricted (
|
||||
const amqp::internal::schema::AMQPTypeNotation & type_)
|
||||
{
|
||||
DBG ("processRestricted - " << type_.name() << std::endl); // NOLINT
|
||||
const auto & restricted = dynamic_cast<const amqp::internal::schema::Restricted &> (
|
||||
type_);
|
||||
|
||||
if (restricted.restrictedType() ==
|
||||
amqp::internal::schema::Restricted::RestrictedTypes::List)
|
||||
{
|
||||
const auto & list = dynamic_cast<const amqp::internal::schema::List &> (restricted);
|
||||
|
||||
DBG ("Processing List - " << list.listOf() << std::endl); // NOLINT
|
||||
|
||||
if (amqp::internal::schema::Field::typeIsPrimitive(list.listOf())) {
|
||||
DBG (" List of Primitives" << std::endl); // NOLINT
|
||||
auto reader = computeIfAbsent<amqp::Reader> (
|
||||
m_readersByType,
|
||||
list.listOf(),
|
||||
[& list] () -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return amqp::PropertyReader::make (list.listOf());
|
||||
});
|
||||
|
||||
return std::make_shared<amqp::ListReader> (type_.name(), reader);
|
||||
} else {
|
||||
DBG (" List of Composite - " << list.listOf() << std::endl); // NOLINT
|
||||
auto reader = m_readersByType[list.listOf()];
|
||||
|
||||
return std::make_shared<amqp::ListReader> (list.name(), reader);
|
||||
}
|
||||
}
|
||||
|
||||
DBG (" ProcessRestricted: Returning nullptr"); // NOLINT
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::shared_ptr<amqp::Reader>
|
||||
CompositeFactory::byType (const std::string & type_) {
|
||||
auto it = m_readersByType.find (type_);
|
||||
|
||||
return (it == m_readersByType.end()) ? nullptr : it->second;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::shared_ptr<amqp::Reader>
|
||||
CompositeFactory::byDescriptor (const std::string & descriptor_) {
|
||||
auto it = m_readersByDescriptor.find (descriptor_);
|
||||
|
||||
return (it == m_readersByDescriptor.end()) ? nullptr : it->second;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
@ -0,0 +1,149 @@
|
||||
#include "CompositeReader.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
|
||||
#include <proton/codec.h>
|
||||
#include <sstream>
|
||||
#include "debug.h"
|
||||
#include "proton/proton_wrapper.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string amqp::CompositeReader::m_name { // NOLINT
|
||||
"Composite Reader"
|
||||
};
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
amqp::
|
||||
CompositeReader::CompositeReader (
|
||||
std::string type_,
|
||||
std::vector<std::weak_ptr<amqp::Reader>> & readers_
|
||||
) : m_readers (readers_)
|
||||
, m_type (std::move (type_))
|
||||
{
|
||||
DBG ("MAKE CompositeReader: " << m_type << ": " << m_readers.size() << std::endl); // NOLINT
|
||||
for (auto reader : m_readers) {
|
||||
assert (reader.lock());
|
||||
if (auto r = reader.lock()) {
|
||||
DBG (" prop: " << r->name() << " " << r->type() << std::endl); // NOLINT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::
|
||||
CompositeReader::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::
|
||||
CompositeReader::type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
CompositeReader::read (pn_data_t * data_) const {
|
||||
return std::any(1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
CompositeReader::readString (pn_data_t * data_) const {
|
||||
pn_data_next (data_);
|
||||
proton::auto_enter ae (data_);
|
||||
|
||||
return "Composite";
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
||||
std::vector<std::unique_ptr<amqp::Value>>
|
||||
amqp::
|
||||
CompositeReader::_dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<amqp::internal::schema::Schema> & schema_
|
||||
) const {
|
||||
DBG ("Read Composite: " << m_name << " : " << type() << std::endl); // NOLINT
|
||||
proton::is_described (data_);
|
||||
proton::auto_enter ae (data_);
|
||||
|
||||
const auto & it = schema_->fromDescriptor(proton::get_symbol<std::string>(data_));
|
||||
auto & fields = dynamic_cast<amqp::internal::schema::Composite &>(*(it->second.get())).fields();
|
||||
|
||||
assert (fields.size() == m_readers.size());
|
||||
|
||||
pn_data_next (data_);
|
||||
|
||||
std::vector<std::unique_ptr<amqp::Value>> read;
|
||||
read.reserve (fields.size());
|
||||
|
||||
proton::is_list (data_);
|
||||
{
|
||||
proton::auto_enter ae (data_);
|
||||
|
||||
for (int i (0) ; i < m_readers.size() ; ++i) {
|
||||
if (auto l = m_readers[i].lock()) {
|
||||
DBG (fields[i]->name() << " " << (l ? "true" : "false") << std::endl); // NOLINT
|
||||
|
||||
read.emplace_back(l->dump(fields[i]->name(), data_, schema_));
|
||||
} else {
|
||||
std::stringstream s;
|
||||
s << "null field reader: " << fields[i]->name();
|
||||
throw std::runtime_error(s.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
CompositeReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
|
||||
return std::make_unique<amqp::TypedPair<std::vector<std::unique_ptr<amqp::Value>>>> (
|
||||
name_,
|
||||
_dump(data_, schema_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
CompositeReader::dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
|
||||
return std::make_unique<amqp::TypedSingle<std::vector<std::unique_ptr<amqp::Value>>>> (
|
||||
_dump (data_, schema_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include "Reader.h"
|
||||
|
||||
#include <any>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
class CompositeReader : public Reader {
|
||||
private :
|
||||
std::vector<std::weak_ptr<amqp::Reader>> m_readers;
|
||||
|
||||
static const std::string m_name;
|
||||
|
||||
std::string m_type;
|
||||
|
||||
std::vector<std::unique_ptr<amqp::Value>> _dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<amqp::internal::schema::Schema> & schema_) const;
|
||||
|
||||
public :
|
||||
CompositeReader (
|
||||
std::string type_,
|
||||
std::vector<std::weak_ptr<amqp::Reader>> & readers_
|
||||
);
|
||||
|
||||
~CompositeReader() = default;
|
||||
|
||||
std::any read (pn_data_t *) const override;
|
||||
|
||||
std::string readString(pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const override;
|
||||
|
||||
const std::string & name() const override;
|
||||
const std::string & type() const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
343
experimental/cpp-serializer/src/amqp/consumer/PropertyReader.cxx
Normal file
343
experimental/cpp-serializer/src/amqp/consumer/PropertyReader.cxx
Normal file
@ -0,0 +1,343 @@
|
||||
#include "PropertyReader.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
|
||||
#include <proton/codec.h>
|
||||
|
||||
#include "proton/proton_wrapper.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<std::string, std::shared_ptr<amqp::PropertyReader>(*)() > propertyMap = {
|
||||
{
|
||||
"int", []() -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return std::make_shared<amqp::IntPropertyReader> ();
|
||||
}
|
||||
},
|
||||
{
|
||||
"string", []() -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return std::make_shared<amqp::StringPropertyReader> (
|
||||
amqp::StringPropertyReader());
|
||||
}
|
||||
},
|
||||
{
|
||||
"boolean", []() -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return std::make_shared<amqp::BoolPropertyReader> (
|
||||
amqp::BoolPropertyReader());
|
||||
}
|
||||
},
|
||||
{
|
||||
"long", []() -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return std::make_shared<amqp::LongPropertyReader> (
|
||||
amqp::LongPropertyReader());
|
||||
}
|
||||
},
|
||||
{
|
||||
"double", []() -> std::shared_ptr<amqp::PropertyReader> {
|
||||
return std::make_shared<amqp::DoublePropertyReader> (
|
||||
amqp::DoublePropertyReader());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string amqp::StringPropertyReader::m_name { // NOLINT
|
||||
"String Reader"
|
||||
};
|
||||
|
||||
const std::string amqp::StringPropertyReader::m_type { // NOLINT
|
||||
"string"
|
||||
};
|
||||
|
||||
const std::string amqp::IntPropertyReader::m_name { // NOLINT
|
||||
"Int Reader"
|
||||
};
|
||||
|
||||
const std::string amqp::IntPropertyReader::m_type { // NOLINT
|
||||
"int"
|
||||
};
|
||||
|
||||
const std::string amqp::BoolPropertyReader::m_name { // NOLINT
|
||||
"Bool Reader"
|
||||
};
|
||||
|
||||
const std::string amqp::BoolPropertyReader::m_type { // NOLINT
|
||||
"bool"
|
||||
};
|
||||
|
||||
const std::string amqp::LongPropertyReader::m_name { // NOLINT
|
||||
"Long Reader"
|
||||
};
|
||||
|
||||
const std::string amqp::LongPropertyReader::m_type { // NOLINT
|
||||
"long"
|
||||
};
|
||||
|
||||
const std::string amqp::DoublePropertyReader::m_name { // NOLINT
|
||||
"Double Reader"
|
||||
};
|
||||
|
||||
const std::string amqp::DoublePropertyReader::m_type { // NOLINT
|
||||
"double"
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* Static factory method
|
||||
*/
|
||||
std::shared_ptr<amqp::PropertyReader>
|
||||
amqp::
|
||||
PropertyReader::make (const FieldPtr & field_) {
|
||||
return propertyMap[field_->type()]();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::shared_ptr<amqp::PropertyReader>
|
||||
amqp::
|
||||
PropertyReader::make (const std::string & type_) {
|
||||
return propertyMap[type_]();
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* StringPropertyReader
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
StringPropertyReader::read (pn_data_t * data_) const {
|
||||
return std::any ("hello");
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
StringPropertyReader::readString (pn_data_t * data_) const {
|
||||
return proton::readAndNext<std::string> (data_);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
StringPropertyReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedPair<std::string>> (
|
||||
name_,
|
||||
"\"" + proton::readAndNext<std::string> (data_) + "\"");
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
StringPropertyReader::dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedSingle<std::string>> (
|
||||
"\"" + proton::readAndNext<std::string> (data_) + "\"");
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* IntPropertyReader
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
IntPropertyReader::read (pn_data_t * data_) const {
|
||||
return std::any (1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
IntPropertyReader::readString (pn_data_t * data_) const {
|
||||
return std::to_string (proton::readAndNext<int> (data_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
IntPropertyReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedPair<std::string>> (
|
||||
name_,
|
||||
std::to_string (proton::readAndNext<int> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
IntPropertyReader::dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedSingle<std::string>> (
|
||||
std::to_string (proton::readAndNext<int> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* BoolPropertyReader
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
BoolPropertyReader::read (pn_data_t * data_) const {
|
||||
return std::any (true);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
BoolPropertyReader::readString (pn_data_t * data_) const {
|
||||
return std::to_string (proton::readAndNext<bool> (data_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
BoolPropertyReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedPair<std::string>> (
|
||||
name_,
|
||||
std::to_string (proton::readAndNext<bool> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
BoolPropertyReader::dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedSingle<std::string>> (
|
||||
std::to_string (proton::readAndNext<bool> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* LongPropertyReader
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
LongPropertyReader::read (pn_data_t * data_) const {
|
||||
return std::any (10L);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
LongPropertyReader::readString (pn_data_t * data_) const {
|
||||
return std::to_string (proton::readAndNext<long> (data_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
LongPropertyReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedPair<std::string>> (
|
||||
name_,
|
||||
std::to_string (proton::readAndNext<long> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
LongPropertyReader::dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedSingle<std::string>> (
|
||||
std::to_string (proton::readAndNext<long> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* DoublePropertyReader
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
DoublePropertyReader::read (pn_data_t * data_) const {
|
||||
return std::any (10.0);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
DoublePropertyReader::readString (pn_data_t * data_) const {
|
||||
return std::to_string (proton::readAndNext<double> (data_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
DoublePropertyReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedPair<std::string>> (
|
||||
name_,
|
||||
std::to_string (proton::readAndNext<double> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
DoublePropertyReader::dump (
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_) const
|
||||
{
|
||||
return std::make_unique<TypedSingle<std::string>> (
|
||||
std::to_string (proton::readAndNext<double> (data_)));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
204
experimental/cpp-serializer/src/amqp/consumer/PropertyReader.h
Normal file
204
experimental/cpp-serializer/src/amqp/consumer/PropertyReader.h
Normal file
@ -0,0 +1,204 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <iostream>
|
||||
#include "Reader.h"
|
||||
|
||||
#include "amqp/schema/Field.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
class PropertyReader : public Reader {
|
||||
private :
|
||||
using FieldPtr = std::unique_ptr<internal::schema::Field>;
|
||||
|
||||
public :
|
||||
/**
|
||||
* Static Factory method for creating appropriate derived types
|
||||
*/
|
||||
static std::shared_ptr<PropertyReader> make (const FieldPtr &);
|
||||
static std::shared_ptr<PropertyReader> make (const std::string &);
|
||||
|
||||
~PropertyReader() override = default;
|
||||
|
||||
std::string readString(pn_data_t *) const override = 0;
|
||||
|
||||
std::any read (pn_data_t *) const override = 0;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override = 0;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override = 0;
|
||||
|
||||
const std::string & name() const override = 0;
|
||||
|
||||
const std::string & type() const override = 0;
|
||||
};
|
||||
|
||||
|
||||
class StringPropertyReader : public PropertyReader {
|
||||
private :
|
||||
static const std::string m_name;
|
||||
static const std::string m_type;
|
||||
|
||||
public :
|
||||
std::string readString (pn_data_t *) const override;
|
||||
|
||||
std::any read (pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
const std::string & name() const override {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string & type() const override {
|
||||
return m_type;
|
||||
}
|
||||
};
|
||||
|
||||
class IntPropertyReader : public PropertyReader {
|
||||
private :
|
||||
static const std::string m_name;
|
||||
static const std::string m_type;
|
||||
|
||||
public :
|
||||
~IntPropertyReader() override = default;
|
||||
|
||||
std::string readString (pn_data_t *) const override;
|
||||
|
||||
std::any read (pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
const std::string & name() const override {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string & type() const override {
|
||||
return m_type;
|
||||
}
|
||||
};
|
||||
|
||||
class BoolPropertyReader : public PropertyReader {
|
||||
private :
|
||||
static const std::string m_name;
|
||||
static const std::string m_type;
|
||||
|
||||
public :
|
||||
std::string readString (pn_data_t *) const override;
|
||||
|
||||
std::any read (pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
const std::string & name() const override {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string & type() const override {
|
||||
return m_type;
|
||||
}
|
||||
};
|
||||
|
||||
class LongPropertyReader : public PropertyReader {
|
||||
private :
|
||||
static const std::string m_name;
|
||||
static const std::string m_type;
|
||||
|
||||
public :
|
||||
std::string readString (pn_data_t *) const override;
|
||||
|
||||
std::any read (pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
const std::string & name() const override {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string & type() const override {
|
||||
return m_type;
|
||||
}
|
||||
};
|
||||
|
||||
class DoublePropertyReader : public PropertyReader {
|
||||
private :
|
||||
static const std::string m_name;
|
||||
static const std::string m_type;
|
||||
|
||||
public :
|
||||
std::string readString (pn_data_t *) const override;
|
||||
|
||||
std::any read (pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &
|
||||
) const override;
|
||||
|
||||
const std::string & name() const override {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
const std::string & type() const override {
|
||||
return m_type;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
|
136
experimental/cpp-serializer/src/amqp/consumer/Reader.cxx
Normal file
136
experimental/cpp-serializer/src/amqp/consumer/Reader.cxx
Normal file
@ -0,0 +1,136 @@
|
||||
#include "Reader.h"
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
struct AutoMap {
|
||||
std::stringstream & m_stream;
|
||||
|
||||
AutoMap (const std::string & s, std::stringstream & stream_) : m_stream (stream_) {
|
||||
m_stream << s << " : { ";
|
||||
}
|
||||
|
||||
AutoMap (std::stringstream & stream_) : m_stream (stream_) {
|
||||
m_stream << "{ ";
|
||||
}
|
||||
|
||||
~AutoMap() {
|
||||
m_stream << " }";
|
||||
}
|
||||
};
|
||||
|
||||
struct AutoList {
|
||||
std::stringstream & m_stream;
|
||||
|
||||
AutoList (const std::string & s, std::stringstream & stream_) : m_stream (stream_) {
|
||||
m_stream << s << " : [ ";
|
||||
}
|
||||
|
||||
AutoList (std::stringstream & stream_) : m_stream (stream_) {
|
||||
m_stream << "[ ";
|
||||
}
|
||||
|
||||
~AutoList() {
|
||||
m_stream << " ]";
|
||||
}
|
||||
};
|
||||
|
||||
template<class Auto, class T>
|
||||
std::string
|
||||
dumpPair(const std::string & name_, const T & begin_, const T & end_) {
|
||||
std::stringstream rtn;
|
||||
{
|
||||
Auto am (name_, rtn);
|
||||
|
||||
rtn << (*(begin_))->dump();
|
||||
for (auto it(std::next(begin_)) ; it != end_; ++it) {
|
||||
rtn << ", " << (*it)->dump();
|
||||
}
|
||||
}
|
||||
|
||||
return rtn.str();
|
||||
}
|
||||
|
||||
template<class Auto, class T>
|
||||
std::string
|
||||
dumpSingle(const T & begin_, const T & end_) {
|
||||
std::stringstream rtn;
|
||||
{
|
||||
Auto am (rtn);
|
||||
|
||||
rtn << (*(begin_))->dump();
|
||||
for (auto it(std::next(begin_)) ; it != end_; ++it) {
|
||||
rtn << ", " << (*it)->dump();
|
||||
}
|
||||
}
|
||||
|
||||
return rtn.str();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::vector<std::unique_ptr<amqp::Pair>>>::dump() const {
|
||||
return ::dumpPair<AutoMap> (m_property, m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::list<std::unique_ptr<amqp::Pair>>>::dump() const {
|
||||
return ::dumpPair<AutoMap> (m_property, m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::vector<std::unique_ptr<amqp::Value>>>::dump() const {
|
||||
return ::dumpPair<AutoMap> (m_property, m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::list<std::unique_ptr<amqp::Value>>>::dump() const {
|
||||
return ::dumpPair<AutoList> (m_property, m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::list<std::unique_ptr<amqp::Value>>>::dump() const {
|
||||
return ::dumpSingle<AutoList> (m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::vector<std::unique_ptr<amqp::Value>>>::dump() const {
|
||||
return ::dumpSingle<AutoMap> (m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::list<std::unique_ptr<amqp::Single>>>::dump() const {
|
||||
return ::dumpSingle<AutoList> (m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::vector<std::unique_ptr<amqp::Single>>>::dump() const {
|
||||
return ::dumpSingle<AutoMap> (m_value.begin(), m_value.end());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
211
experimental/cpp-serializer/src/amqp/consumer/Reader.h
Normal file
211
experimental/cpp-serializer/src/amqp/consumer/Reader.h
Normal file
@ -0,0 +1,211 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <any>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "schema/Schema.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct pn_data_t;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
class Value {
|
||||
public :
|
||||
virtual std::string dump() const = 0;
|
||||
|
||||
virtual ~Value() = default;
|
||||
};
|
||||
|
||||
class Single : public Value {
|
||||
public :
|
||||
std::string dump() const override = 0;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class TypedSingle : public Single {
|
||||
private:
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
explicit TypedSingle (const T & value_)
|
||||
: Single()
|
||||
, m_value (value_)
|
||||
{ }
|
||||
|
||||
explicit TypedSingle (T && value_)
|
||||
: Single()
|
||||
, m_value { std::move (value_) }
|
||||
{ }
|
||||
|
||||
TypedSingle (const TypedSingle && value_) noexcept
|
||||
: Single()
|
||||
, m_value { std::move (value_.m_value) }
|
||||
{ }
|
||||
|
||||
const T & value() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::string dump() const override;
|
||||
};
|
||||
|
||||
class Pair : public Value {
|
||||
protected :
|
||||
std::string m_property;
|
||||
|
||||
public:
|
||||
explicit Pair(const std::string & property_)
|
||||
: m_property (property_)
|
||||
{ }
|
||||
|
||||
virtual ~Pair() = default;
|
||||
|
||||
Pair (amqp::Pair && pair_) noexcept
|
||||
: m_property (std::move (pair_.m_property))
|
||||
{ }
|
||||
|
||||
std::string dump() const override = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class TypedPair : public Pair {
|
||||
private:
|
||||
T m_value;
|
||||
|
||||
public:
|
||||
TypedPair (const std::string & property_, T & value_)
|
||||
: Pair (property_)
|
||||
, m_value (value_)
|
||||
{ }
|
||||
|
||||
TypedPair (const std::string & property_, T && value_)
|
||||
: Pair (property_)
|
||||
, m_value (std::move (value_))
|
||||
{ }
|
||||
|
||||
TypedPair (TypedPair && pair_)
|
||||
: Pair (std::move (pair_.m_property))
|
||||
, m_value (std::move (pair_.m_value))
|
||||
{ }
|
||||
|
||||
const T & value() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::string dump() const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::TypeSingle
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
template<typename T>
|
||||
inline std::string
|
||||
amqp::TypedSingle<T>::dump() const {
|
||||
return std::to_string(m_value);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string
|
||||
amqp::TypedSingle<std::string>::dump() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::vector<std::unique_ptr<amqp::Value>>>::dump() const;
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::list<std::unique_ptr<amqp::Value>>>::dump() const;
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::vector<std::unique_ptr<amqp::Single>>>::dump() const;
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedSingle<std::list<std::unique_ptr<amqp::Single>>>::dump() const;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::TypedPair
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
template<typename T>
|
||||
inline std::string
|
||||
amqp::TypedPair<T>::dump() const {
|
||||
return m_property + " : " + std::to_string (m_value);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline std::string
|
||||
amqp::TypedPair<std::string>::dump() const {
|
||||
return m_property + " : " + m_value;
|
||||
}
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::vector<std::unique_ptr<amqp::Value>>>::dump() const;
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::list<std::unique_ptr<amqp::Value>>>::dump() const;
|
||||
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::vector<std::unique_ptr<amqp::Pair>>>::dump() const;
|
||||
|
||||
template<>
|
||||
std::string
|
||||
amqp::TypedPair<std::list<std::unique_ptr<amqp::Pair>>>::dump() const;
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
class Reader {
|
||||
public :
|
||||
virtual ~Reader() = default;
|
||||
virtual const std::string & name() const = 0;
|
||||
virtual const std::string & type() const = 0;
|
||||
|
||||
virtual std::any read(pn_data_t *) const = 0;
|
||||
virtual std::string readString(pn_data_t *) const = 0;
|
||||
|
||||
virtual std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const = 0;
|
||||
|
||||
virtual std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,116 @@
|
||||
#include "RestrictedReader.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "proton/proton_wrapper.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string amqp::RestrictedReader::m_name { // NOLINT
|
||||
"Restricted Reader"
|
||||
};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::any
|
||||
amqp::
|
||||
RestrictedReader::read(pn_data_t *) const {
|
||||
return std::any(1);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::
|
||||
RestrictedReader::readString(pn_data_t * data_) const {
|
||||
return "hello";
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::list<std::unique_ptr<amqp::Value>>
|
||||
amqp::
|
||||
ListReader::dump_(
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_
|
||||
) const {
|
||||
proton::is_described (data_);
|
||||
|
||||
std::list<std::unique_ptr<amqp::Value>> read;
|
||||
|
||||
{
|
||||
proton::auto_enter ae (data_);
|
||||
auto it = schema_->fromDescriptor(proton::readAndNext<std::string>(data_));
|
||||
|
||||
{
|
||||
proton::auto_list_enter ale (data_, true);
|
||||
|
||||
for (size_t i { 0 } ; i < ale.elements() ; ++i) {
|
||||
read.emplace_back (m_reader.lock()->dump(data_, schema_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
ListReader::dump (
|
||||
const std::string & name_,
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_
|
||||
) const {
|
||||
proton::auto_next an (data_);
|
||||
|
||||
return std::make_unique<amqp::TypedPair<std::list<std::unique_ptr<amqp::Value>>>>(
|
||||
name_,
|
||||
dump_ (data_, schema_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::Value>
|
||||
amqp::
|
||||
ListReader::dump(
|
||||
pn_data_t * data_,
|
||||
const std::unique_ptr<internal::schema::Schema> & schema_
|
||||
) const {
|
||||
proton::auto_next an (data_);
|
||||
|
||||
return std::make_unique<amqp::TypedSingle<std::list<std::unique_ptr<amqp::Value>>>>(
|
||||
dump_ (data_, schema_));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::
|
||||
RestrictedReader::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::
|
||||
RestrictedReader::type() const {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
amqp::internal::schema::Restricted::RestrictedTypes
|
||||
amqp::
|
||||
ListReader::restrictedType() const {
|
||||
return internal::schema::Restricted::RestrictedTypes::List;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include "Reader.h"
|
||||
|
||||
#include <any>
|
||||
#include <vector>
|
||||
|
||||
#include "amqp/schema/restricted-types/Restricted.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct pn_data_t;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
class RestrictedReader : public Reader {
|
||||
private :
|
||||
static const std::string m_name;
|
||||
const std::string m_type;
|
||||
|
||||
public :
|
||||
RestrictedReader (const std::string & type_)
|
||||
: m_type (type_)
|
||||
{ }
|
||||
|
||||
~RestrictedReader() = default;
|
||||
|
||||
std::any read(pn_data_t *) const override ;
|
||||
|
||||
std::string readString(pn_data_t *) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const override = 0;
|
||||
|
||||
const std::string & name() const override;
|
||||
const std::string & type() const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
class ListReader : public RestrictedReader {
|
||||
private :
|
||||
// How to read the underlying types
|
||||
std::weak_ptr<amqp::Reader> m_reader;
|
||||
|
||||
std::list<std::unique_ptr<amqp::Value>> dump_(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const;
|
||||
|
||||
public :
|
||||
ListReader (
|
||||
const std::string & type_,
|
||||
std::weak_ptr<amqp::Reader> reader_
|
||||
) : RestrictedReader (type_)
|
||||
, m_reader (reader_)
|
||||
{ }
|
||||
|
||||
~ListReader() final = default;
|
||||
|
||||
internal::schema::Restricted::RestrictedTypes restrictedType() const;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
const std::string &,
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const override;
|
||||
|
||||
std::unique_ptr<Value> dump(
|
||||
pn_data_t *,
|
||||
const std::unique_ptr<internal::schema::Schema> &) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,161 @@
|
||||
#include "AMQPDescriptorRegistory.h"
|
||||
#include "AMQPDescriptors.h"
|
||||
|
||||
#include <limits>
|
||||
#include <climits>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
namespace internal {
|
||||
|
||||
|
||||
const uint64_t DESCRIPTOR_TOP_32BITS = 0xc562L << (32 + 16);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
namespace internal {
|
||||
|
||||
const int ENVELOPE = 1;
|
||||
const int SCHEMA = 2;
|
||||
const int OBJECT = 3;
|
||||
const int FIELD = 4;
|
||||
const int COMPOSITE_TYPE = 5;
|
||||
const int RESTRICTED_TYPE = 6;
|
||||
const int CHOICE = 7;
|
||||
const int REFERENCED_OBJECT = 8;
|
||||
const int TRANSFORM_SCHEMA = 9;
|
||||
const int TRANSFORM_ELEMENT = 10;
|
||||
const int TRANSFORM_ELEMENT_KEY = 11;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
namespace amqp {
|
||||
|
||||
std::map<uint64_t, std::shared_ptr<internal::AMQPDescriptor>>
|
||||
AMQPDescriptorRegistory = {
|
||||
{
|
||||
1L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::EnvelopeDescriptor> (
|
||||
internal::EnvelopeDescriptor (
|
||||
"ENVELOPE",
|
||||
internal::ENVELOPE))
|
||||
},
|
||||
{
|
||||
2L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::SchemaDescriptor> (
|
||||
internal::SchemaDescriptor (
|
||||
"SCHEMA",
|
||||
internal::SCHEMA))
|
||||
},
|
||||
{
|
||||
3L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::ObjectDescriptor> (
|
||||
internal::ObjectDescriptor (
|
||||
"OBJECT_DESCRIPTOR",
|
||||
internal::OBJECT))
|
||||
},
|
||||
{
|
||||
4L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::FieldDescriptor> (
|
||||
internal::FieldDescriptor (
|
||||
"FIELD",
|
||||
internal::FIELD))
|
||||
},
|
||||
{
|
||||
5L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::CompositeDescriptor> (
|
||||
internal::CompositeDescriptor (
|
||||
"COMPOSITE_TYPE",
|
||||
internal::COMPOSITE_TYPE))
|
||||
},
|
||||
{
|
||||
6L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::RestrictedDescriptor> (
|
||||
internal::RestrictedDescriptor (
|
||||
"RESTRICTED_TYPE",
|
||||
internal::RESTRICTED_TYPE))
|
||||
},
|
||||
{
|
||||
7L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::ChoiceDescriptor> (
|
||||
internal::ChoiceDescriptor (
|
||||
"CHOICE",
|
||||
internal::CHOICE))
|
||||
},
|
||||
{
|
||||
8L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::ReferencedObjectDescriptor> (
|
||||
internal::ReferencedObjectDescriptor (
|
||||
"REFERENCED_OBJECT",
|
||||
internal::REFERENCED_OBJECT))
|
||||
},
|
||||
{
|
||||
9L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::TransformSchemaDescriptor> (
|
||||
internal::TransformSchemaDescriptor (
|
||||
"TRANSFORM_SCHEMA",
|
||||
internal::TRANSFORM_SCHEMA))
|
||||
},
|
||||
{
|
||||
10L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::TransformElementDescriptor> (
|
||||
internal::TransformElementDescriptor (
|
||||
"TRANSFORM_ELEMENT",
|
||||
internal::TRANSFORM_ELEMENT))
|
||||
},
|
||||
{
|
||||
11L | internal::DESCRIPTOR_TOP_32BITS,
|
||||
std::make_shared<internal::TransformElementKeyDescriptor> (
|
||||
internal::TransformElementKeyDescriptor (
|
||||
"TRANSFORM_ELEMENT_KEY",
|
||||
internal::TRANSFORM_ELEMENT_KEY))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
uint32_t
|
||||
amqp::stripCorda (uint64_t id) {
|
||||
return static_cast<uint32_t>(id & (uint64_t)UINT_MAX);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::describedToString(uint64_t val_) {
|
||||
switch (val_) {
|
||||
case (1L | internal::DESCRIPTOR_TOP_32BITS) : return "ENVELOPE";
|
||||
case (2L | internal::DESCRIPTOR_TOP_32BITS) : return "SCHEMA";
|
||||
case (3L | internal::DESCRIPTOR_TOP_32BITS) : return "OBJECT_DESCRIPTOR";
|
||||
case (4L | internal::DESCRIPTOR_TOP_32BITS) : return "FIELD";
|
||||
case (5L | internal::DESCRIPTOR_TOP_32BITS) : return "COMPOSITE_TYPE";
|
||||
case (6L | internal::DESCRIPTOR_TOP_32BITS) : return "RESTRICTED_TYPE";
|
||||
case (7L | internal::DESCRIPTOR_TOP_32BITS) : return "CHOICE";
|
||||
case (8L | internal::DESCRIPTOR_TOP_32BITS) : return "REFERENCED_OBJECT";
|
||||
case (9L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_SCHEMA";
|
||||
case (10L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT";
|
||||
case (11L | internal::DESCRIPTOR_TOP_32BITS) : return "TRANSFORM_ELEMENT_KEY";
|
||||
default : return "UNKNOWN";
|
||||
};
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::string
|
||||
amqp::describedToString(uint32_t val_) {
|
||||
return describedToString(val_ | internal::DESCRIPTOR_TOP_32BITS);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include "amqp/AMQPDescriptor.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* R3 AMQP assigned enterprise number
|
||||
*
|
||||
* see [here](https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers)
|
||||
*
|
||||
* Repeated here for brevity:
|
||||
* 50530 - R3 - Mike Hearn - mike&r3.com
|
||||
*/
|
||||
namespace amqp::internal {
|
||||
|
||||
extern const uint64_t DESCRIPTOR_TOP_32BITS;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
extern const int ENVELOPE;
|
||||
extern const int SCHEMA;
|
||||
extern const int OBJECT_DESCRIPTOR;
|
||||
extern const int FIELD;
|
||||
extern const int COMPOSITE_TYPE;
|
||||
extern const int RESTRICTED_TYPE;
|
||||
extern const int CHOICE;
|
||||
extern const int REFERENCED_OBJECT;
|
||||
extern const int TRANSFORM_SCHEMA;
|
||||
extern const int TRANSFORM_ELEMENT;
|
||||
extern const int TRANSFORM_ELEMENT_KEY;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
namespace amqp {
|
||||
|
||||
extern std::map<uint64_t, std::shared_ptr<internal::AMQPDescriptor>> AMQPDescriptorRegistory;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Some basic utlility functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp {
|
||||
|
||||
/**
|
||||
* the top 32 bits of a Corda AMQP descriptor is the assigned CORDA identifier.
|
||||
*
|
||||
* Utility function to strip that off and return a simple integer that maps
|
||||
* to our described types.
|
||||
*/
|
||||
uint32_t stripCorda (uint64_t id);
|
||||
|
||||
std::string describedToString(uint64_t);
|
||||
std::string describedToString(uint32_t);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,398 @@
|
||||
#include "AMQPDescriptors.h"
|
||||
#include "AMQPDescriptorRegistory.h"
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <proton/types.h>
|
||||
#include <proton/codec.h>
|
||||
#include "colours.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "Field.h"
|
||||
#include "Schema.h"
|
||||
#include "Envelope.h"
|
||||
#include "Composite.h"
|
||||
#include "amqp/schema/restricted-types/Restricted.h"
|
||||
#include "amqp/schema/OrderedTypeNotations.h"
|
||||
#include "AMQPDescribed.h"
|
||||
|
||||
#include "proton/proton_wrapper.h"
|
||||
#include "AMQPDescriptorRegistory.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Look up a described type by its ID in the AMQPDescriptorRegistory and
|
||||
* return the coresponding schema type. Specialised below to avoid
|
||||
* the cast and re-owning of the unigue pointer when we're happy
|
||||
* with a simple std::unique_ptr<AMQPDescribed>
|
||||
*/
|
||||
template<class T>
|
||||
std::unique_ptr<T>
|
||||
dispatchDescribed (pn_data_t * data_) {
|
||||
proton::is_described(data_);
|
||||
proton::auto_enter p (data_);
|
||||
proton::is_ulong(data_);
|
||||
|
||||
auto id = pn_data_get_ulong(data_);
|
||||
|
||||
return std::unique_ptr<T> (
|
||||
static_cast<T *>(amqp::AMQPDescriptorRegistory[id]->build(data_).release()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void
|
||||
amqp::internal::
|
||||
AMQPDescriptor::validateAndNext (pn_data_t * const data_) const {
|
||||
if (pn_data_type(data_) != PN_ULONG) {
|
||||
throw std::runtime_error ("Bad type for a descriptor");
|
||||
}
|
||||
|
||||
if ( (m_val == -1)
|
||||
|| (pn_data_get_ulong(data_) != (static_cast<uint32_t>(m_val) | amqp::internal::DESCRIPTOR_TOP_32BITS)))
|
||||
{
|
||||
throw std::runtime_error ("Invalid Type");
|
||||
}
|
||||
|
||||
pn_data_next(data_);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace {
|
||||
const std::string
|
||||
consumeBlob (pn_data_t * data_) {
|
||||
proton::is_described (data_);
|
||||
proton::auto_enter p (data_);
|
||||
return proton::get_symbol<std::string> (data_);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::EnvelopeDescriptor
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
EnvelopeDescriptor::build(pn_data_t * data_) const {
|
||||
DBG ("ENVELOPE" << std::endl); // NOLINT
|
||||
|
||||
validateAndNext(data_);
|
||||
|
||||
proton::auto_enter p (data_);
|
||||
|
||||
/*
|
||||
* The actual blob... if this was java we would use the type symbols
|
||||
* in the blob to look up serialisers in the cache... but we don't
|
||||
* have any so we are actually going to need to use the schema
|
||||
* which we parse *after* this to be able to read any data!
|
||||
*/
|
||||
std::string outerType = consumeBlob(data_);
|
||||
|
||||
pn_data_next (data_);
|
||||
|
||||
/*
|
||||
* The scehama
|
||||
*/
|
||||
auto schema = dispatchDescribed<schema::Schema> (data_);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/*
|
||||
* The transforms schema
|
||||
*/
|
||||
// Skip for now
|
||||
// dispatchDescribed (data_);
|
||||
|
||||
return std::make_unique<schema::Envelope> (schema::Envelope (schema, outerType));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
SchemaDescriptor::build(pn_data_t * data_) const {
|
||||
DBG ("SCHEMA" << std::endl); // NOLINT
|
||||
|
||||
validateAndNext(data_);
|
||||
|
||||
schema::OrderedTypeNotations<schema::AMQPTypeNotation> schemas;
|
||||
|
||||
/*
|
||||
* The Schema is stored as a list of lists of described objects
|
||||
*/
|
||||
{
|
||||
proton::auto_list_enter ale (data_);
|
||||
|
||||
for (int i { 1 } ; pn_data_next(data_) ; ++i) {
|
||||
DBG (" " << i << "/" << ale.elements() << std::endl); // NOLINT
|
||||
proton::auto_list_enter ale2 (data_);
|
||||
while (pn_data_next(data_)) {
|
||||
schemas.insert (dispatchDescribed<schema::AMQPTypeNotation>(data_));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<schema::Schema> (std::move (schemas));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::ObjectDescriptor
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
ObjectDescriptor::build(pn_data_t * data_) const {
|
||||
DBG ("DESCRIPTOR" << std::endl); // NOLINT
|
||||
|
||||
validateAndNext(data_);
|
||||
|
||||
proton::auto_enter p (data_);
|
||||
|
||||
auto symbol = proton::get_symbol<std::string> (data_);
|
||||
|
||||
return std::make_unique<schema::Descriptor> (symbol);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::FieldDescriptor
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
FieldDescriptor::build(pn_data_t * data_) const {
|
||||
DBG ("FIELD" << std::endl); // NOLINT
|
||||
|
||||
validateAndNext(data_);
|
||||
|
||||
proton::auto_enter ae (data_);
|
||||
|
||||
/* name: String */
|
||||
auto name = proton::get_string(data_);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* type: String */
|
||||
auto type = proton::get_string(data_);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* requires: List<String> */
|
||||
std::list<std::string> requires;
|
||||
{
|
||||
proton::auto_list_enter ale (data_);
|
||||
while (pn_data_next(data_)) {
|
||||
requires.push_back (proton::get_string(data_));
|
||||
}
|
||||
}
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* default: String? */
|
||||
auto def = proton::get_string(data_, true);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* label: String? */
|
||||
auto label = proton::get_string(data_, true);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* mandatory: Boolean - copes with the Kotlin concept of nullability.
|
||||
If something is mandatory then it cannot be null */
|
||||
auto mandatory = proton::get_boolean(data_);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* multiple: Boolean */
|
||||
auto multiple = proton::get_boolean(data_);
|
||||
|
||||
return std::make_unique<schema::Field> (name, type, requires, def, label,
|
||||
mandatory, multiple);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::CompositeDescriptor
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
CompositeDescriptor::build(pn_data_t * data_) const {
|
||||
DBG ("COMPOSITE" << std::endl); // NOLINT
|
||||
|
||||
validateAndNext(data_);
|
||||
|
||||
proton::auto_enter p (data_);
|
||||
|
||||
/* Class Name - String */
|
||||
auto name = proton::get_string(data_);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* Label Name - Nullable String */
|
||||
auto label = proton::get_string(data_, true);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* provides: List<String> */
|
||||
std::list<std::string> provides;
|
||||
{
|
||||
proton::auto_list_enter p2 (data_);
|
||||
while (pn_data_next(data_)) {
|
||||
provides.push_back (proton::get_string (data_));
|
||||
}
|
||||
}
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* descriptor: Descriptor */
|
||||
auto descriptor = dispatchDescribed<schema::Descriptor>(data_);
|
||||
|
||||
pn_data_next(data_);
|
||||
|
||||
/* fields: List<Described>*/
|
||||
std::vector<std::unique_ptr<schema::Field>> fields;
|
||||
fields.reserve (pn_data_get_list (data_));
|
||||
{
|
||||
proton::auto_list_enter p2 (data_);
|
||||
while (pn_data_next(data_)) {
|
||||
fields.emplace_back (dispatchDescribed<schema::Field>(data_));
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<schema::Composite> (
|
||||
schema::Composite (name, label, provides, descriptor, fields));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Restricted types represent lists and maps
|
||||
*
|
||||
* NOTE: The Corda serialization scheme doesn't support all container classes
|
||||
* as it has the requiremnt that iteration order be deterministic for purposes
|
||||
* of signing over data.
|
||||
*
|
||||
* name : String
|
||||
* label : String?
|
||||
* provides : List<String>
|
||||
* source : String
|
||||
* descriptor : Descriptor
|
||||
* choices : List<Choice>
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
RestrictedDescriptor::build(pn_data_t * data_) const {
|
||||
DBG ("RESTRICTED" << std::endl); // NOLINT
|
||||
validateAndNext(data_);
|
||||
|
||||
proton::auto_enter ae (data_);
|
||||
|
||||
auto name = proton::readAndNext<std::string>(data_);
|
||||
auto label = proton::readAndNext<std::string>(data_, true);
|
||||
|
||||
std::vector<std::string> provides;
|
||||
{
|
||||
proton::auto_list_enter ae2 (data_);
|
||||
while (pn_data_next(data_)) {
|
||||
provides.push_back (proton::get_string (data_));
|
||||
}
|
||||
}
|
||||
|
||||
pn_data_next (data_);
|
||||
|
||||
auto source = proton::readAndNext<std::string>(data_);
|
||||
auto descriptor = dispatchDescribed<schema::Descriptor>(data_);
|
||||
|
||||
// SKIP the choices section **FOR NOW**
|
||||
|
||||
return schema::Restricted::make (descriptor, name,
|
||||
label, provides, source);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Essentially, an enum.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
ChoiceDescriptor::build(pn_data_t * data_) const {
|
||||
validateAndNext(data_);
|
||||
|
||||
DBG ("CHOICE " << data_ << std::endl); // NOLINT
|
||||
|
||||
return std::unique_ptr<amqp::internal::AMQPDescribed> (nullptr);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
ReferencedObjectDescriptor::build(pn_data_t * data_) const {
|
||||
validateAndNext(data_);
|
||||
|
||||
DBG ("REFERENCED OBJECT " << data_ << std::endl); // NOLINT
|
||||
|
||||
return std::unique_ptr<amqp::internal::AMQPDescribed> (nullptr);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
TransformSchemaDescriptor::build(pn_data_t * data_) const {
|
||||
validateAndNext(data_);
|
||||
|
||||
DBG ("TRANSFORM SCHEMA " << data_ << std::endl); // NOLINT
|
||||
|
||||
return std::unique_ptr<amqp::internal::AMQPDescribed> (nullptr);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
TransformElementDescriptor::build(pn_data_t * data_) const {
|
||||
validateAndNext(data_);
|
||||
|
||||
DBG ("TRANSFORM ELEMENT " << data_ << std::endl); // NOLINT
|
||||
|
||||
return std::unique_ptr<amqp::internal::AMQPDescribed> (nullptr);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::unique_ptr<amqp::internal::AMQPDescribed>
|
||||
amqp::internal::
|
||||
TransformElementKeyDescriptor::build(pn_data_t * data_) const {
|
||||
validateAndNext(data_);
|
||||
|
||||
DBG ("TRANSFORM ELEMENT KEY" << data_ << std::endl); // NOLINT
|
||||
|
||||
return std::unique_ptr<amqp::internal::AMQPDescribed> (nullptr);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
@ -0,0 +1,228 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
#include "amqp/AMQPDescriptor.h"
|
||||
#include "amqp/schema/Descriptor.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
struct pn_data_t;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp:: internal {
|
||||
|
||||
class EnvelopeDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
EnvelopeDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
EnvelopeDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~EnvelopeDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class SchemaDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
SchemaDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
SchemaDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~SchemaDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class ObjectDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
ObjectDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
ObjectDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~ObjectDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class FieldDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
FieldDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
FieldDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~FieldDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class CompositeDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
CompositeDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
CompositeDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~CompositeDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class RestrictedDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
RestrictedDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
RestrictedDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~RestrictedDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class ChoiceDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
ChoiceDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
ChoiceDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~ChoiceDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class ReferencedObjectDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
ReferencedObjectDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
ReferencedObjectDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~ReferencedObjectDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class TransformSchemaDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
TransformSchemaDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
TransformSchemaDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~TransformSchemaDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class TransformElementDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
TransformElementDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
TransformElementDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~TransformElementDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal {
|
||||
|
||||
class TransformElementKeyDescriptor : public AMQPDescriptor {
|
||||
public :
|
||||
TransformElementKeyDescriptor() : AMQPDescriptor() { }
|
||||
|
||||
TransformElementKeyDescriptor(const std::string & symbol_, int val_)
|
||||
: AMQPDescriptor(symbol_, val_)
|
||||
{ }
|
||||
|
||||
~TransformElementKeyDescriptor() final = default;
|
||||
|
||||
std::unique_ptr<AMQPDescribed> build (pn_data_t *) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
@ -0,0 +1,62 @@
|
||||
#include <iostream>
|
||||
#include "AMQPTypeNotation.h"
|
||||
|
||||
#include "colours.h"
|
||||
|
||||
#include "Composite.h"
|
||||
#include "amqp/schema/restricted-types/Restricted.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
/**
|
||||
* Provide nice mechanism by which Composite and Restricted types, both
|
||||
* derived types of [AMQPTypeNotation], can be printed
|
||||
*
|
||||
* @param stream_ where the output should go
|
||||
* @param clazz_ what we want to print
|
||||
* @return the stream to allow proper io chaining
|
||||
*/
|
||||
std::ostream &
|
||||
operator << (std::ostream & stream_, const AMQPTypeNotation & clazz_) {
|
||||
switch (clazz_.type()) {
|
||||
case AMQPTypeNotation::Type::Composite : {
|
||||
stream_ << dynamic_cast<const Composite &>(clazz_);
|
||||
break;
|
||||
}
|
||||
case AMQPTypeNotation::Type::Restricted : {
|
||||
stream_ << dynamic_cast<const Restricted &>(clazz_);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::schema::AMQPTypeNotation
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
AMQPTypeNotation::descriptor() const {
|
||||
return m_descriptor->name();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
AMQPTypeNotation::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <memory>
|
||||
#include <types.h>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include "Descriptor.h"
|
||||
#include "OrderedTypeNotations.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Forward class declarations
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class Restricted;
|
||||
class Composite;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class AMQPTypeNotation : public AMQPDescribed, public OrderedTypeNotation {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const AMQPTypeNotation &);
|
||||
|
||||
enum Type { Composite, Restricted };
|
||||
|
||||
private :
|
||||
std::string m_name;
|
||||
std::unique_ptr<Descriptor> m_descriptor;
|
||||
|
||||
public :
|
||||
AMQPTypeNotation (
|
||||
const std::string & name_,
|
||||
std::unique_ptr<Descriptor> & descriptor_
|
||||
) : m_name (name_)
|
||||
, m_descriptor (std::move(descriptor_))
|
||||
{ }
|
||||
|
||||
const std::string & descriptor() const;
|
||||
|
||||
const std::string & name() const;
|
||||
|
||||
virtual Type type() const = 0;
|
||||
|
||||
int dependsOn (const OrderedTypeNotation &) const override = 0;
|
||||
virtual int dependsOn (const class Restricted &) const = 0;
|
||||
virtual int dependsOn (const class Composite &) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
148
experimental/cpp-serializer/src/amqp/schema/Composite.cxx
Normal file
148
experimental/cpp-serializer/src/amqp/schema/Composite.cxx
Normal file
@ -0,0 +1,148 @@
|
||||
#include "Composite.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "colours.h"
|
||||
|
||||
#include "amqp/schema/restricted-types/Restricted.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream & stream_, const Composite & clazz_) {
|
||||
stream_
|
||||
<< "name : " << clazz_.name() << std::endl
|
||||
<< "label : " << clazz_.m_label << std::endl
|
||||
<< "descriptor : " << clazz_.descriptor() << std::endl
|
||||
<< "fields : ";
|
||||
|
||||
for (auto const & i : clazz_.m_fields) stream_ << *i << std::setw (13) << " ";
|
||||
stream_ << std::setw(0);
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::schema::Composite
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
Composite::Composite (
|
||||
const std::string & name_,
|
||||
std::string label_,
|
||||
const std::list<std::string> & provides_,
|
||||
std::unique_ptr<Descriptor> & descriptor_,
|
||||
std::vector<std::unique_ptr<Field>> & fields_
|
||||
) : AMQPTypeNotation (name_, descriptor_)
|
||||
, m_label (std::move (label_))
|
||||
, m_provides (provides_)
|
||||
, m_fields (std::move (fields_))
|
||||
{ }
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::vector<std::unique_ptr<amqp::internal::schema::Field>> &
|
||||
amqp::internal::schema::
|
||||
Composite::fields() const {
|
||||
return m_fields;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::AMQPTypeNotation::Type
|
||||
amqp::internal::schema::
|
||||
Composite::type() const {
|
||||
return AMQPTypeNotation::Type::Composite;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* Use a visitor style pattern to work out weather two types, composite or
|
||||
* restricted, are "less than" one or not. In this case we define being
|
||||
* "less than" not having a type that the other depends on. This will
|
||||
* eventually give us a set ordered in such a way we can simply create
|
||||
* each element in turn
|
||||
*
|
||||
* "...This object determines the order of the elements in the container: it is
|
||||
* a function pointer or a function object that takes two arguments of the same
|
||||
* type as the container elements, and returns true if the first argument is
|
||||
* considered to go before the second in the strict weak ordering it defines,
|
||||
* and false otherwise. ..."
|
||||
|
||||
*
|
||||
* @param rhs
|
||||
* @return
|
||||
*/
|
||||
int
|
||||
amqp::internal::schema::
|
||||
Composite::dependsOn (const OrderedTypeNotation & rhs) const {
|
||||
return dynamic_cast<const AMQPTypeNotation &>(rhs).dependsOn(*this);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int
|
||||
amqp::internal::schema::
|
||||
Composite::dependsOn (const amqp::internal::schema::Restricted & lhs_) const {
|
||||
// does the left hand side depend on us
|
||||
auto rtn { 0 };
|
||||
|
||||
for (const auto i : lhs_) {
|
||||
DBG (" C/R a) " << i << " == " << name() << std::endl); // NOLINT
|
||||
if (i == name()) {
|
||||
rtn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// does this depend on the left hand side
|
||||
for (auto const & field : m_fields) {
|
||||
DBG (" C/R b) " << field->resolvedType() << " == " << lhs_.name() << std::endl); // NOLINT
|
||||
|
||||
if (field->resolvedType() == lhs_.name()) {
|
||||
rtn = 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/*********************************************************o*********************/
|
||||
|
||||
int
|
||||
amqp::internal::schema::
|
||||
Composite::dependsOn (const amqp::internal::schema::Composite & lhs_) const {
|
||||
auto rtn { 0 };
|
||||
|
||||
// do we depend on the lhs, i.e. is one of our fields it
|
||||
for (auto const & field : lhs_) {
|
||||
DBG (" C/C a) " << field->resolvedType() << " == " << name() << std::endl); // NOLINT
|
||||
if (field->resolvedType() == name()) {
|
||||
rtn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// does the left hand side depend on us. i.e. is one of it's fields
|
||||
// us
|
||||
for (const auto & field : m_fields) {
|
||||
DBG (" C/C b) " << field->resolvedType() << " == " << lhs_.name() << std::endl); // NOLINT
|
||||
|
||||
if (field->resolvedType() == lhs_.name()) {
|
||||
rtn = 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
85
experimental/cpp-serializer/src/amqp/schema/Composite.h
Normal file
85
experimental/cpp-serializer/src/amqp/schema/Composite.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <types.h>
|
||||
|
||||
#include "Field.h"
|
||||
#include "Descriptor.h"
|
||||
#include "AMQPTypeNotation.h"
|
||||
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Forward class declarations
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class Restricted;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
/*
|
||||
* A Corda AMQP Schema Composite type has:
|
||||
*
|
||||
* val name: String,
|
||||
* val label: String?,
|
||||
* val provides: List<String>,
|
||||
* val descriptor: Descriptor,
|
||||
* val fields: List<Field>
|
||||
*/
|
||||
class Composite : public AMQPTypeNotation {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const Composite&);
|
||||
|
||||
private :
|
||||
// could be null in the stream... not sure that information is
|
||||
// worth preserving beyond an empty string here.
|
||||
std::string m_label;
|
||||
|
||||
// interfaces the class implements... again since we can't
|
||||
// use Karen to dynamically construct a class
|
||||
// we don't know about knowing the interfaces (java concept)
|
||||
// that this class implemented isn't al that useful but we'll
|
||||
// at least preserve the list
|
||||
std::list<std::string> m_provides;
|
||||
|
||||
/**
|
||||
* The properties of the Class
|
||||
*/
|
||||
std::vector<std::unique_ptr<Field>> m_fields;
|
||||
|
||||
public :
|
||||
Composite (
|
||||
const std::string & name_,
|
||||
std::string label_,
|
||||
const std::list<std::string> & provides_,
|
||||
std::unique_ptr<Descriptor> & descriptor_,
|
||||
std::vector<std::unique_ptr<Field>> & fields_);
|
||||
|
||||
const std::vector<std::unique_ptr<Field>> & fields() const;
|
||||
|
||||
Type type() const override;
|
||||
|
||||
int dependsOn (const OrderedTypeNotation &) const override;
|
||||
int dependsOn (const class Restricted &) const override;
|
||||
int dependsOn (const Composite &) const override;
|
||||
|
||||
decltype(m_fields)::const_iterator begin() const { return m_fields.cbegin();}
|
||||
decltype(m_fields)::const_iterator end() const { return m_fields.cend(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
34
experimental/cpp-serializer/src/amqp/schema/Descriptor.cxx
Normal file
34
experimental/cpp-serializer/src/amqp/schema/Descriptor.cxx
Normal file
@ -0,0 +1,34 @@
|
||||
#include "Descriptor.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream & stream_, const Descriptor & desc_) {
|
||||
stream_ << desc_.m_name;
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Descriptor Implementation
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
Descriptor::Descriptor (std::string name_)
|
||||
: m_name (std::move (name_))
|
||||
{ }
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
Descriptor::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
32
experimental/cpp-serializer/src/amqp/schema/Descriptor.h
Normal file
32
experimental/cpp-serializer/src/amqp/schema/Descriptor.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class Descriptor : public AMQPDescribed {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const Descriptor&);
|
||||
|
||||
private :
|
||||
std::string m_name;
|
||||
|
||||
public :
|
||||
Descriptor() = default;
|
||||
|
||||
explicit Descriptor (std::string);
|
||||
|
||||
const std::string & name() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
50
experimental/cpp-serializer/src/amqp/schema/Envelope.cxx
Normal file
50
experimental/cpp-serializer/src/amqp/schema/Envelope.cxx
Normal file
@ -0,0 +1,50 @@
|
||||
#include "Envelope.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (
|
||||
std::ostream & stream_,
|
||||
const amqp::internal::schema::Envelope & e_
|
||||
) {
|
||||
stream_ << *(e_.m_schema);
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::schema::Envelope
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
Envelope::Envelope (
|
||||
std::unique_ptr<Schema> & schema_,
|
||||
std::string descriptor_
|
||||
) : m_schema (std::move (schema_))
|
||||
, m_descriptor (std::move (descriptor_))
|
||||
{ }
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::unique_ptr<amqp::internal::schema::Schema> &
|
||||
amqp::internal::schema::
|
||||
Envelope::schema() const {
|
||||
return m_schema;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
Envelope::descriptor() const {
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
38
experimental/cpp-serializer/src/amqp/schema/Envelope.h
Normal file
38
experimental/cpp-serializer/src/amqp/schema/Envelope.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
|
||||
#include "Schema.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class Envelope : public AMQPDescribed {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const Envelope &);
|
||||
|
||||
private :
|
||||
std::unique_ptr<Schema> m_schema;
|
||||
std::string m_descriptor;
|
||||
|
||||
public :
|
||||
Envelope() = delete;
|
||||
|
||||
Envelope (
|
||||
std::unique_ptr<Schema> & schema_,
|
||||
std::string descriptor_);
|
||||
|
||||
const std::unique_ptr<Schema> & schema() const;
|
||||
|
||||
const std::string & descriptor() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
109
experimental/cpp-serializer/src/amqp/schema/Field.cxx
Normal file
109
experimental/cpp-serializer/src/amqp/schema/Field.cxx
Normal file
@ -0,0 +1,109 @@
|
||||
#include "Field.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream & stream_, const Field & field_) {
|
||||
std::stringstream ss;
|
||||
for (auto &i: field_.m_requires) { ss << i; }
|
||||
|
||||
stream_ << field_.m_name << " : " << field_.m_type.first << " : [" << ss.str() << "]" << std::endl;
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
Field::Field (
|
||||
const std::string & name_,
|
||||
const std::string & type_,
|
||||
const std::list<std::string> & requires_,
|
||||
const std::string & default_,
|
||||
const std::string & label_,
|
||||
bool mandatory_,
|
||||
bool multiple_
|
||||
) : m_name (name_)
|
||||
, m_requires (requires_)
|
||||
, m_default (default_)
|
||||
, m_label (label_)
|
||||
, m_mandatory (mandatory_)
|
||||
, m_multiple (multiple_)
|
||||
{
|
||||
if (typeIsPrimitive(type_)) {
|
||||
m_type = std::make_pair(type_, FieldType::PrimitiveProperty);
|
||||
} else if (type_ == "*") {
|
||||
m_type = std::make_pair(type_, FieldType::RestrictedProperty);
|
||||
} else {
|
||||
m_type = std::make_pair(type_, FieldType::CompositeProperty);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
bool
|
||||
amqp::internal::schema::
|
||||
Field::typeIsPrimitive(const std::string & type_) {
|
||||
return (type_ == "string" ||
|
||||
type_ == "long" ||
|
||||
type_ == "boolean" ||
|
||||
type_ == "int" ||
|
||||
type_ == "double");
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
Field::name() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
Field::type() const {
|
||||
return m_type.first;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
Field::resolvedType() const {
|
||||
return (type() == "*") ? requires().front() : type();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::FieldType
|
||||
amqp::internal::schema::
|
||||
Field::fieldType() const {
|
||||
return m_type.second;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::list<std::string> &
|
||||
amqp::internal::schema::
|
||||
Field::requires() const {
|
||||
return m_requires;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
bool
|
||||
amqp::internal::schema::
|
||||
Field::primitive() const {
|
||||
return m_type.second == PrimitiveProperty;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
63
experimental/cpp-serializer/src/amqp/schema/Field.h
Normal file
63
experimental/cpp-serializer/src/amqp/schema/Field.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
/******************************************************************************/
|
||||
|
||||
#include "Descriptor.h"
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
enum FieldType { PrimitiveProperty, CompositeProperty, RestrictedProperty };
|
||||
|
||||
/**
|
||||
*
|
||||
* A Corda AMQP Scehma Field type has:
|
||||
* - name : String
|
||||
* - type : String
|
||||
* - requires : List<String>
|
||||
* - default : nullable String
|
||||
* - label : nullable String
|
||||
* - mandatory : Boolean
|
||||
* - multiple : Boolean
|
||||
*/
|
||||
class Field : public AMQPDescribed {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const Field &);
|
||||
|
||||
static bool typeIsPrimitive(const std::string &);
|
||||
|
||||
private :
|
||||
std::string m_name;
|
||||
std::pair<std::string, FieldType> m_type;
|
||||
std::list<std::string> m_requires;
|
||||
std::string m_default;
|
||||
std::string m_label;
|
||||
bool m_mandatory;
|
||||
bool m_multiple;
|
||||
|
||||
public :
|
||||
Field (const std::string & name_,
|
||||
const std::string & type_,
|
||||
const std::list<std::string> & requires_,
|
||||
const std::string & default_,
|
||||
const std::string & label_,
|
||||
bool mandatory_,
|
||||
bool multiple_);
|
||||
|
||||
const std::string & name() const;
|
||||
const std::string & type() const;
|
||||
const std::string & resolvedType() const;
|
||||
FieldType fieldType() const;
|
||||
const std::list<std::string> & requires() const;
|
||||
bool primitive() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,206 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <ostream>
|
||||
#include <iostream>
|
||||
|
||||
#include "types.h"
|
||||
#include "colours.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Forward declarations
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
template<class T>
|
||||
class OrderedTypeNotations;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::ostream & operator << (
|
||||
std::ostream &,
|
||||
const amqp::internal::schema::OrderedTypeNotations<T> &);
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* OrderedTypeNotation
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class OrderedTypeNotation {
|
||||
public :
|
||||
virtual ~OrderedTypeNotation() = default;
|
||||
|
||||
virtual int dependsOn (const OrderedTypeNotation &) const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
template<class T>
|
||||
class OrderedTypeNotations {
|
||||
private:
|
||||
std::list<std::list<uPtr<T>>> m_schemas;
|
||||
|
||||
public :
|
||||
typedef decltype(m_schemas.begin()) iterator;
|
||||
|
||||
private:
|
||||
void insert (uPtr<T> &&, iterator);
|
||||
void insertNewList (uPtr<T> &&);
|
||||
void insertNewList (
|
||||
uPtr<T> &&,
|
||||
typename std::list<std::list<uPtr<T>>>::iterator &);
|
||||
|
||||
public :
|
||||
void insert(uPtr<T> && ptr);
|
||||
|
||||
friend std::ostream & ::operator << <> (
|
||||
std::ostream &,
|
||||
const amqp::internal::schema::OrderedTypeNotations<T> &);
|
||||
|
||||
decltype (m_schemas.crbegin()) begin() const {
|
||||
return m_schemas.crbegin();
|
||||
}
|
||||
|
||||
decltype (m_schemas.crend()) end() const {
|
||||
return m_schemas.crend();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
template<class T>
|
||||
std::ostream &
|
||||
operator << (
|
||||
std::ostream &stream_,
|
||||
const amqp::internal::schema::OrderedTypeNotations<T> &otn_
|
||||
) {
|
||||
int idx1{0};
|
||||
for (const auto &i : otn_.m_schemas) {
|
||||
stream_ << "level " << ++idx1 << std::endl;
|
||||
for (const auto &j : i) {
|
||||
stream_ << " * " << j->name() << std::endl;
|
||||
}
|
||||
stream_ << std::endl;
|
||||
}
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
template<class T>
|
||||
void
|
||||
amqp::internal::schema::
|
||||
OrderedTypeNotations<T>::insertNewList(uPtr<T> && ptr) {
|
||||
std::list<uPtr<T>> l;
|
||||
l.emplace_back (std::move (ptr));
|
||||
m_schemas.emplace_back(std::move (l));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* This could be a bit more space efficient by checking the previous element
|
||||
* for dependendies again as its possible we are moving multiple elements "up"
|
||||
* but the extra checks probably don't make it worth it.
|
||||
*/
|
||||
template<class T>
|
||||
void
|
||||
amqp::internal::schema::
|
||||
OrderedTypeNotations<T>::insertNewList(
|
||||
uPtr<T> && ptr,
|
||||
typename std::list<std::list<uPtr<T>>>::iterator & here_)
|
||||
{
|
||||
std::list<uPtr<T>> l;
|
||||
l.emplace_back (std::move (ptr));
|
||||
m_schemas.insert(here_, std::move (l));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
template<class T>
|
||||
void
|
||||
amqp::internal::schema::
|
||||
OrderedTypeNotations<T>::insert (uPtr<T> && ptr) {
|
||||
return insert (std::move (ptr), m_schemas.begin());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
template<class T>
|
||||
void
|
||||
amqp::internal::schema::
|
||||
OrderedTypeNotations<T>::insert (
|
||||
uPtr<T> && ptr,
|
||||
amqp::internal::schema::OrderedTypeNotations<T>::iterator l_
|
||||
) {
|
||||
/*
|
||||
* First we find where this element needs to be added
|
||||
*/
|
||||
amqp::internal::schema::OrderedTypeNotations<T>::iterator insertionPoint { l_ };
|
||||
|
||||
for (auto i = l_ ; i != m_schemas.end() ; ++i) {
|
||||
for (const auto & j : *i) {
|
||||
/*
|
||||
* A score of 0 means no dependencies at all
|
||||
* A score of 1 means "j" has a dependency on what's being inserted
|
||||
* A score of 2 means what's being inserted depends on "j"
|
||||
*/
|
||||
auto score = j->dependsOn(*ptr);
|
||||
|
||||
if (score == 1) {
|
||||
insertionPoint = std::next(i);
|
||||
} else if (score == 2) {
|
||||
insertionPoint = i;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
done:
|
||||
|
||||
/*
|
||||
* Now we insert it and work out if anything requires shuffling
|
||||
*/
|
||||
if (insertionPoint == m_schemas.end()) {
|
||||
insertNewList (std::move(ptr));
|
||||
} else {
|
||||
const auto & insertedPtr = insertionPoint->emplace_front (std::move(ptr));
|
||||
|
||||
for (auto j = std::next (insertionPoint->begin()) ; j != insertionPoint->end() ; ) {
|
||||
auto toErase = j++;
|
||||
|
||||
auto score { insertedPtr->dependsOn (**toErase) };
|
||||
|
||||
if (score > 0) {
|
||||
uPtr<T> tmpPtr{std::move(*toErase)};
|
||||
insertionPoint->erase (toErase);
|
||||
switch (score) {
|
||||
// Needs to go after the element we're adding
|
||||
case 1: {
|
||||
insert(std::move(tmpPtr), std::next(insertionPoint));
|
||||
break;
|
||||
}
|
||||
// Needs to go before the element we're adding
|
||||
case 2: {
|
||||
insertNewList (std::move(tmpPtr), insertionPoint);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
75
experimental/cpp-serializer/src/amqp/schema/Schema.cxx
Normal file
75
experimental/cpp-serializer/src/amqp/schema/Schema.cxx
Normal file
@ -0,0 +1,75 @@
|
||||
|
||||
#include "Schema.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Non member related functions
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (std::ostream & stream_, const Schema & schema_) {
|
||||
|
||||
for (auto i { schema_.m_types.begin() } ; i != schema_.m_types.end() ; ++i) {
|
||||
for (auto & j : *i) {
|
||||
stream_ << j->name() << " " << j->type() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::schema::Schema
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
Schema::Schema (
|
||||
OrderedTypeNotations<AMQPTypeNotation> types_
|
||||
) : m_types (std::move (types_)) {
|
||||
for (auto i { m_types.begin() } ; i != m_types.end() ; ++i) {
|
||||
for (auto & j : *i) {
|
||||
DBG ("Schema: " << j->descriptor() << " " << j->name() << std::endl); // NOLINT
|
||||
m_descriptorToType.emplace(j->descriptor(), std::ref (j));
|
||||
m_typeToDescriptor.emplace(j->name(), std::ref (j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const amqp::internal::schema::OrderedTypeNotations<amqp::internal::schema::AMQPTypeNotation> &
|
||||
amqp::internal::schema::
|
||||
Schema::types() const {
|
||||
return m_types;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::Schema::SchemaMap::const_iterator
|
||||
amqp::internal::schema::
|
||||
Schema::fromType (const std::string & type_) const {
|
||||
return m_typeToDescriptor.find(type_);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::Schema::SchemaMap::const_iterator
|
||||
amqp::internal::schema::
|
||||
Schema::fromDescriptor (const std::string & descriptor_) const {
|
||||
return m_descriptorToType.find (descriptor_);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
63
experimental/cpp-serializer/src/amqp/schema/Schema.h
Normal file
63
experimental/cpp-serializer/src/amqp/schema/Schema.h
Normal file
@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <iosfwd>
|
||||
|
||||
#include "types.h"
|
||||
#include "Composite.h"
|
||||
#include "Descriptor.h"
|
||||
#include "OrderedTypeNotations.h"
|
||||
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
typedef std::function <bool(const uPtr<AMQPTypeNotation> &, const uPtr<AMQPTypeNotation> &)> const SetSort;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
/*
|
||||
*/
|
||||
class Schema : public AMQPDescribed {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const Schema &);
|
||||
|
||||
typedef std::map<std::string, const std::reference_wrapper<const uPtr<AMQPTypeNotation>>> SchemaMap;
|
||||
|
||||
private :
|
||||
OrderedTypeNotations<AMQPTypeNotation> m_types;
|
||||
SchemaMap m_descriptorToType;
|
||||
SchemaMap m_typeToDescriptor;
|
||||
|
||||
public :
|
||||
Schema (OrderedTypeNotations<AMQPTypeNotation> types_);
|
||||
|
||||
const OrderedTypeNotations<AMQPTypeNotation> & types() const;
|
||||
|
||||
SchemaMap::const_iterator fromType (const std::string &) const;
|
||||
SchemaMap::const_iterator fromDescriptor (const std::string &) const;
|
||||
|
||||
decltype(m_types.begin()) begin() const { return m_types.begin(); }
|
||||
decltype(m_types.end()) end() const { return m_types.end(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -0,0 +1,116 @@
|
||||
#include <iostream>
|
||||
#include "List.h"
|
||||
|
||||
#include "debug.h"
|
||||
#include "colours.h"
|
||||
|
||||
#include "schema/Composite.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
std::pair<std::string, std::string>
|
||||
listType (const std::string & list_) {
|
||||
auto pos = list_.find ('<');
|
||||
|
||||
return std::make_pair (
|
||||
std::string { list_.substr (0, pos) },
|
||||
std::string { list_.substr(pos + 1, list_.size() - pos - 2) }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
List::List (
|
||||
uPtr<Descriptor> & descriptor_,
|
||||
const std::string & name_,
|
||||
const std::string & label_,
|
||||
const std::vector<std::string> & provides_,
|
||||
const std::string & source_
|
||||
) : Restricted (
|
||||
descriptor_,
|
||||
name_,
|
||||
label_,
|
||||
provides_,
|
||||
amqp::internal::schema::Restricted::RestrictedTypes::List)
|
||||
, m_listOf { listType(name_).second }
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::vector<std::string>::const_iterator
|
||||
amqp::internal::schema::
|
||||
List::begin() const {
|
||||
return m_listOf.begin();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
std::vector<std::string>::const_iterator
|
||||
amqp::internal::schema::
|
||||
List::end() const {
|
||||
return m_listOf.end();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
const std::string &
|
||||
amqp::internal::schema::
|
||||
List::listOf() const {
|
||||
return m_listOf[0];
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int
|
||||
amqp::internal::schema::
|
||||
List::dependsOn (const amqp::internal::schema::Restricted & lhs_) const {
|
||||
auto rtn { 0 };
|
||||
switch (lhs_.restrictedType()) {
|
||||
case RestrictedTypes::List : {
|
||||
const auto & list { dynamic_cast<const List &>(lhs_) };
|
||||
|
||||
// does the left hand side depend on us
|
||||
DBG (" L/L a) " << list.listOf() << " == " << name() << std::endl); // NOLINT
|
||||
if (list.listOf() == name()) {
|
||||
rtn = 1;
|
||||
}
|
||||
|
||||
// do we depend on the lhs
|
||||
DBG (" L/L b) " << listOf() << " == " << list.name() << std::endl); // NOLINT
|
||||
if (listOf() == list.name()) {
|
||||
rtn = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int
|
||||
amqp::internal::schema::
|
||||
List::dependsOn (const amqp::internal::schema::Composite & lhs_) const {
|
||||
auto rtn { 0 };
|
||||
for (const auto & field : lhs_.fields()) {
|
||||
DBG (" L/C a) " << field->resolvedType() << " == " << name() << std::endl); // NOLINT
|
||||
if (field->resolvedType() == name()) {
|
||||
rtn = 1;
|
||||
}
|
||||
}
|
||||
|
||||
DBG (" L/C b) " << listOf() << " == " << lhs_.name() << std::endl); // NOLINT
|
||||
if (listOf() == lhs_.name()) {
|
||||
rtn = 2;
|
||||
}
|
||||
|
||||
return rtn;
|
||||
}
|
||||
|
||||
/*********************************************************o*********************/
|
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "Restricted.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class List : public Restricted {
|
||||
private :
|
||||
std::vector<std::string> m_listOf;
|
||||
|
||||
public :
|
||||
List (
|
||||
uPtr<Descriptor> & descriptor_,
|
||||
const std::string &,
|
||||
const std::string &,
|
||||
const std::vector<std::string> &,
|
||||
const std::string &);
|
||||
|
||||
std::vector<std::string>::const_iterator begin() const override;
|
||||
std::vector<std::string>::const_iterator end() const override;
|
||||
|
||||
const std::string & listOf() const;
|
||||
|
||||
int dependsOn (const Restricted &) const override;
|
||||
int dependsOn (const class Composite &) const override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
@ -0,0 +1,131 @@
|
||||
#include "Restricted.h"
|
||||
#include "List.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (
|
||||
std::ostream & stream_,
|
||||
const amqp::internal::schema::Restricted & clazz_)
|
||||
{
|
||||
stream_
|
||||
<< "name : " << clazz_.name() << std::endl
|
||||
<< "label : " << clazz_.m_label << std::endl
|
||||
<< "descriptor : " << clazz_.descriptor() << std::endl
|
||||
<< "source : " << clazz_.m_source << std::endl
|
||||
<< "provides : [" << std::endl;
|
||||
|
||||
for (auto & provides : clazz_.m_provides) {
|
||||
stream_ << " " << provides << std::endl;
|
||||
}
|
||||
stream_<< " ]" << std::endl;
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
std::ostream &
|
||||
operator << (
|
||||
std::ostream & stream_,
|
||||
const amqp::internal::schema::Restricted::RestrictedTypes & type_)
|
||||
{
|
||||
switch (type_) {
|
||||
case Restricted::RestrictedTypes::List : {
|
||||
stream_ << "list";
|
||||
break;
|
||||
}
|
||||
case Restricted::RestrictedTypes::Map : {
|
||||
stream_ << "map";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* amqp::internal::schema::Restricted
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/**
|
||||
* Named constructor
|
||||
*
|
||||
* @param descriptor_
|
||||
* @param name_
|
||||
* @param label_
|
||||
* @param provides_
|
||||
* @param source_
|
||||
* @return
|
||||
*/
|
||||
std::unique_ptr<amqp::internal::schema::Restricted>
|
||||
amqp::internal::schema::
|
||||
Restricted::make(
|
||||
uPtr<Descriptor> & descriptor_,
|
||||
const std::string & name_,
|
||||
const std::string & label_,
|
||||
const std::vector<std::string> & provides_,
|
||||
const std::string & source_)
|
||||
{
|
||||
if (source_ == "list") {
|
||||
return std::make_unique<amqp::internal::schema::List> (
|
||||
descriptor_, name_, label_, provides_, source_);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::
|
||||
Restricted::Restricted (
|
||||
uPtr<Descriptor> & descriptor_,
|
||||
const std::string & name_,
|
||||
std::string label_,
|
||||
const std::vector<std::string> & provides_,
|
||||
const amqp::internal::schema::Restricted::RestrictedTypes & source_
|
||||
) : AMQPTypeNotation (name_, descriptor_)
|
||||
, m_label (std::move (label_))
|
||||
, m_provides (provides_)
|
||||
, m_source (source_)
|
||||
{
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::AMQPTypeNotation::Type
|
||||
amqp::internal::schema::
|
||||
Restricted::type() const {
|
||||
return AMQPTypeNotation::Type::Restricted;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
amqp::internal::schema::Restricted::RestrictedTypes
|
||||
amqp::internal::schema::
|
||||
Restricted::restrictedType() const {
|
||||
return m_source;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int
|
||||
amqp::internal::schema::
|
||||
Restricted::dependsOn (const OrderedTypeNotation & rhs_) const {
|
||||
return dynamic_cast<const AMQPTypeNotation &>(rhs_).dependsOn(*this);
|
||||
}
|
||||
|
||||
/*********************************************************o*********************/
|
||||
|
@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "Field.h"
|
||||
#include "Descriptor.h"
|
||||
#include "AMQPTypeNotation.h"
|
||||
|
||||
#include "amqp/AMQPDescribed.h"
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* Forward class declarations
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class Composite;
|
||||
class OrderedTypeNotation;
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace amqp::internal::schema {
|
||||
|
||||
class Restricted : public AMQPTypeNotation {
|
||||
public :
|
||||
friend std::ostream & operator << (std::ostream &, const Restricted&);
|
||||
|
||||
enum RestrictedTypes { List, Map };
|
||||
|
||||
private :
|
||||
// could be null in the stream... not sure that information is
|
||||
// worth preserving beyond an empty string here.
|
||||
std::string m_label;
|
||||
|
||||
/**
|
||||
* Which Java interfaces the type implemented when serialised within
|
||||
* the JVM. Not really useful for C++ but we're keepign it for
|
||||
* the sense of completeness
|
||||
*/
|
||||
std::vector<std::string> m_provides;
|
||||
|
||||
/**
|
||||
* Is it a map or list
|
||||
*/
|
||||
RestrictedTypes m_source;
|
||||
|
||||
protected :
|
||||
/**
|
||||
* keep main constructor private to force use of the named constructor
|
||||
*/
|
||||
Restricted (
|
||||
std::unique_ptr<Descriptor> & descriptor_,
|
||||
const std::string &,
|
||||
std::string,
|
||||
const std::vector<std::string> &,
|
||||
const RestrictedTypes &);
|
||||
|
||||
public :
|
||||
static std::unique_ptr<Restricted> make(
|
||||
std::unique_ptr<Descriptor> & descriptor_,
|
||||
const std::string &,
|
||||
const std::string &,
|
||||
const std::vector<std::string> &,
|
||||
const std::string &);
|
||||
|
||||
Restricted (Restricted&) = delete;
|
||||
|
||||
Type type() const override;
|
||||
|
||||
RestrictedTypes restrictedType() const;
|
||||
|
||||
/**
|
||||
* @return an iterator over the types the restricted class represents.
|
||||
* In the case of a list, the element this is a list of, in the
|
||||
* case of a map the key and value types etc.
|
||||
*/
|
||||
virtual std::vector<std::string>::const_iterator begin() const = 0;
|
||||
virtual std::vector<std::string>::const_iterator end() const = 0;
|
||||
|
||||
int dependsOn (const OrderedTypeNotation &) const override;
|
||||
int dependsOn (const Restricted &) const override = 0;
|
||||
int dependsOn (const class Composite &) const override = 0;
|
||||
};
|
||||
|
||||
|
||||
std::ostream & operator << (std::ostream &, const Restricted::RestrictedTypes &);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
1
experimental/cpp-serializer/src/amqp/test/.gitignore
vendored
Normal file
1
experimental/cpp-serializer/src/amqp/test/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
amqp-test
|
18
experimental/cpp-serializer/src/amqp/test/CMakeLists.txt
Normal file
18
experimental/cpp-serializer/src/amqp/test/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
set (EXE "amqp-test")
|
||||
|
||||
set (amqp-test-sources
|
||||
main.cxx
|
||||
Pair.cxx
|
||||
Single.cxx
|
||||
OrderedTypeNotationTest.cxx
|
||||
)
|
||||
|
||||
link_directories (${BLOB-INSPECTOR_BINARY_DIR}/src/amqp)
|
||||
|
||||
add_executable (${EXE} ${amqp-test-sources})
|
||||
|
||||
target_link_libraries (${EXE} gtest amqp)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries (${EXE} pthread qpid-proton proton)
|
||||
endif (UNIX)
|
@ -0,0 +1,222 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "OrderedTypeNotations.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
class OTN : public amqp::internal::schema::OrderedTypeNotation {
|
||||
private :
|
||||
std::string m_name;
|
||||
std::vector<std::string> m_dependsOn;
|
||||
public :
|
||||
OTN(std::string name_, std::vector<std::string> dependsOn_)
|
||||
: m_name (std::move (name_))
|
||||
, m_dependsOn (std::move (dependsOn_))
|
||||
{ }
|
||||
|
||||
|
||||
int dependsOn (const OrderedTypeNotation & otn_) const override {
|
||||
const auto & otn = dynamic_cast<const OTN &>(otn_);
|
||||
|
||||
// does the "left hand side" depend on us (in this case
|
||||
// the lhs is us as we're not inverting
|
||||
if (std::find (
|
||||
m_dependsOn.begin(),
|
||||
m_dependsOn.end(),
|
||||
otn.name()) != m_dependsOn.end())
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
// do we depend on the left hand side
|
||||
|
||||
|
||||
if (std::find (
|
||||
otn.begin(),
|
||||
otn.end(),
|
||||
name()) != otn.end())
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string & name() const { return m_name; }
|
||||
|
||||
decltype(m_dependsOn.cbegin()) begin() const { return m_dependsOn.cbegin(); }
|
||||
decltype(m_dependsOn.cend()) end() const { return m_dependsOn.cend(); }
|
||||
};
|
||||
|
||||
inline
|
||||
std::string
|
||||
str (const amqp::internal::schema::OrderedTypeNotations<OTN> & list_) {
|
||||
std::stringstream ss;
|
||||
ss << list_;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
/**
|
||||
* Makes testing easier if we compress the list into a flat series rather than
|
||||
* being all fancy with our output
|
||||
*/
|
||||
template<>
|
||||
std::ostream &
|
||||
operator << (
|
||||
std::ostream &stream_,
|
||||
const amqp::internal::schema::OrderedTypeNotations<OTN> &otn_
|
||||
) {
|
||||
auto first { true };
|
||||
for (const auto & i : otn_.m_schemas) {
|
||||
for (const auto & j : i) {
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
stream_ << " ";
|
||||
}
|
||||
stream_ << j->name();
|
||||
}
|
||||
}
|
||||
|
||||
return stream_;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, singleInsert) { // NOLINT
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
list.insert(std::make_unique<OTN>("A", std::vector<std::string>()));
|
||||
ASSERT_EQ("A", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, twoInserts) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
list.insert(std::make_unique<OTN>("A", std::vector<std::string>()));
|
||||
list.insert(std::make_unique<OTN>("B", std::vector<std::string>()));
|
||||
ASSERT_EQ("A B", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, A_depends_on_B) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { "B" };
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
list.insert(std::make_unique<OTN>("B", std::vector<std::string>()));
|
||||
ASSERT_EQ("A B", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, B_depends_on_A) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { };
|
||||
std::vector<std::string> bDeps = { "A" };
|
||||
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
list.insert(std::make_unique<OTN>("B", bDeps));
|
||||
|
||||
ASSERT_EQ ("B A", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, three_1) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { };
|
||||
std::vector<std::string> bDeps = { "A" };
|
||||
std::vector<std::string> cDeps = { "A" };
|
||||
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
list.insert(std::make_unique<OTN>("B", bDeps));
|
||||
list.insert(std::make_unique<OTN>("C", cDeps));
|
||||
|
||||
ASSERT_EQ ("B C A", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, three_2) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { "B" };
|
||||
std::vector<std::string> bDeps = { "C" };
|
||||
std::vector<std::string> cDeps = { };
|
||||
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
list.insert(std::make_unique<OTN>("B", bDeps));
|
||||
list.insert(std::make_unique<OTN>("C", cDeps));
|
||||
|
||||
EXPECT_EQ ("A B C", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, three_3) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { "B" };
|
||||
std::vector<std::string> bDeps = { "C" };
|
||||
std::vector<std::string> cDeps = { };
|
||||
|
||||
list.insert(std::make_unique<OTN>("C", cDeps));
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
list.insert(std::make_unique<OTN>("B", bDeps));
|
||||
|
||||
EXPECT_EQ ("A B C", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, three_4) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { "B" };
|
||||
std::vector<std::string> bDeps = { "C" };
|
||||
std::vector<std::string> cDeps = { };
|
||||
|
||||
list.insert(std::make_unique<OTN>("C", cDeps));
|
||||
list.insert(std::make_unique<OTN>("B", bDeps));
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
|
||||
EXPECT_EQ ("A B C", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (OTNTest, three_5) { // NOLINT
|
||||
std::cout << std::endl;
|
||||
amqp::internal::schema::OrderedTypeNotations<OTN> list;
|
||||
|
||||
std::vector<std::string> aDeps = { "B" };
|
||||
std::vector<std::string> bDeps = { "C" };
|
||||
std::vector<std::string> cDeps = { };
|
||||
|
||||
list.insert(std::make_unique<OTN>("B", bDeps));
|
||||
list.insert(std::make_unique<OTN>("C", cDeps));
|
||||
list.insert(std::make_unique<OTN>("A", aDeps));
|
||||
|
||||
EXPECT_EQ ("A B C", str (list));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
56
experimental/cpp-serializer/src/amqp/test/Pair.cxx
Normal file
56
experimental/cpp-serializer/src/amqp/test/Pair.cxx
Normal file
@ -0,0 +1,56 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Reader.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (Pair, string) { // NOLINT
|
||||
amqp::TypedPair<std::string> str_test ("Left", "Hello");
|
||||
|
||||
EXPECT_EQ("Left : Hello", str_test.dump());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (Pair, int) { // NOLINT
|
||||
amqp::TypedPair<int> int_test ("Left", 101);
|
||||
|
||||
EXPECT_EQ("Left : 101", int_test.dump());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (Pair, UP1) { // NOLINT
|
||||
std::unique_ptr<amqp::TypedPair<double>> test =
|
||||
std::make_unique<amqp::TypedPair<double>> ("property", 10.0);
|
||||
|
||||
EXPECT_EQ("property : 10.000000", test->dump());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
TEST (Pair, UP2) { // NOLINT
|
||||
struct builder {
|
||||
static std::unique_ptr<amqp::Pair>
|
||||
build (const std::string & prop_, int val_) {
|
||||
return std::make_unique<amqp::TypedPair<int>> (prop_, val_);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<amqp::Value>> vec;
|
||||
vec.reserve(2);
|
||||
|
||||
vec.emplace_back (builder::build ("first", 1));
|
||||
vec.emplace_back (builder::build ("second", 2));
|
||||
|
||||
std::unique_ptr<amqp::Pair> test =
|
||||
std::make_unique<amqp::TypedPair<std::vector<std::unique_ptr<amqp::Value>>>> (
|
||||
"Vector", std::move (vec));
|
||||
|
||||
EXPECT_EQ("Vector : { first : 1, second : 2 }", test->dump());
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
35
experimental/cpp-serializer/src/amqp/test/Single.cxx
Normal file
35
experimental/cpp-serializer/src/amqp/test/Single.cxx
Normal file
@ -0,0 +1,35 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "Reader.h"
|
||||
|
||||
TEST (Single, string) { // NOLINT
|
||||
amqp::TypedSingle<std::string> str_test ("Hello");
|
||||
|
||||
EXPECT_EQ("Hello", str_test.dump());
|
||||
}
|
||||
|
||||
TEST (Single, list) { // NOLINT
|
||||
|
||||
struct builder {
|
||||
static std::unique_ptr<amqp::Value>
|
||||
build (int val_) {
|
||||
return std::make_unique<amqp::TypedSingle<int>> (val_);
|
||||
}
|
||||
};
|
||||
|
||||
std::list<std::unique_ptr<amqp::Value>> list;
|
||||
|
||||
list.emplace_back (builder::build (1));
|
||||
list.emplace_back (builder::build (2));
|
||||
list.emplace_back (builder::build (3));
|
||||
list.emplace_back (builder::build (4));
|
||||
list.emplace_back (builder::build (5));
|
||||
|
||||
std::unique_ptr<amqp::Single> test =
|
||||
std::make_unique<amqp::TypedSingle<std::list<std::unique_ptr<amqp::Value>>>> (
|
||||
std::move (list));
|
||||
|
||||
EXPECT_EQ("[ 1, 2, 3, 4, 5 ]", test->dump());
|
||||
}
|
7
experimental/cpp-serializer/src/amqp/test/main.cxx
Normal file
7
experimental/cpp-serializer/src/amqp/test/main.cxx
Normal file
@ -0,0 +1,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
int
|
||||
main (int argc, char ** argv){
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Reference in New Issue
Block a user