Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
73fc0a2
changed some library dependency systems and wrote a down a specificat…
melektron Nov 2, 2023
b8a89b7
worked on implementing basic websocket server (working) and also adde…
melektron Nov 2, 2023
9f2413c
updated strutil and specifically format and improved logging
melektron Nov 3, 2023
ef012bf
added some message handling, experimented with pings and http
melektron Nov 3, 2023
7cf0ca6
got close on timeout working
melektron Nov 3, 2023
4aad12f
made ping loop an asio timer instead of thread
melektron Nov 4, 2023
0c4afd7
properly imlemented ping/pong loop for keep-alive
melektron Nov 5, 2023
5d5a343
started moving codable and link/event systems into library from exper…
melektron Nov 5, 2023
0f48b24
added simple event and link classes
melektron Nov 11, 2023
96f0e85
defined seperate classes for incoming and outgoing event
melektron Nov 15, 2023
e919ef8
worked a bit on defining requirements
melektron Nov 18, 2023
4618f5f
finished the protocol definition for events (for now) and added some …
melektron Nov 19, 2023
6a96024
started implementing proper event protocol
melektron Nov 20, 2023
9007c11
added flags module
melektron Nov 26, 2023
f9bcecd
started working on message parsing and authentication procedure
melektron Nov 26, 2023
3c56b66
implemented auth handling to some degree
melektron Nov 29, 2023
13fdcaf
implemented transaction system and implemented auth transaction properly
melektron Dec 3, 2023
eac648c
fixed format warning by adding specialized, non formatting dynamic st…
melektron Dec 4, 2023
177348f
improved logging
melektron Dec 10, 2023
bb8f7c8
implemented first idea of event subscription
melektron Dec 10, 2023
185e951
reworked event sub/unsub/emit a little and got them working for now
melektron Dec 10, 2023
2365840
implemented the transmission of event sub messages after auth done
melektron Dec 10, 2023
56586b8
implemented event subscribing and unsubscribing (at least internally)
melektron Dec 17, 2023
7ba98b6
implemented all event define methods (also for incoming/outgoing only…
melektron Dec 23, 2023
6b5eeed
fixed issue causing events being unsubscribed prematurely
melektron Dec 23, 2023
7087e7b
implemented event emitting
melektron Dec 26, 2023
36e5805
added explaination/roadmap/plan/reasoning for the msglink networking …
melektron Dec 27, 2023
a0a59ed
fixed a few problems with duplicate functions in header only lib by m…
melektron Dec 28, 2023
48f9aa4
started combining link with websocket server, not quite working jet
melektron Dec 29, 2023
8834342
fixed issue with ping being sent during closing handshake causing an …
melektron Jan 3, 2024
b759db9
added rudimentary json/codable optional support and started with supp…
melektron Jan 14, 2024
8824e87
implemented proper optional support for codable objects
melektron Jan 19, 2024
0bc0574
changed optional coding to use custom coders and renamed generated co…
melektron Jan 20, 2024
a21b02b
implemented sending pong message if client requests it
melektron Jan 21, 2024
fe4f721
added RAII controlled subscription handle
melektron Jan 21, 2024
617bb03
attempted to improve event macro mismatch errors by using static asse…
melektron Jan 21, 2024
d16f093
undid attempted event improvements and started working on procedures.…
melektron Jan 21, 2024
a66ee5c
got function call to work in most simple form (no error handling jet)
melektron Jan 28, 2024
17787e2
implemented error handling for msglink RFCs and bidirectional functions
melektron Jan 28, 2024
e2dc398
added link error handling
melektron Jan 28, 2024
3906607
implemented outgoing function calls (still needs to be made properly …
melektron Jan 29, 2024
cfba3cf
implemented thread-safety of server class
melektron Feb 4, 2024
648dd9e
implemented thread safety in the link
melektron Feb 4, 2024
f55c0cf
removed unused dependencies to ts-stl
melektron Feb 4, 2024
5382685
added the concept of a global class tree context for thread safety an…
melektron Feb 25, 2024
80e5024
removed the old recursive link user call lock in favour of the global…
melektron Feb 25, 2024
62bd56f
implemented global thread safety (even in constructors) using context…
melektron Mar 4, 2024
1c420c2
implemented thread-safety and lock-free calling of function handlers
melektron Mar 5, 2024
bb9f868
removed now unnecessary transaction locks
melektron Mar 11, 2024
a3ec859
linear mapping function and flags to disable exceptions
melektron Jun 17, 2024
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
275 changes: 275 additions & 0 deletions include/el/codable.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
/*
ELEKTRON © 2023 - now
Written by melektron
www.elektron.work
05.11.23, 18:28
All rights reserved.

This source code is licensed under the Apache-2.0 license found in the
LICENSE file in the root directory of this source tree.

Codable helper classes and macros for defining structures
and classes that can be encoded to and/or decoded from json.

This functionality is based on Niels Lohmann's JSON for modern C++ library
and depends on it. It must be includable as follows:

#include <nlohmann/json.hpp>
*/

#pragma once

#include "cxxversions.h"

#include <functional>
#include <nlohmann/json.hpp>
#ifdef __EL_ENABLE_CXX20
#include <concepts>
#endif

#include "metaprog.hpp"
#include "codable_types.hpp"


namespace el
{
/**
* @brief Class interface for
* decodable structures and classes.
*
* This also provides the converter function from_json()
* which allows integration with the nlohmann::json library's
* builtin conversion system. This generates an operator allowing
* the assignment of a json object to any decodable object.
*/
class decodable
{
protected:
virtual ~decodable() = default;

public:
/**
* @brief function which decodes the decodable
* object from json-encoded data
*
* @param _output the json instance to decode.
* This can be a number, object, list or whatever json type
* is used to represent this codable. Invalid type will throw
* a decoder exception.
*/
virtual void _el_codable_decode(const nlohmann::json &_input) = 0;

/**
* @brief function to convert this decodable from json using
* the functionality provided by the nlohmann::json library
*
* @param _j_output json instance to decode
* @param _t_input decodable to decode from json
*/
friend void from_json(const nlohmann::json &_j_input, decodable &_t_output)
{
_t_output._el_codable_decode(_j_input);
};
};

/**
* @brief Class interface for
* encodable structures and classes.
*
* This also provides the converter function to_json()
* which allows integration with the nlohmann::json library's
* builtin conversion system. This generates an operator allowing
* the assignment of any decodable object to a json object.
*/
class encodable
{
protected:
virtual ~encodable() = default;

public:

/**
* @brief function which encodes the encodable's
* members to json.
*
* @param _output the json instance to save the json encoded object to.
* This might be converted to number, object, list or whatever json type
* is used to represent this encodable.
*/
virtual void _el_codable_encode(nlohmann::json &_output) const = 0;

/**
* @brief function to convert this encodable to json using
* the functionality provided by the nlohmann::json library
*
* @param _j_output json instance to encode to
* @param _t_input encodable to encode
*/
friend void to_json(nlohmann::json &_j_output, const encodable &_t_input)
{
_t_input._el_codable_encode(_j_output);
}
};

/**
* @brief Class interface for
* codable structures and classes.
*
* This combines encodable and decodable
* for objects that need to be both en- and decoded.
*/
class codable : public encodable, public decodable
{
protected:
virtual ~codable() = default;
};


#ifdef __EL_ENABLE_CXX20
/**
* The following concepts define constraints that allow targeting specific
* kinds of codables such as a class that is either ONLY an encodable
* or ONLY a decodable or both.
*/

/**
* @brief Constrains _T to be ONLY derived from encodable
* and NOT from decodable
*/
template<class _T>
concept EncodableOnly = std::derived_from<_T, encodable> && !std::derived_from<_T, decodable>;

/**
* @brief Constrains _T to be at derived at least from encodable
* (but can additionally also derive from decodable)
*/
template<class _T>
concept AtLeaseEncodable = std::derived_from<_T, encodable>;

/**
* @brief Constrains _T to be ONLY derived from decodable
* and NOT from encodable
*/
template<class _T>
concept DecodableOnly = std::derived_from<_T, decodable> && !std::derived_from<_T, encodable>;

/**
* @brief Constrains _T to be at derived at least from decodable
* (but can additionally also derive from encodable)
*/
template<class _T>
concept AtLeastDecodable = std::derived_from<_T, decodable>;

/**
* @brief Constrains _T to be derived BOTH from encodable
* and from decodable, making it a full codable
*/
template<class _T>
concept FullCodable = std::derived_from<_T, encodable> && std::derived_from<_T, decodable>;

/**
* @brief Constrains _T to be derived from encodable
* and/or decodable. This constrains a type to be any
* sort of codable.
*/
template<class _T>
concept AnyCodable = std::derived_from<_T, encodable> || std::derived_from<_T, decodable>;

#endif // __EL_ENABLE_CXX20


/**
* Automatic constructor generation
*
*/

// (private) generates a constructor argument for a structure member (of a codable)
#define __EL_CODABLE_CONSTRUCTOR_ARG(member) decltype(member) & _ ## member,
// (private) generates a constructor initializer list entry for a member from the above defined argument
#define __EL_CODABLE_CONSTRUCTOR_INIT(member) member(_ ## member),

// (public) generates a constructor for a given structure which initializes the given members
#define EL_CODABLE_GENERATE_CONSTRUCTORS(TypeName, ...) \
private: \
inline int __el_codable_ctorgen_dummy; \
public: \
TypeName() = default; \
TypeName(EL_METAPROG_DO_FOR_EACH(__EL_CODABLE_CONSTRUCTOR_ARG, __VA_ARGS__) char __dummy = 0) \
: EL_METAPROG_DO_FOR_EACH(__EL_CODABLE_CONSTRUCTOR_INIT, __VA_ARGS__) \
__el_codable_ctorgen_dummy(__dummy) /* dummy is because comma left by macro */ \
{}

/**
* Encoding/Decoding code generation
*
*/

// (private) generates code which uses a member's encoder function to add it to a json object
#define __EL_CODABLE_ENCODE_KEY(member) _el_codable_encode_ ## member (#member, _output);
// (private) generates code which uses a member's decoder function to retrieve it's value from a json object
#define __EL_CODABLE_DECODE_KEY(member) _el_codable_decode_ ## member (#member, _input);

// (public) generates the declaration of the encoder method for a specific member
#define EL_ENCODER(member) void _el_codable_encode_ ## member (const char *member_name, nlohmann::json &encoded_data) const
// (public) generates the declaration of the decoder method for a specific member
#define EL_DECODER(member) void _el_codable_decode_ ## member (const char *member_name, const nlohmann::json &encoded_data)

// (private) generates the default encoder method for a member
#define __EL_CODABLE_DEFINE_DEFAULT_ENCODER(member) \
/* these dummy templates make this function less specialized than one without, \
so the user can manually define their encoder which will take precedence over \
this one */ \
template <class _D = void> \
EL_ENCODER(member) \
{ \
/*encoded_data[member_name] = member;*/ \
::el::codable_types::encode_to_object(encoded_data, member_name, member); \
}

// (private) generates the default decoder method for a member
#define __EL_CODABLE_DEFINE_DEFAULT_DECODER(member) \
/* these dummy templates make this function less specialized than one without, \
so the user can manually define their encoder which will take precedence over \
this one */ \
template <class _D = void> \
EL_DECODER(member) \
{ \
/* explicit convert using .get to avoid unwanted casting paths */ \
/*member = encoded_data.at(member_name).get<decltype(member)>();*/ \
::el::codable_types::decode_from_object(encoded_data, member_name, member); \
}

// (private) generates the default encoder/decoder methods for a class member
#define __EL_CODABLE_DEFINE_DEFAULT_CONVERTERS(member) \
__EL_CODABLE_DEFINE_DEFAULT_ENCODER(member) \
__EL_CODABLE_DEFINE_DEFAULT_DECODER(member)

// (public) generates the methods necessary to make a structure encodable.
// Only the provided members will be made encodable, the others will not be touched.
#define EL_DEFINE_ENCODABLE(Name, ...) \
\
EL_METAPROG_DO_FOR_EACH(__EL_CODABLE_DEFINE_DEFAULT_ENCODER, __VA_ARGS__) \
\
virtual void _el_codable_encode(nlohmann::json &_output) const override \
{ \
EL_METAPROG_DO_FOR_EACH(__EL_CODABLE_ENCODE_KEY, __VA_ARGS__) \
}

// (public) generates the methods necessary to make a structure decodable.
// Only the provided members will be made decodable, the others will not be touched.
#define EL_DEFINE_DECODABLE(Name, ...) \
\
EL_METAPROG_DO_FOR_EACH(__EL_CODABLE_DEFINE_DEFAULT_DECODER, __VA_ARGS__) \
\
virtual void _el_codable_decode(const nlohmann::json &_input) override \
{ \
EL_METAPROG_DO_FOR_EACH(__EL_CODABLE_DECODE_KEY, __VA_ARGS__) \
}

// (public) generates the methods necessary to make a structure codable (encodable and decodable).
// Only the provided members will be made encodable/decodable, the others will not be touched.
#define EL_DEFINE_CODABLE(Name, ...) \
EL_DEFINE_ENCODABLE(Name, __VA_ARGS__) \
EL_DEFINE_DECODABLE(Name, __VA_ARGS__) \

} // namespace el
Loading