Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: #320 #326

Merged
merged 7 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions include/ClientGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,55 @@ class [[nodiscard("unnecessary construction")]] Generator
const std::string& outerScope, const ResponseField& responseField) const noexcept;
[[nodiscard("unnecessary memory copy")]] static std::string getTypeModifierList(
const TypeModifierStack& modifiers) noexcept;
void outputResponseFieldVisitorStates(std::ostream& sourceFile,
const ResponseField& responseField, std::string_view parent = {}) const noexcept;
void outputResponseFieldVisitorAddValue(std::ostream& sourceFile,
const ResponseField& responseField, bool arrayElement = false,
std::string_view parentState = {}, std::string_view parentAccessor = {},
std::string_view parentCppType = {}) const noexcept;
void outputResponseFieldVisitorReserve(std::ostream& sourceFile,
const ResponseField& responseField, std::string_view parentState = {},
std::string_view parentAccessor = {}, std::string_view parentCppType = {}) const noexcept;
void outputResponseFieldVisitorStartObject(std::ostream& sourceFile,
const ResponseField& responseField, std::string_view parentState = {},
std::string_view parentAccessor = {}, std::string_view parentCppType = {}) const noexcept;
void outputResponseFieldVisitorAddMember(std::ostream& sourceFile,
const ResponseFieldList& children, bool arrayElement = false,
std::string_view parentState = {}) const noexcept;
void outputResponseFieldVisitorEndObject(std::ostream& sourceFile,
const ResponseField& responseField, bool arrayElement = false,
std::string_view parentState = {}) const noexcept;
void outputResponseFieldVisitorStartArray(std::ostream& sourceFile,
const ResponseField& responseField, std::string_view parentState = {},
std::string_view parentAccessor = {}, std::string_view parentCppType = {}) const noexcept;
void outputResponseFieldVisitorEndArray(std::ostream& sourceFilearrayElement,
const ResponseField& responseField, bool arrayElement = false,
std::string_view parentState = {}) const noexcept;
void outputResponseFieldVisitorAddNull(std::ostream& sourceFilearrayElement,
const ResponseField& responseField, bool arrayElement = false,
std::string_view parentState = {}, std::string_view parentAccessor = {}) const noexcept;
void outputResponseFieldVisitorAddMovedValue(std::ostream& sourceFile,
const ResponseField& responseField, std::string_view movedCppType,
bool arrayElement = false, std::string_view parentState = {},
std::string_view parentAccessor = {}) const noexcept;
void outputResponseFieldVisitorAddString(
std::ostream& sourceFile, const ResponseField& responseField) const noexcept;
void outputResponseFieldVisitorAddEnum(std::ostream& sourceFile,
const ResponseField& responseField, bool arrayElement = false,
std::string_view parentState = {}, std::string_view parentAccessor = {},
std::string_view parentCppType = {}) const noexcept;
void outputResponseFieldVisitorAddId(
std::ostream& sourceFile, const ResponseField& responseField) const noexcept;
void outputResponseFieldVisitorAddCopiedValue(std::ostream& sourceFile,
const ResponseField& responseField, std::string_view copiedCppType,
bool arrayElement = false, std::string_view parentState = {},
std::string_view parentAccessor = {}) const noexcept;
void outputResponseFieldVisitorAddBool(
std::ostream& sourceFile, const ResponseField& responseField) const noexcept;
void outputResponseFieldVisitorAddInt(
std::ostream& sourceFile, const ResponseField& responseField) const noexcept;
void outputResponseFieldVisitorAddFloat(
std::ostream& sourceFile, const ResponseField& responseField) const noexcept;

const SchemaLoader _schemaLoader;
const RequestLoader _requestLoader;
Expand Down
289 changes: 288 additions & 1 deletion include/graphqlservice/GraphQLResponse.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
#ifndef GRAPHQLRESPONSE_H
#define GRAPHQLRESPONSE_H

#include "internal/DllExports.h"
#include "internal/Awaitable.h"
#include "internal/DllExports.h"

#include <cstddef>
#include <cstdint>
#include <initializer_list>
#include <iterator>
#include <list>
#include <memory>
#include <string>
#include <string_view>
Expand Down Expand Up @@ -375,6 +376,292 @@ GRAPHQLRESPONSE_EXPORT IdType Value::release<IdType>();

using AwaitableValue = internal::Awaitable<Value>;

// Type-erased visitor for alternate representations of Value.
class [[nodiscard("unnecessary construction")]] ValueVisitor final
: public std::enable_shared_from_this<ValueVisitor>
{
private:
struct Concept
{
virtual ~Concept() = default;

virtual void add_value(std::shared_ptr<const Value>&& value) = 0;

virtual void reserve(std::size_t count) = 0;

virtual void start_object() = 0;
virtual void add_member(std::string&& key) = 0;
virtual void end_object() = 0;

virtual void start_array() = 0;
virtual void end_array() = 0;

virtual void add_null() = 0;
virtual void add_string(std::string&& value) = 0;
virtual void add_enum(std::string&& value) = 0;
virtual void add_id(IdType&& value) = 0;
virtual void add_bool(bool value) = 0;
virtual void add_int(int value) = 0;
virtual void add_float(double value) = 0;

virtual void complete() = 0;
};

template <class T>
struct Model : Concept
{
explicit Model(std::shared_ptr<T> pimpl) noexcept
: _pimpl { std::move(pimpl) }
{
}

void add_value(std::shared_ptr<const Value>&& value) final
{
_pimpl->add_value(std::move(value));
}

void reserve(std::size_t count) final
{
_pimpl->reserve(count);
}

void start_object() final
{
_pimpl->start_object();
}

void add_member(std::string&& key) final
{
_pimpl->add_member(std::move(key));
}

void end_object() final
{
_pimpl->end_object();
}

void start_array() final
{
_pimpl->start_array();
}

void end_array() final
{
_pimpl->end_array();
}

void add_null() final
{
_pimpl->add_null();
}

void add_string(std::string&& value) final
{
_pimpl->add_string(std::move(value));
}

void add_enum(std::string&& value) final
{
_pimpl->add_enum(std::move(value));
}

void add_id(IdType&& value) final
{
_pimpl->add_id(std::move(value));
}

void add_bool(bool value) final
{
_pimpl->add_bool(value);
}

void add_int(int value) final
{
_pimpl->add_int(value);
}

void add_float(double value) final
{
_pimpl->add_float(value);
}

void complete() final
{
_pimpl->complete();
}

private:
std::shared_ptr<T> _pimpl;
};

const std::shared_ptr<Concept> _concept;

public:
template <class T>
ValueVisitor(std::shared_ptr<T> writer) noexcept
: _concept { std::static_pointer_cast<Concept>(
std::make_shared<Model<T>>(std::move(writer))) }
{
}

GRAPHQLRESPONSE_EXPORT void add_value(std::shared_ptr<const Value>&& value);

GRAPHQLRESPONSE_EXPORT void reserve(std::size_t count);

GRAPHQLRESPONSE_EXPORT void start_object();
GRAPHQLRESPONSE_EXPORT void add_member(std::string&& key);
GRAPHQLRESPONSE_EXPORT void end_object();

GRAPHQLRESPONSE_EXPORT void start_array();
GRAPHQLRESPONSE_EXPORT void end_array();

GRAPHQLRESPONSE_EXPORT void add_null();
GRAPHQLRESPONSE_EXPORT void add_string(std::string&& value);
GRAPHQLRESPONSE_EXPORT void add_enum(std::string&& value);
GRAPHQLRESPONSE_EXPORT void add_id(IdType&& value);
GRAPHQLRESPONSE_EXPORT void add_bool(bool value);
GRAPHQLRESPONSE_EXPORT void add_int(int value);
GRAPHQLRESPONSE_EXPORT void add_float(double value);

GRAPHQLRESPONSE_EXPORT void complete();
};

// Pending token for ValueVisitor.
struct [[nodiscard("unnecessary construction")]] ValueToken
{
using OpaqueValue = std::shared_ptr<const Value>;

GRAPHQLRESPONSE_EXPORT explicit ValueToken(OpaqueValue&& value);

struct Reserve
{
std::size_t capacity;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(Reserve&& value);

struct StartObject
{
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(StartObject&& value);

struct AddMember
{
std::string key;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(AddMember&& value);

struct EndObject
{
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(EndObject&& value);

struct StartArray
{
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(StartArray&& value);

struct EndArray
{
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(EndArray&& value);

struct NullValue
{
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(NullValue&& value);

struct StringValue
{
std::string value;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(StringValue&& value);

struct EnumValue
{
std::string value;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(EnumValue&& value);

struct IdValue
{
IdType value;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(IdValue&& value);

struct BoolValue
{
bool value;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(BoolValue&& value);

struct IntValue
{
int value;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(IntValue&& value);

struct FloatValue
{
double value;
};

GRAPHQLRESPONSE_EXPORT explicit ValueToken(FloatValue&& value);

GRAPHQLRESPONSE_EXPORT void visit(const std::shared_ptr<ValueVisitor>& visitor) &&;

private:
using variant_type =
std::variant<OpaqueValue, Reserve, StartObject, AddMember, EndObject, StartArray, EndArray,
NullValue, StringValue, EnumValue, IdValue, BoolValue, IntValue, FloatValue>;

variant_type _value;
};

class [[nodiscard("unnecessary construction")]] ValueTokenStream final
{
public:
ValueTokenStream() noexcept = default;
~ValueTokenStream() = default;

ValueTokenStream(ValueTokenStream&&) noexcept = default;
ValueTokenStream& operator=(ValueTokenStream&&) noexcept = default;

ValueTokenStream(const ValueTokenStream&) = delete;
ValueTokenStream& operator=(const ValueTokenStream&) = delete;

template <class TArg>
ValueTokenStream(TArg&& arg)
: _tokens { ValueToken { std::forward<TArg>(arg) } }
{
}

template <class TArg>
void push_back(TArg&& arg)
{
_tokens.push_back(ValueToken { std::forward<TArg>(arg) });
}

GRAPHQLRESPONSE_EXPORT void append(ValueTokenStream&& other);

GRAPHQLRESPONSE_EXPORT void visit(const std::shared_ptr<ValueVisitor>& visitor) &&;
GRAPHQLRESPONSE_EXPORT Value value() &&;

private:
std::list<ValueToken> _tokens;
};

class [[nodiscard("unnecessary construction")]] Writer final
{
private:
Expand Down
Loading