Compare commits
76 Commits
master
...
fb-tidy-sn
Author | SHA1 | Date |
---|---|---|
Claudius Holeksa | b1f8ac8334 | |
Claudius Holeksa | 76121c563d | |
Claudius Holeksa | 1c75e0de2c | |
Claudius Holeksa | 0afe4fe38e | |
Claudius Holeksa | 0325661bf8 | |
Claudius Holeksa | cdd27abe65 | |
Claudius Holeksa | c7b269be29 | |
Claudius Holeksa | 15cff82096 | |
Claudius Holeksa | 6b8de4b52a | |
Claudius Holeksa | a64b7cafa0 | |
Claudius Holeksa | a1a718967d | |
Claudius Holeksa | 6968a80518 | |
Claudius Holeksa | 55a6d4dd9b | |
Claudius Holeksa | 4384f8acfa | |
Claudius Holeksa | 77acd00720 | |
Claudius Holeksa | 3004dec554 | |
Claudius Holeksa | 9330d1ee74 | |
Claudius Holeksa | c51bb63e9b | |
Claudius Holeksa | 389d23bd28 | |
Claudius Holeksa | 30937d98c5 | |
Claudius Holeksa | 4fa6ed0d59 | |
Claudius Holeksa | 33188f213e | |
Claudius Holeksa | 7aacdc357c | |
Claudius Holeksa | 21a1bde479 | |
Claudius Holeksa | a963bdff6c | |
Claudius Holeksa | d845848449 | |
Claudius Holeksa | 37ed2ebc8e | |
Claudius Holeksa | e4b6204edd | |
Claudius Holeksa | 536aa05298 | |
Claudius Holeksa | 74663daeef | |
keldu | 91a8f680b2 | |
Claudius Holeksa | 2e9d96a1d0 | |
Claudius Holeksa | 3651aea384 | |
keldu | 7fecac92c0 | |
keldu | cdb096a44f | |
Claudius Holeksa | 5d3796c751 | |
Claudius Holeksa | fb9312acb1 | |
keldu | f695b047e9 | |
Claudius Holeksa | 7518dd7ed4 | |
Claudius Holeksa | afbe54c795 | |
Claudius Holeksa | 9e4260cc04 | |
Claudius Holeksa | f0f1c8f2e8 | |
keldu | 5ce093cb6a | |
Claudius Holeksa | b8b461a4c6 | |
keldu | f92ebab88a | |
keldu | 01ebd991ae | |
keldu | f38a122efa | |
keldu | 80c5fd6bfb | |
Claudius Holeksa | c0241fe666 | |
keldu | b25b28a560 | |
keldu | 54608ac410 | |
keldu | 9136e902f1 | |
Claudius Holeksa | 2ea95b8b3e | |
Claudius Holeksa | dc5ad0e62a | |
Claudius Holeksa | 883cfc32a5 | |
Claudius Holeksa | 2af95c3664 | |
Claudius Holeksa | c82d717c2d | |
Claudius Holeksa | 0d06a58798 | |
Claudius Holeksa | d172f458a3 | |
Claudius Holeksa | e571a7ce90 | |
Claudius Holeksa | a5cfca7a12 | |
Claudius Holeksa | ffed345df1 | |
keldu | 0808db94ee | |
Claudius Holeksa | f44b6a1dc8 | |
Claudius Holeksa | b0991ce29b | |
Claudius Holeksa | 60d710cab7 | |
Claudius Holeksa | 28ea7d6708 | |
Claudius Holeksa | 3ff512bfca | |
Claudius Holeksa | 2d8889983a | |
Claudius Holeksa | 5a6f63eadb | |
Claudius Holeksa | 911db65409 | |
Claudius Holeksa | f29d1c6512 | |
Claudius Holeksa | 3cb0434e49 | |
Claudius Holeksa | 7117f23fcd | |
Claudius Holeksa | 6624960f86 | |
Claudius Holeksa | 12c61f46dc |
|
@ -0,0 +1,12 @@
|
|||
Checks: '-*,readability-identifier-naming'
|
||||
CheckOptions:
|
||||
- { key: readability-identifier-naming.AggressiveDependentMemberLookup, value: true }
|
||||
- { key: readability-identifier-naming.NamespaceCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.ClassCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.StructCase, value: CamelCase }
|
||||
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.ParameterCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.VariableCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
|
||||
- { key: readability-identifier-naming.PrivateMemberPrefix, value: 'm_' }
|
|
@ -71,3 +71,7 @@ thoughts
|
|||
*.swp
|
||||
vgcore.*
|
||||
*.pdf
|
||||
|
||||
# cache file for ale
|
||||
.cache
|
||||
async.plist
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
with import <nixpkgs> {};
|
||||
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShell {
|
||||
name = "forstio";
|
||||
nativeBuildInputs = [ scons gnutls clang_12 clang-tools];
|
||||
|
||||
buildPhase = ''
|
||||
'';
|
||||
}
|
29
SConstruct
29
SConstruct
|
@ -46,8 +46,11 @@ env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=['#source/forstio','
|
|||
CXX='clang++',
|
||||
CPPDEFINES=['SAW_UNIX'],
|
||||
CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
|
||||
LIBS=['gnutls'])
|
||||
LIBS=[])
|
||||
env.__class__.add_source_files = add_kel_source_files
|
||||
env.Tool('compilation_db');
|
||||
env.cdb = env.CompilationDatabase('compile_commands.json');
|
||||
|
||||
|
||||
env.objects = []
|
||||
env.sources = []
|
||||
|
@ -60,26 +63,8 @@ env.driver_sources = []
|
|||
env.driver_headers = []
|
||||
|
||||
Export('env')
|
||||
SConscript('source/forstio/SConscript')
|
||||
SConscript('driver/SConscript')
|
||||
|
||||
# Library build
|
||||
|
||||
env_library = env.Clone()
|
||||
|
||||
env.objects_shared = []
|
||||
env_library.add_source_files(env.objects_shared, env.sources + env.driver_sources + env.tls_sources, shared=True)
|
||||
env.library_shared = env_library.SharedLibrary('#build/forstio', [env.objects_shared])
|
||||
|
||||
env.objects_static = []
|
||||
env_library.add_source_files(env.objects_static, env.sources + env.driver_sources + env.tls_sources)
|
||||
env.library_static = env_library.StaticLibrary('#build/forstio', [env.objects_static])
|
||||
|
||||
env.Alias('library', [env.library_shared, env.library_static])
|
||||
env.Alias('library_shared', env.library_shared)
|
||||
env.Alias('library_static', env.library_static)
|
||||
|
||||
env.Default('library')
|
||||
SConscript('source/forstio/SConscript')
|
||||
|
||||
# Tests
|
||||
SConscript('test/SConscript')
|
||||
|
@ -98,7 +83,9 @@ format_iter(env,env.sources + env.driver_sources + env.headers + env.driver_head
|
|||
|
||||
env.Alias('format', env.format_actions)
|
||||
|
||||
env.Alias('all', ['format', 'library_shared', 'library_static', 'test'])
|
||||
env.Alias('cdb', env.cdb);
|
||||
env.Alias('all', ['format', 'library', 'test'])
|
||||
env.Default('all')
|
||||
|
||||
env.Install('$prefix/lib/', [env.library_shared, env.library_static])
|
||||
env.Install('$prefix/include/forstio/', [env.headers])
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "driver/io-unix.h"
|
||||
#include "io-unix.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
@ -18,11 +18,11 @@ IFdOwner::~IFdOwner() {
|
|||
}
|
||||
}
|
||||
|
||||
ssize_t unixRead(int fd, void *buffer, size_t length) {
|
||||
ssize_t unix_read(int fd, void *buffer, size_t length) {
|
||||
return ::recv(fd, buffer, length, 0);
|
||||
}
|
||||
|
||||
ssize_t unixWrite(int fd, const void *buffer, size_t length) {
|
||||
ssize_t unix_write(int fd, const void *buffer, size_t length) {
|
||||
return ::send(fd, buffer, length, 0);
|
||||
}
|
||||
|
||||
|
@ -129,7 +129,7 @@ UnixDatagram::UnixDatagram(UnixEventPort &event_port, int file_descriptor,
|
|||
: IFdOwner{event_port, file_descriptor, fd_flags, EPOLLIN | EPOLLOUT} {}
|
||||
|
||||
namespace {
|
||||
ssize_t unixReadMsg(int fd, void *buffer, size_t length) {
|
||||
ssize_t unix_read_msg(int fd, void *buffer, size_t length) {
|
||||
struct ::sockaddr_storage their_addr;
|
||||
socklen_t addr_len = sizeof(sockaddr_storage);
|
||||
return ::recvfrom(fd, buffer, length, 0,
|
||||
|
@ -137,15 +137,15 @@ ssize_t unixReadMsg(int fd, void *buffer, size_t length) {
|
|||
&addr_len);
|
||||
}
|
||||
|
||||
ssize_t unixWriteMsg(int fd, const void *buffer, size_t length,
|
||||
::sockaddr *dest_addr, socklen_t dest_addr_len) {
|
||||
ssize_t unix_write_msg(int fd, const void *buffer, size_t length,
|
||||
::sockaddr *dest_addr, socklen_t dest_addr_len) {
|
||||
|
||||
return ::sendto(fd, buffer, length, 0, dest_addr, dest_addr_len);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ErrorOr<size_t> UnixDatagram::read(void *buffer, size_t length) {
|
||||
ssize_t read_bytes = unixReadMsg(fd(), buffer, length);
|
||||
ssize_t read_bytes = unix_read_msg(fd(), buffer, length);
|
||||
if (read_bytes > 0) {
|
||||
return static_cast<size_t>(read_bytes);
|
||||
}
|
||||
|
@ -163,8 +163,8 @@ ErrorOr<size_t> UnixDatagram::write(const void *buffer, size_t length,
|
|||
UnixNetworkAddress &unix_dest = static_cast<UnixNetworkAddress &>(dest);
|
||||
SocketAddress &sock_addr = unix_dest.unixAddress();
|
||||
socklen_t sock_addr_length = sock_addr.getRawLength();
|
||||
ssize_t write_bytes = unixWriteMsg(fd(), buffer, length, sock_addr.getRaw(),
|
||||
sock_addr_length);
|
||||
ssize_t write_bytes = unix_write_msg(fd(), buffer, length,
|
||||
sock_addr.getRaw(), sock_addr_length);
|
||||
if (write_bytes > 0) {
|
||||
return static_cast<size_t>(write_bytes);
|
||||
}
|
||||
|
@ -192,14 +192,14 @@ void UnixDatagram::notify(uint32_t mask) {
|
|||
}
|
||||
|
||||
namespace {
|
||||
bool beginsWith(const std::string_view &viewed,
|
||||
const std::string_view &begins) {
|
||||
bool begins_with(const std::string_view &viewed,
|
||||
const std::string_view &begins) {
|
||||
return viewed.size() >= begins.size() &&
|
||||
viewed.compare(0, begins.size(), begins) == 0;
|
||||
}
|
||||
|
||||
std::variant<UnixNetworkAddress, UnixNetworkAddress *>
|
||||
translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
|
||||
translate_network_address_to_unix_network_address(NetworkAddress &addr) {
|
||||
auto addr_variant = addr.representation();
|
||||
std::variant<UnixNetworkAddress, UnixNetworkAddress *> os_addr = std::visit(
|
||||
[](auto &arg)
|
||||
|
@ -210,7 +210,7 @@ translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
|
|||
return static_cast<UnixNetworkAddress *>(arg);
|
||||
}
|
||||
|
||||
auto sock_addrs = SocketAddress::parse(
|
||||
auto sock_addrs = SocketAddress::resolve(
|
||||
std::string_view{arg->address()}, arg->port());
|
||||
|
||||
return UnixNetworkAddress{arg->address(), arg->port(),
|
||||
|
@ -220,7 +220,7 @@ translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
|
|||
return os_addr;
|
||||
}
|
||||
|
||||
UnixNetworkAddress &translateToUnixAddressRef(
|
||||
UnixNetworkAddress &translate_to_unix_address_ref(
|
||||
std::variant<UnixNetworkAddress, UnixNetworkAddress *> &addr_variant) {
|
||||
return std::visit(
|
||||
[](auto &arg) -> UnixNetworkAddress & {
|
||||
|
@ -240,8 +240,10 @@ UnixNetworkAddress &translateToUnixAddressRef(
|
|||
} // namespace
|
||||
|
||||
Own<Server> UnixNetwork::listen(NetworkAddress &addr) {
|
||||
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
|
||||
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
|
||||
auto unix_addr_storage =
|
||||
translate_network_address_to_unix_network_address(addr);
|
||||
UnixNetworkAddress &address =
|
||||
translate_to_unix_address_ref(unix_addr_storage);
|
||||
|
||||
assert(address.unixAddressSize() > 0);
|
||||
if (address.unixAddressSize() == 0) {
|
||||
|
@ -272,8 +274,10 @@ Own<Server> UnixNetwork::listen(NetworkAddress &addr) {
|
|||
}
|
||||
|
||||
Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
|
||||
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
|
||||
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
|
||||
auto unix_addr_storage =
|
||||
translate_network_address_to_unix_network_address(addr);
|
||||
UnixNetworkAddress &address =
|
||||
translate_to_unix_address_ref(unix_addr_storage);
|
||||
|
||||
assert(address.unixAddressSize() > 0);
|
||||
if (address.unixAddressSize() == 0) {
|
||||
|
@ -332,8 +336,10 @@ Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
|
|||
}
|
||||
|
||||
Own<Datagram> UnixNetwork::datagram(NetworkAddress &addr) {
|
||||
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
|
||||
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
|
||||
auto unix_addr_storage =
|
||||
translate_network_address_to_unix_network_address(addr);
|
||||
UnixNetworkAddress &address =
|
||||
translate_to_unix_address_ref(unix_addr_storage);
|
||||
|
||||
SAW_ASSERT(address.unixAddressSize() > 0) { return nullptr; }
|
||||
|
||||
|
@ -370,18 +376,18 @@ size_t UnixNetworkAddress::unixAddressSize() const { return addresses.size(); }
|
|||
|
||||
UnixNetwork::UnixNetwork(UnixEventPort &event) : event_port{event} {}
|
||||
|
||||
Conveyor<Own<NetworkAddress>> UnixNetwork::parseAddress(const std::string &path,
|
||||
uint16_t port_hint) {
|
||||
Conveyor<Own<NetworkAddress>>
|
||||
UnixNetwork::resolveAddress(const std::string &path, uint16_t port_hint) {
|
||||
std::string_view addr_view{path};
|
||||
{
|
||||
std::string_view begins_with = "unix:";
|
||||
if (beginsWith(addr_view, begins_with)) {
|
||||
if (begins_with(addr_view, begins_with)) {
|
||||
addr_view.remove_prefix(begins_with.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<SocketAddress> addresses =
|
||||
SocketAddress::parse(addr_view, port_hint);
|
||||
SocketAddress::resolve(addr_view, port_hint);
|
||||
|
||||
return Conveyor<Own<NetworkAddress>>{
|
||||
heap<UnixNetworkAddress>(path, port_hint, std::move(addresses))};
|
||||
|
@ -403,7 +409,7 @@ EventLoop &UnixIoProvider::eventLoop() { return event_loop; }
|
|||
|
||||
} // namespace unix
|
||||
|
||||
ErrorOr<AsyncIoContext> setupAsyncIo() {
|
||||
ErrorOr<AsyncIoContext> setup_async_io() {
|
||||
using namespace unix;
|
||||
try {
|
||||
Own<UnixEventPort> prt = heap<UnixEventPort>();
|
||||
|
|
248
driver/io-unix.h
248
driver/io-unix.h
|
@ -30,41 +30,41 @@
|
|||
|
||||
namespace saw {
|
||||
namespace unix {
|
||||
constexpr int MAX_EPOLL_EVENTS = 256;
|
||||
constexpr int max_epoll_events = 256;
|
||||
|
||||
class UnixEventPort;
|
||||
class IFdOwner {
|
||||
class i_fd_owner {
|
||||
protected:
|
||||
UnixEventPort &event_port;
|
||||
|
||||
private:
|
||||
int file_descriptor;
|
||||
int fd_flags;
|
||||
uint32_t event_mask;
|
||||
int m_file_descriptor;
|
||||
int m_fd_flags;
|
||||
uint32_t m_event_mask;
|
||||
|
||||
public:
|
||||
IFdOwner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
|
||||
uint32_t event_mask);
|
||||
i_fd_owner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
|
||||
uint32_t event_mask);
|
||||
|
||||
virtual ~IFdOwner();
|
||||
virtual ~i_fd_owner();
|
||||
|
||||
virtual void notify(uint32_t mask) = 0;
|
||||
|
||||
int fd() const { return file_descriptor; }
|
||||
int fd() const { return m_file_descriptor; }
|
||||
};
|
||||
|
||||
class UnixEventPort final : public EventPort {
|
||||
private:
|
||||
int epoll_fd;
|
||||
int signal_fd;
|
||||
int m_epoll_fd;
|
||||
int m_signal_fd;
|
||||
|
||||
sigset_t signal_fd_set;
|
||||
sigset_t m_signal_fd_set;
|
||||
|
||||
std::unordered_multimap<Signal, Own<ConveyorFeeder<void>>> signal_conveyors;
|
||||
std::unordered_multimap<Signal, Own<ConveyorFeeder<void>>> m_signal_conveyors;
|
||||
|
||||
int pipefds[2];
|
||||
int m_pipefds[2];
|
||||
|
||||
std::vector<int> toUnixSignal(Signal signal) const {
|
||||
std::vector<int> to_unix_signal(Signal signal) const {
|
||||
switch (signal) {
|
||||
case Signal::User1:
|
||||
return {SIGUSR1};
|
||||
|
@ -74,7 +74,7 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
Signal fromUnixSignal(int signal) const {
|
||||
Signal from_unix_signal(int signal) const {
|
||||
switch (signal) {
|
||||
case SIGUSR1:
|
||||
return Signal::User1;
|
||||
|
@ -86,8 +86,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void notifySignalListener(int sig) {
|
||||
Signal signal = fromUnixSignal(sig);
|
||||
void notify_signal_listener(int sig) {
|
||||
Signal signal = from_unix_signal(sig);
|
||||
|
||||
auto equal_range = signal_conveyors.equal_range(signal);
|
||||
for (auto iter = equal_range.first; iter != equal_range.second;
|
||||
|
@ -101,11 +101,11 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
bool pollImpl(int time) {
|
||||
epoll_event events[MAX_EPOLL_EVENTS];
|
||||
bool poll_impl(int time) {
|
||||
epoll_event events[max_epoll_events];
|
||||
int nfds = 0;
|
||||
do {
|
||||
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, time);
|
||||
nfds = epoll_wait(m_epoll_fd, events, max_epoll_events, time);
|
||||
|
||||
if (nfds < 0) {
|
||||
/// @todo error_handling
|
||||
|
@ -117,50 +117,50 @@ private:
|
|||
while (1) {
|
||||
struct ::signalfd_siginfo siginfo;
|
||||
ssize_t n =
|
||||
::read(signal_fd, &siginfo, sizeof(siginfo));
|
||||
::read(m_signal_fd, &siginfo, sizeof(siginfo));
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
assert(n == sizeof(siginfo));
|
||||
|
||||
notifySignalListener(siginfo.ssi_signo);
|
||||
notify_signal_listener(siginfo.ssi_signo);
|
||||
}
|
||||
} else if (events[i].data.u64 == 1) {
|
||||
uint8_t i;
|
||||
if (pipefds[0] < 0) {
|
||||
if (m_pipefds[0] < 0) {
|
||||
continue;
|
||||
}
|
||||
while (1) {
|
||||
ssize_t n = ::recv(pipefds[0], &i, sizeof(i), 0);
|
||||
ssize_t n = ::recv(m_pipefds[0], &i, sizeof(i), 0);
|
||||
if (n < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IFdOwner *owner =
|
||||
reinterpret_cast<IFdOwner *>(events[i].data.ptr);
|
||||
i_fd_owner *owner =
|
||||
reinterpret_cast<i_fd_owner *>(events[i].data.ptr);
|
||||
if (owner) {
|
||||
owner->notify(events[i].events);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (nfds == MAX_EPOLL_EVENTS);
|
||||
} while (nfds == max_epoll_events);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
UnixEventPort() : epoll_fd{-1}, signal_fd{-1} {
|
||||
UnixEventPort() : m_epoll_fd{-1}, m_signal_fd{-1} {
|
||||
::signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
epoll_fd = ::epoll_create1(EPOLL_CLOEXEC);
|
||||
if (epoll_fd < 0) {
|
||||
m_epoll_fd = ::epoll_create1(EPOLL_CLOEXEC);
|
||||
if (m_epoll_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
::sigemptyset(&signal_fd_set);
|
||||
signal_fd = ::signalfd(-1, &signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
if (signal_fd < 0) {
|
||||
::sigemptyset(&m_signal_fd_set);
|
||||
m_signal_fd = ::signalfd(-1, &m_signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
if (m_signal_fd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -168,51 +168,50 @@ public:
|
|||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN;
|
||||
event.data.u64 = 0;
|
||||
::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, signal_fd, &event);
|
||||
::epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_signal_fd, &event);
|
||||
|
||||
int rc = ::pipe2(pipefds, O_NONBLOCK | O_CLOEXEC);
|
||||
int rc = ::pipe2(m_pipefds, O_NONBLOCK | O_CLOEXEC);
|
||||
if (rc < 0) {
|
||||
return;
|
||||
}
|
||||
memset(&event, 0, sizeof(event));
|
||||
event.events = EPOLLIN;
|
||||
event.data.u64 = 1;
|
||||
::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipefds[0], &event);
|
||||
::epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, m_pipefds[0], &event);
|
||||
}
|
||||
|
||||
~UnixEventPort() {
|
||||
::close(epoll_fd);
|
||||
::close(signal_fd);
|
||||
::close(pipefds[0]);
|
||||
::close(pipefds[1]);
|
||||
::close(m_epoll_fd);
|
||||
::close(m_signal_fd);
|
||||
::close(m_pipefds[0]);
|
||||
::close(m_pipefds[1]);
|
||||
}
|
||||
|
||||
Conveyor<void> onSignal(Signal signal) override {
|
||||
Conveyor<void> on_signal(Signal signal) override {
|
||||
auto caf = newConveyorAndFeeder<void>();
|
||||
|
||||
signal_conveyors.insert(std::make_pair(signal, std::move(caf.feeder)));
|
||||
|
||||
std::vector<int> sig = toUnixSignal(signal);
|
||||
std::vector<int> sig = to_unix_signal(signal);
|
||||
|
||||
for (auto iter = sig.begin(); iter != sig.end(); ++iter) {
|
||||
::sigaddset(&signal_fd_set, *iter);
|
||||
}
|
||||
::sigprocmask(SIG_BLOCK, &signal_fd_set, nullptr);
|
||||
::signalfd(signal_fd, &signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
::sigprocmask(SIG_BLOCK, &m_signal_fd_set, nullptr);
|
||||
::signalfd(m_signal_fd, &m_signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
|
||||
|
||||
auto node_and_storage =
|
||||
Conveyor<void>::fromConveyor(std::move(caf.conveyor));
|
||||
return Conveyor<void>::toConveyor(std::move(node_and_storage.first),
|
||||
node_and_storage.second);
|
||||
auto node = Conveyor<void>::fromConveyor(std::move(caf.conveyor));
|
||||
return Conveyor<void>::toConveyor(std::move(node));
|
||||
}
|
||||
|
||||
void poll() override { pollImpl(0); }
|
||||
void poll() override { poll_impl(0); }
|
||||
|
||||
void wait() override { pollImpl(-1); }
|
||||
void wait() override { poll_impl(-1); }
|
||||
|
||||
void wait(const std::chrono::steady_clock::duration &duration) override {
|
||||
pollImpl(std::chrono::duration_cast<std::chrono::milliseconds>(duration)
|
||||
.count());
|
||||
poll_impl(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(duration)
|
||||
.count());
|
||||
}
|
||||
void
|
||||
wait(const std::chrono::steady_clock::time_point &time_point) override {
|
||||
|
@ -220,24 +219,24 @@ public:
|
|||
if (time_point <= now) {
|
||||
poll();
|
||||
} else {
|
||||
pollImpl(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
time_point - now)
|
||||
.count());
|
||||
poll_impl(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
time_point - now)
|
||||
.count());
|
||||
}
|
||||
}
|
||||
|
||||
void wake() override {
|
||||
/// @todo pipe() in the beginning and write something minor into it like
|
||||
/// uint8_t or sth the value itself doesn't matter
|
||||
if (pipefds[1] < 0) {
|
||||
if (m_pipefds[1] < 0) {
|
||||
return;
|
||||
}
|
||||
uint8_t i = 0;
|
||||
::send(pipefds[1], &i, sizeof(i), MSG_DONTWAIT);
|
||||
::send(m_pipefds[1], &i, sizeof(i), MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
void subscribe(IFdOwner &owner, int fd, uint32_t event_mask) {
|
||||
if (epoll_fd < 0 || fd < 0) {
|
||||
void subscribe(i_fd_owner &owner, int fd, uint32_t event_mask) {
|
||||
if (m_epoll_fd < 0 || fd < 0) {
|
||||
return;
|
||||
}
|
||||
::epoll_event event;
|
||||
|
@ -245,45 +244,45 @@ public:
|
|||
event.events = event_mask | EPOLLET;
|
||||
event.data.ptr = &owner;
|
||||
|
||||
if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event) < 0) {
|
||||
if (::epoll_ctl(m_epoll_fd, EPOLL_CTL_ADD, fd, &event) < 0) {
|
||||
/// @todo error_handling
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void unsubscribe(int fd) {
|
||||
if (epoll_fd < 0 || fd < 0) {
|
||||
if (m_epoll_fd < 0 || fd < 0) {
|
||||
return;
|
||||
}
|
||||
if (::epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, nullptr) < 0) {
|
||||
if (::epoll_ctl(m_epoll_fd, EPOLL_CTL_DEL, fd, nullptr) < 0) {
|
||||
/// @todo error_handling
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ssize_t unixRead(int fd, void *buffer, size_t length);
|
||||
ssize_t unixWrite(int fd, const void *buffer, size_t length);
|
||||
ssize_t unix_read(int fd, void *buffer, size_t length);
|
||||
ssize_t unix_write(int fd, const void *buffer, size_t length);
|
||||
|
||||
class UnixIoStream final : public IoStream, public IFdOwner {
|
||||
class unix_io_stream final : public IoStream, public i_fd_owner {
|
||||
private:
|
||||
Own<ConveyorFeeder<void>> read_ready = nullptr;
|
||||
Own<ConveyorFeeder<void>> on_read_disconnect = nullptr;
|
||||
Own<ConveyorFeeder<void>> write_ready = nullptr;
|
||||
Own<ConveyorFeeder<void>> m_read_ready = nullptr;
|
||||
Own<ConveyorFeeder<void>> m_on_read_disconnect = nullptr;
|
||||
Own<ConveyorFeeder<void>> m_write_ready = nullptr;
|
||||
|
||||
public:
|
||||
UnixIoStream(UnixEventPort &event_port, int file_descriptor, int fd_flags,
|
||||
uint32_t event_mask);
|
||||
unix_io_stream(UnixEventPort &event_port, int file_descriptor, int fd_flags,
|
||||
uint32_t event_mask);
|
||||
|
||||
ErrorOr<size_t> read(void *buffer, size_t length) override;
|
||||
|
||||
Conveyor<void> readReady() override;
|
||||
Conveyor<void> read_ready() override;
|
||||
|
||||
Conveyor<void> onReadDisconnected() override;
|
||||
Conveyor<void> on_read_disconnected() override;
|
||||
|
||||
ErrorOr<size_t> write(const void *buffer, size_t length) override;
|
||||
|
||||
Conveyor<void> writeReady() override;
|
||||
Conveyor<void> write_ready() override;
|
||||
|
||||
/*
|
||||
void read(void *buffer, size_t min_length, size_t max_length) override;
|
||||
|
@ -300,32 +299,32 @@ public:
|
|||
void notify(uint32_t mask) override;
|
||||
};
|
||||
|
||||
class UnixServer final : public Server, public IFdOwner {
|
||||
class unix_server final : public Server, public i_fd_owner {
|
||||
private:
|
||||
Own<ConveyorFeeder<Own<IoStream>>> accept_feeder = nullptr;
|
||||
Own<ConveyorFeeder<Own<IoStream>>> m_accept_feeder = nullptr;
|
||||
|
||||
public:
|
||||
UnixServer(UnixEventPort &event_port, int file_descriptor, int fd_flags);
|
||||
unix_server(UnixEventPort &event_port, int file_descriptor, int fd_flags);
|
||||
|
||||
Conveyor<Own<IoStream>> accept() override;
|
||||
|
||||
void notify(uint32_t mask) override;
|
||||
};
|
||||
|
||||
class UnixDatagram final : public Datagram, public IFdOwner {
|
||||
class unix_datagram final : public Datagram, public i_fd_owner {
|
||||
private:
|
||||
Own<ConveyorFeeder<void>> read_ready = nullptr;
|
||||
Own<ConveyorFeeder<void>> write_ready = nullptr;
|
||||
Own<ConveyorFeeder<void>> m_read_ready = nullptr;
|
||||
Own<ConveyorFeeder<void>> m_write_ready = nullptr;
|
||||
|
||||
public:
|
||||
UnixDatagram(UnixEventPort &event_port, int file_descriptor, int fd_flags);
|
||||
unix_datagram(UnixEventPort &event_port, int file_descriptor, int fd_flags);
|
||||
|
||||
ErrorOr<size_t> read(void *buffer, size_t length) override;
|
||||
Conveyor<void> readReady() override;
|
||||
Conveyor<void> read_ready() override;
|
||||
|
||||
ErrorOr<size_t> write(const void *buffer, size_t length,
|
||||
NetworkAddress &dest) override;
|
||||
Conveyor<void> writeReady() override;
|
||||
Conveyor<void> write_ready() override;
|
||||
|
||||
void notify(uint32_t mask) override;
|
||||
};
|
||||
|
@ -333,7 +332,7 @@ public:
|
|||
/**
|
||||
* Helper class which provides potential addresses to NetworkAddress
|
||||
*/
|
||||
class SocketAddress {
|
||||
class socket_address {
|
||||
private:
|
||||
union {
|
||||
struct sockaddr generic;
|
||||
|
@ -341,47 +340,47 @@ private:
|
|||
struct sockaddr_in inet;
|
||||
struct sockaddr_in6 inet6;
|
||||
struct sockaddr_storage storage;
|
||||
} address;
|
||||
} m_address;
|
||||
|
||||
socklen_t address_length;
|
||||
bool wildcard;
|
||||
socklen_t m_address_length;
|
||||
bool m_wildcard;
|
||||
|
||||
SocketAddress() : wildcard{false} {}
|
||||
socket_address() : m_wildcard{false} {}
|
||||
|
||||
public:
|
||||
SocketAddress(const void *sockaddr, socklen_t len, bool wildcard)
|
||||
: address_length{len}, wildcard{wildcard} {
|
||||
assert(len <= sizeof(address));
|
||||
memcpy(&address.generic, sockaddr, len);
|
||||
socket_address(const void *sockaddr, socklen_t len, bool wildcard)
|
||||
: m_address_length{len}, m_wildcard{wildcard} {
|
||||
assert(len <= sizeof(m_address));
|
||||
memcpy(&m_address.generic, sockaddr, len);
|
||||
}
|
||||
|
||||
int socket(int type) const {
|
||||
type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
|
||||
|
||||
int result = ::socket(address.generic.sa_family, type, 0);
|
||||
int result = ::socket(m_address.generic.sa_family, type, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool bind(int fd) const {
|
||||
if (wildcard) {
|
||||
if (m_wildcard) {
|
||||
int value = 0;
|
||||
::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
|
||||
}
|
||||
int error = ::bind(fd, &address.generic, address_length);
|
||||
int error = ::bind(fd, &m_address.generic, m_address_length);
|
||||
return error < 0;
|
||||
}
|
||||
|
||||
struct ::sockaddr *getRaw() {
|
||||
return &address.generic;
|
||||
struct ::sockaddr *get_raw() {
|
||||
return &m_address.generic;
|
||||
}
|
||||
|
||||
const struct ::sockaddr *getRaw() const { return &address.generic; }
|
||||
const struct ::sockaddr *get_raw() const { return &m_address.generic; }
|
||||
|
||||
socklen_t getRawLength() const { return address_length; }
|
||||
socklen_t get_raw_length() const { return m_address_length; }
|
||||
|
||||
static std::vector<SocketAddress> parse(std::string_view str,
|
||||
uint16_t port_hint) {
|
||||
std::vector<SocketAddress> results;
|
||||
static std::vector<socket_address> resolve(std::string_view str,
|
||||
uint16_t port_hint) {
|
||||
std::vector<socket_address> results;
|
||||
|
||||
struct ::addrinfo *head;
|
||||
struct ::addrinfo hints;
|
||||
|
@ -400,7 +399,7 @@ public:
|
|||
}
|
||||
|
||||
for (struct ::addrinfo *it = head; it != nullptr; it = it->ai_next) {
|
||||
if (it->ai_addrlen > sizeof(SocketAddress::address)) {
|
||||
if (it->ai_addrlen > sizeof(socket_address::m_address)) {
|
||||
continue;
|
||||
}
|
||||
results.push_back({it->ai_addr, it->ai_addrlen, wildcard});
|
||||
|
@ -410,35 +409,36 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class UnixNetworkAddress final : public OsNetworkAddress {
|
||||
class unix_network_address final : public OsNetworkAddress {
|
||||
private:
|
||||
const std::string path;
|
||||
uint16_t port_hint;
|
||||
std::vector<SocketAddress> addresses;
|
||||
const std::string m_path;
|
||||
uint16_t m_port_hint;
|
||||
std::vector<socket_address> m_addresses;
|
||||
|
||||
public:
|
||||
UnixNetworkAddress(const std::string &path, uint16_t port_hint,
|
||||
std::vector<SocketAddress> &&addr)
|
||||
: path{path}, port_hint{port_hint}, addresses{std::move(addr)} {}
|
||||
unix_network_address(const std::string &path, uint16_t port_hint,
|
||||
std::vector<socket_address> &&addr)
|
||||
: m_path{path}, m_port_hint{port_hint}, addresses{std::move(addr)} {}
|
||||
|
||||
const std::string &address() const override;
|
||||
|
||||
uint16_t port() const override;
|
||||
|
||||
// Custom address info
|
||||
SocketAddress &unixAddress(size_t i = 0);
|
||||
size_t unixAddressSize() const;
|
||||
socket_address &unix_address(size_t i = 0);
|
||||
size_t unix_address_size() const;
|
||||
};
|
||||
|
||||
class UnixNetwork final : public Network {
|
||||
class unix_network final : public Network {
|
||||
private:
|
||||
UnixEventPort &event_port;
|
||||
UnixEventPort &m_event_port;
|
||||
|
||||
public:
|
||||
UnixNetwork(UnixEventPort &event_port);
|
||||
unix_network(UnixEventPort &event_port);
|
||||
|
||||
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &address,
|
||||
uint16_t port_hint = 0) override;
|
||||
Conveyor<Own<NetworkAddress>>
|
||||
resolve_address(const std::string &address,
|
||||
uint16_t port_hint = 0) override;
|
||||
|
||||
Own<Server> listen(NetworkAddress &addr) override;
|
||||
|
||||
|
@ -447,21 +447,21 @@ public:
|
|||
Own<Datagram> datagram(NetworkAddress &addr) override;
|
||||
};
|
||||
|
||||
class UnixIoProvider final : public IoProvider {
|
||||
class unix_io_provider final : public IoProvider {
|
||||
private:
|
||||
UnixEventPort &event_port;
|
||||
EventLoop event_loop;
|
||||
UnixEventPort &m_event_port;
|
||||
EventLoop m_event_loop;
|
||||
|
||||
UnixNetwork unix_network;
|
||||
unix_network m_unix_network;
|
||||
|
||||
public:
|
||||
UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port);
|
||||
unix_io_provider(UnixEventPort &port_ref, Own<EventPort> port);
|
||||
|
||||
Network &network() override;
|
||||
|
||||
Own<InputStream> wrapInputFd(int fd) override;
|
||||
Own<InputStream> wrap_input_fd(int fd) override;
|
||||
|
||||
EventLoop &eventLoop();
|
||||
EventLoop &event_loop();
|
||||
};
|
||||
} // namespace unix
|
||||
} // namespace saw
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
with import <nixpkgs> {};
|
||||
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
pkgs.mkShellNoCC {
|
||||
name = "forstio";
|
||||
nativeBuildInputs = [
|
||||
scons
|
||||
clang-tools_12
|
||||
clang-analyzer
|
||||
clang_12
|
||||
cppcheck
|
||||
];
|
||||
|
||||
buildInputs = [ gnutls ];
|
||||
}
|
|
@ -12,5 +12,25 @@ dir_path = Dir('.').abspath
|
|||
env.sources += sorted(glob.glob(dir_path + "/*.cpp"))
|
||||
env.headers += sorted(glob.glob(dir_path + "/*.h"))
|
||||
|
||||
env.tls_sources += sorted(glob.glob(dir_path + "/tls/*.cpp"))
|
||||
env.tls_headers += sorted(glob.glob(dir_path + "/tls/*.h"))
|
||||
# Environment for base library
|
||||
base_lib_env = env.Clone();
|
||||
|
||||
## Shared lib
|
||||
objects_shared = []
|
||||
base_lib_env.add_source_files(objects_shared, env.sources + env.driver_sources, shared=True);
|
||||
env.library_shared = base_lib_env.SharedLibrary('#build/forstio', [objects_shared]);
|
||||
|
||||
## Static lib
|
||||
objects_static = []
|
||||
base_lib_env.add_source_files(objects_static, env.sources + env.driver_sources, shared=False);
|
||||
env.library_static = base_lib_env.StaticLibrary('#build/forstio', [objects_static]);
|
||||
|
||||
# Export to other libs
|
||||
Export('base_lib_env')
|
||||
|
||||
#SConscript("rpc/SConscript");
|
||||
SConscript("tls/SConscript");
|
||||
|
||||
# Set Alias
|
||||
env.Alias('library_base', [env.library_shared, env.library_static]);
|
||||
env.Alias('library', ['library_base', 'library_tls']);
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#include "async.h"
|
||||
#include "common.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
@ -7,7 +9,7 @@ namespace saw {
|
|||
namespace {
|
||||
thread_local EventLoop *local_loop = nullptr;
|
||||
|
||||
EventLoop ¤tEventLoop() {
|
||||
EventLoop ¤t_event_loop() {
|
||||
EventLoop *loop = local_loop;
|
||||
assert(loop);
|
||||
return *loop;
|
||||
|
@ -16,15 +18,53 @@ EventLoop ¤tEventLoop() {
|
|||
|
||||
ConveyorNode::ConveyorNode() {}
|
||||
|
||||
ConveyorStorage::ConveyorStorage(ConveyorStorage *c) : child_storage{c} {}
|
||||
ConveyorNodeWithChildMixin::ConveyorNodeWithChildMixin(
|
||||
Own<ConveyorNode> &&child_, ConveyorNode &owner)
|
||||
: child{std::move(child_)} {
|
||||
assert(child);
|
||||
|
||||
ConveyorStorage::~ConveyorStorage() {
|
||||
if (parent) {
|
||||
parent->unlinkChild();
|
||||
}
|
||||
child->notifyParentAttached(owner);
|
||||
}
|
||||
|
||||
void ConveyorStorage::unlinkChild() { child_storage = nullptr; }
|
||||
ErrorOr<Own<ConveyorNode>>
|
||||
ConveyorNodeWithChildMixin::swapChild(Own<ConveyorNode> &&swapee) {
|
||||
SAW_ASSERT(child) {
|
||||
return criticalError("Child should exist if this function is called");
|
||||
}
|
||||
Own<ConveyorNode> old_child = std::move(child);
|
||||
|
||||
/**
|
||||
* We need the parent of the old_child's next storage
|
||||
*/
|
||||
ConveyorStorage *old_storage = old_child->nextStorage();
|
||||
ConveyorStorage *old_storage_parent = old_storage ? old_storage->getParent()
|
||||
: nullptr;
|
||||
|
||||
/**
|
||||
* Swap in the new child
|
||||
*/
|
||||
if (swapee) {
|
||||
child = std::move(swapee);
|
||||
|
||||
/**
|
||||
* Then we need to set the new child's storage parent since the next
|
||||
* storage has a nullptr set And if the old_storage_parent is a nullptr,
|
||||
* then it doesn't matter. So we don't check for it
|
||||
*/
|
||||
ConveyorStorage *swapee_storage = child->nextStorage();
|
||||
if (swapee_storage) {
|
||||
swapee_storage->setParent(old_storage_parent);
|
||||
}
|
||||
}
|
||||
|
||||
return old_child;
|
||||
}
|
||||
|
||||
ConveyorStorage::ConveyorStorage() {}
|
||||
|
||||
ConveyorStorage::~ConveyorStorage() {}
|
||||
|
||||
ConveyorStorage *ConveyorStorage::get_parent() const { return parent; }
|
||||
|
||||
void ConveyorEventStorage::setParent(ConveyorStorage *p) {
|
||||
/*
|
||||
|
@ -43,12 +83,10 @@ void ConveyorEventStorage::setParent(ConveyorStorage *p) {
|
|||
parent = p;
|
||||
}
|
||||
|
||||
ConveyorEventStorage::ConveyorEventStorage(ConveyorStorage *c)
|
||||
: ConveyorStorage{c} {}
|
||||
ConveyorEventStorage::ConveyorEventStorage() : ConveyorStorage{} {}
|
||||
|
||||
ConveyorBase::ConveyorBase(Own<ConveyorNode> &&node_p,
|
||||
ConveyorStorage *storage_p)
|
||||
: node{std::move(node_p)}, storage{storage_p} {}
|
||||
ConveyorBase::ConveyorBase(Own<ConveyorNode> &&node_p)
|
||||
: node{std::move(node_p)} {}
|
||||
|
||||
Error PropagateError::operator()(const Error &error) const {
|
||||
return error.copyError();
|
||||
|
@ -56,7 +94,7 @@ Error PropagateError::operator()(const Error &error) const {
|
|||
|
||||
Error PropagateError::operator()(Error &&error) { return std::move(error); }
|
||||
|
||||
Event::Event() : Event(currentEventLoop()) {}
|
||||
Event::Event() : Event(current_event_loop()) {}
|
||||
|
||||
Event::Event(EventLoop &loop) : loop{loop} {}
|
||||
|
||||
|
@ -156,12 +194,12 @@ void Event::disarm() {
|
|||
|
||||
bool Event::isArmed() const { return prev != nullptr; }
|
||||
|
||||
SinkConveyor::SinkConveyor() : node{nullptr} {}
|
||||
ConveyorSink::ConveyorSink() : node{nullptr} {}
|
||||
|
||||
SinkConveyor::SinkConveyor(Own<ConveyorNode> &&node_p)
|
||||
ConveyorSink::ConveyorSink(Own<ConveyorNode> &&node_p)
|
||||
: node{std::move(node_p)} {}
|
||||
|
||||
void EventLoop::setRunnable(bool runnable) { is_runnable = runnable; }
|
||||
void EventLoop::set_runnable(bool runnable) { is_runnable = runnable; }
|
||||
|
||||
EventLoop::EventLoop() {}
|
||||
|
||||
|
@ -170,17 +208,17 @@ EventLoop::EventLoop(Own<EventPort> &&event_port)
|
|||
|
||||
EventLoop::~EventLoop() { assert(local_loop != this); }
|
||||
|
||||
void EventLoop::enterScope() {
|
||||
void EventLoop::enter_scope() {
|
||||
assert(!local_loop);
|
||||
local_loop = this;
|
||||
}
|
||||
|
||||
void EventLoop::leaveScope() {
|
||||
void EventLoop::leave_scope() {
|
||||
assert(local_loop == this);
|
||||
local_loop = nullptr;
|
||||
}
|
||||
|
||||
bool EventLoop::turnLoop() {
|
||||
bool EventLoop::turn_loop() {
|
||||
size_t turn_step = 0;
|
||||
while (head && turn_step < 65536) {
|
||||
if (!turn()) {
|
||||
|
@ -253,11 +291,11 @@ bool EventLoop::poll() {
|
|||
return turnLoop();
|
||||
}
|
||||
|
||||
EventPort *EventLoop::eventPort() { return event_port.get(); }
|
||||
EventPort *EventLoop::event_port() { return event_port.get(); }
|
||||
|
||||
ConveyorSinks &EventLoop::daemon() {
|
||||
ConveyorSinkSet &EventLoop::daemon() {
|
||||
if (!daemon_sink) {
|
||||
daemon_sink = heap<ConveyorSinks>();
|
||||
daemon_sink = heap<ConveyorSinkSet>();
|
||||
}
|
||||
return *daemon_sink;
|
||||
}
|
||||
|
@ -278,13 +316,29 @@ void WaitScope::wait(const std::chrono::steady_clock::time_point &time_point) {
|
|||
|
||||
void WaitScope::poll() { loop.poll(); }
|
||||
|
||||
ErrorOr<Own<ConveyorNode>>
|
||||
ConvertConveyorNodeBase::swapChild(Own<ConveyorNode> &&swapee) noexcept {
|
||||
return child_mixin.swapChild(std::move(swapee));
|
||||
}
|
||||
|
||||
ConveyorStorage *ConvertConveyorNodeBase::nextStorage() noexcept {
|
||||
if (!child_mixin.child) {
|
||||
return nullptr;
|
||||
}
|
||||
return child_mixin.child->nextStorage();
|
||||
}
|
||||
|
||||
ImmediateConveyorNodeBase::ImmediateConveyorNodeBase()
|
||||
: ConveyorEventStorage{nullptr} {}
|
||||
: ConveyorEventStorage{} {}
|
||||
|
||||
MergeConveyorNodeBase::MergeConveyorNodeBase()
|
||||
: ConveyorEventStorage{nullptr} {}
|
||||
MergeConveyorNodeBase::MergeConveyorNodeBase() : ConveyorEventStorage{} {}
|
||||
|
||||
void ConveyorSinks::destroySinkConveyorNode(ConveyorNode &node) {
|
||||
ErrorOr<Own<ConveyorNode>>
|
||||
QueueBufferConveyorNodeBase::swapChild(Own<ConveyorNode> &&swapee_) noexcept {
|
||||
return child_mixin.swapChild(std::move(swapee_));
|
||||
}
|
||||
|
||||
void ConveyorSinkSet::destroySinkConveyorNode(ConveyorNode &node) {
|
||||
if (!isArmed()) {
|
||||
armLast();
|
||||
}
|
||||
|
@ -292,30 +346,31 @@ void ConveyorSinks::destroySinkConveyorNode(ConveyorNode &node) {
|
|||
delete_nodes.push(&node);
|
||||
}
|
||||
|
||||
void ConveyorSinks::fail(Error &&error) {
|
||||
void ConveyorSinkSet::fail(Error &&error) {
|
||||
/// @todo call error_handler
|
||||
}
|
||||
|
||||
ConveyorSinks::ConveyorSinks(EventLoop &event_loop) : Event{event_loop} {}
|
||||
ConveyorSinkSet::ConveyorSinkSet(EventLoop &event_loop) : Event{event_loop} {}
|
||||
|
||||
void ConveyorSinks::add(Conveyor<void> &&sink) {
|
||||
void ConveyorSinkSet::add(Conveyor<void> &&sink) {
|
||||
auto nas = Conveyor<void>::fromConveyor(std::move(sink));
|
||||
SAW_ASSERT(nas) { return; }
|
||||
ConveyorStorage *storage = nas->nextStorage();
|
||||
|
||||
Own<SinkConveyorNode> sink_node = nullptr;
|
||||
try {
|
||||
sink_node =
|
||||
heap<SinkConveyorNode>(nas.second, std::move(nas.first), *this);
|
||||
sink_node = heap<SinkConveyorNode>(std::move(nas), *this);
|
||||
} catch (std::bad_alloc &) {
|
||||
return;
|
||||
}
|
||||
if (nas.second) {
|
||||
nas.second->setParent(sink_node.get());
|
||||
if (storage) {
|
||||
storage->setParent(sink_node.get());
|
||||
}
|
||||
|
||||
sink_nodes.emplace_back(std::move(sink_node));
|
||||
}
|
||||
|
||||
void ConveyorSinks::fire() {
|
||||
void ConveyorSinkSet::fire() {
|
||||
while (!delete_nodes.empty()) {
|
||||
ConveyorNode *node = delete_nodes.front();
|
||||
/*auto erased = */ std::remove_if(sink_nodes.begin(), sink_nodes.end(),
|
||||
|
@ -327,21 +382,34 @@ void ConveyorSinks::fire() {
|
|||
}
|
||||
|
||||
ConvertConveyorNodeBase::ConvertConveyorNodeBase(Own<ConveyorNode> &&dep)
|
||||
: child{std::move(dep)} {}
|
||||
: child_mixin{std::move(dep), *this} {}
|
||||
|
||||
void ConvertConveyorNodeBase::getResult(ErrorOrValue &err_or_val) {
|
||||
getImpl(err_or_val);
|
||||
}
|
||||
|
||||
void AttachConveyorNodeBase::getResult(ErrorOrValue &err_or_val) noexcept {
|
||||
if (child) {
|
||||
child->getResult(err_or_val);
|
||||
if (child_mixin.child) {
|
||||
child_mixin.child->getResult(err_or_val);
|
||||
}
|
||||
}
|
||||
|
||||
void detachConveyor(Conveyor<void> &&conveyor) {
|
||||
EventLoop &loop = currentEventLoop();
|
||||
ConveyorSinks &sink = loop.daemon();
|
||||
ErrorOr<Own<ConveyorNode>>
|
||||
AttachConveyorNodeBase::swapChild(Own<ConveyorNode> &&swapee_) noexcept {
|
||||
return child_mixin.swapChild(std::move(swapee_));
|
||||
}
|
||||
|
||||
ConveyorStorage *AttachConveyorNodeBase::nextStorage() noexcept {
|
||||
if (!child_mixin.child) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return child_mixin.child->nextStorage();
|
||||
}
|
||||
|
||||
void detach_conveyor(Conveyor<void> &&conveyor) {
|
||||
EventLoop &loop = current_event_loop();
|
||||
ConveyorSinkSet &sink = loop.daemon();
|
||||
sink.add(std::move(conveyor));
|
||||
}
|
||||
} // namespace saw
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "error.h"
|
||||
|
||||
#include <cassert>
|
||||
// Template inlining
|
||||
|
@ -9,105 +10,115 @@
|
|||
|
||||
namespace saw {
|
||||
|
||||
template <typename Func> ConveyorResult<Func, void> execLater(Func &&func) {
|
||||
template <typename Func> ConveyorResult<Func, void> exec_later(Func &&func) {
|
||||
Conveyor<void> conveyor{FixVoid<void>{}};
|
||||
return conveyor.then(std::move(func));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Conveyor<T>::Conveyor(FixVoid<T> value) : ConveyorBase(nullptr, nullptr) {
|
||||
Conveyor<T>::Conveyor(FixVoid<T> value) : conveyor_base(nullptr) {
|
||||
// Is there any way to do this?
|
||||
// @todo new ConveyorBase constructor for Immediate values
|
||||
|
||||
Own<ImmediateConveyorNode<FixVoid<T>>> immediate =
|
||||
heap<ImmediateConveyorNode<FixVoid<T>>>(std::move(value));
|
||||
Own<immediate_conveyor_node<FixVoid<T>>> immediate =
|
||||
heap<immediate_conveyor_node<FixVoid<T>>>(std::move(value));
|
||||
|
||||
if (!immediate) {
|
||||
return;
|
||||
}
|
||||
|
||||
storage = static_cast<ConveyorStorage *>(immediate.get());
|
||||
node = std::move(immediate);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Conveyor<T>::Conveyor(Error &&error) : ConveyorBase(nullptr, nullptr) {
|
||||
Own<ImmediateConveyorNode<FixVoid<T>>> immediate =
|
||||
heap<ImmediateConveyorNode<FixVoid<T>>>(std::move(error));
|
||||
Conveyor<T>::Conveyor(Error &&error) : conveyor_base(nullptr) {
|
||||
Own<immediate_conveyor_node<FixVoid<T>>> immediate =
|
||||
heap<immediate_conveyor_node<FixVoid<T>>>(std::move(error));
|
||||
|
||||
if (!immediate) {
|
||||
return;
|
||||
}
|
||||
|
||||
storage = static_cast<ConveyorStorage *>(immediate.get());
|
||||
node = std::move(immediate);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Conveyor<T>::Conveyor(Own<ConveyorNode> node_p, ConveyorStorage *storage_p)
|
||||
: ConveyorBase{std::move(node_p), storage_p} {}
|
||||
Conveyor<T>::Conveyor(Own<conveyor_node> node_p)
|
||||
: conveyor_base{std::move(node_p)} {}
|
||||
|
||||
template <typename T>
|
||||
template <typename Func, typename ErrorFunc>
|
||||
ConveyorResult<Func, T> Conveyor<T>::then(Func &&func, ErrorFunc &&error_func) {
|
||||
Own<ConveyorNode> conversion_node =
|
||||
heap<ConvertConveyorNode<FixVoid<ReturnType<Func, T>>, FixVoid<T>, Func,
|
||||
ErrorFunc>>(std::move(node), std::move(func),
|
||||
std::move(error_func));
|
||||
Own<conveyor_node> conversion_node =
|
||||
heap<convert_conveyor_node<FixVoid<ReturnType<Func, T>>, FixVoid<T>,
|
||||
Func, ErrorFunc>>(
|
||||
std::move(node), std::move(func), std::move(error_func));
|
||||
|
||||
return Conveyor<RemoveErrorOr<ReturnType<Func, T>>>::toConveyor(
|
||||
std::move(conversion_node), storage);
|
||||
return Conveyor<RemoveErrorOr<ReturnType<Func, T>>>::to_conveyor(
|
||||
std::move(conversion_node));
|
||||
}
|
||||
|
||||
template <typename T> Conveyor<T> Conveyor<T>::buffer(size_t size) {
|
||||
Own<QueueBufferConveyorNode<FixVoid<T>>> storage_node =
|
||||
heap<QueueBufferConveyorNode<FixVoid<T>>>(storage, std::move(node),
|
||||
size);
|
||||
SAW_ASSERT(node) { return Conveyor<T>{Own<conveyor_node>{nullptr}}; }
|
||||
ConveyorStorage *storage = node->next_storage();
|
||||
SAW_ASSERT(storage) { return Conveyor<T>{Own<conveyor_node>{nullptr}}; }
|
||||
|
||||
Own<queue_buffer_conveyor_node<FixVoid<T>>> storage_node =
|
||||
heap<queue_buffer_conveyor_node<FixVoid<T>>>(std::move(node), size);
|
||||
|
||||
ConveyorStorage *storage_ptr =
|
||||
static_cast<ConveyorStorage *>(storage_node.get());
|
||||
SAW_ASSERT(storage) { return Conveyor<T>{nullptr, nullptr}; }
|
||||
|
||||
storage->setParent(storage_ptr);
|
||||
return Conveyor<T>{std::move(storage_node), storage_ptr};
|
||||
storage->set_parent(storage_ptr);
|
||||
return Conveyor<T>{std::move(storage_node)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename... Args>
|
||||
Conveyor<T> Conveyor<T>::attach(Args &&...args) {
|
||||
Own<AttachConveyorNode<Args...>> attach_node =
|
||||
heap<AttachConveyorNode<Args...>>(std::move(node), std::move(args...));
|
||||
return Conveyor<T>{std::move(attach_node), storage};
|
||||
Own<attach_conveyor_node<Args...>> attach_node =
|
||||
heap<attach_conveyor_node<Args...>>(std::move(node),
|
||||
std::move(args...));
|
||||
return Conveyor<T>{std::move(attach_node)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::pair<Conveyor<T>, MergeConveyor<T>> Conveyor<T>::merge() {
|
||||
std::pair<Conveyor<T>, merge_conveyor<T>> Conveyor<T>::merge() {
|
||||
Our<MergeConveyorNodeData<T>> data = share<MergeConveyorNodeData<T>>();
|
||||
|
||||
Own<MergeConveyorNode<T>> merge_node = heap<MergeConveyorNode<T>>(data);
|
||||
Own<merge_conveyor_node<T>> merge_node = heap<merge_conveyor_node<T>>(data);
|
||||
|
||||
data->attach(Conveyor<T>::toConveyor(std::move(node), storage));
|
||||
SAW_ASSERT(node) {
|
||||
return std::make_pair(Conveyor<T>{Own<conveyor_node>{nullptr}},
|
||||
merge_conveyor<T>{});
|
||||
}
|
||||
ConveyorStorage *storage = node->next_storage();
|
||||
SAW_ASSERT(storage) {
|
||||
return std::make_pair(Conveyor<T>{Own<conveyor_node>{nullptr}},
|
||||
merge_conveyor<T>{});
|
||||
}
|
||||
|
||||
MergeConveyor<T> node_ref{data};
|
||||
data->attach(Conveyor<T>::to_conveyor(std::move(node)));
|
||||
|
||||
ConveyorStorage *merge_storage =
|
||||
static_cast<ConveyorStorage *>(merge_node.get());
|
||||
merge_conveyor<T> node_ref{data};
|
||||
|
||||
return std::make_pair(Conveyor<T>{std::move(merge_node), merge_storage},
|
||||
return std::make_pair(Conveyor<T>{std::move(merge_node)},
|
||||
std::move(node_ref));
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename ErrorFunc>
|
||||
SinkConveyor Conveyor<void>::sink(ErrorFunc &&error_func) {
|
||||
Own<SinkConveyorNode> sink_node =
|
||||
heap<SinkConveyorNode>(storage, std::move(node));
|
||||
conveyor_sink Conveyor<void>::sink(ErrorFunc &&error_func) {
|
||||
ConveyorStorage *storage = node->next_storage();
|
||||
SAW_ASSERT(storage) { return conveyor_sink{}; }
|
||||
|
||||
Own<SinkConveyorNode> sink_node = heap<SinkConveyorNode>(std::move(node));
|
||||
ConveyorStorage *storage_ptr =
|
||||
static_cast<ConveyorStorage *>(sink_node.get());
|
||||
|
||||
SAW_ASSERT(storage) { return SinkConveyor{}; }
|
||||
storage->setParent(storage_ptr);
|
||||
storage->set_parent(storage_ptr);
|
||||
|
||||
return SinkConveyor{std::move(sink_node)};
|
||||
return conveyor_sink{std::move(sink_node)};
|
||||
}
|
||||
|
||||
void detachConveyor(Conveyor<void> &&conveyor);
|
||||
|
@ -125,56 +136,55 @@ void Conveyor<void>::detach(ErrorFunc &&func) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
Conveyor<T> Conveyor<T>::toConveyor(Own<ConveyorNode> node,
|
||||
ConveyorStorage *storage) {
|
||||
return Conveyor<T>{std::move(node), storage};
|
||||
Conveyor<T> Conveyor<T>::to_conveyor(Own<conveyor_node> node) {
|
||||
return Conveyor<T>{std::move(node)};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::pair<Own<ConveyorNode>, ConveyorStorage *>
|
||||
Conveyor<T>::fromConveyor(Conveyor<T> conveyor) {
|
||||
return std::make_pair(std::move(conveyor.node), conveyor.storage);
|
||||
Own<conveyor_node> Conveyor<T>::from_conveyor(Conveyor<T> conveyor) {
|
||||
return std::move(conveyor.node);
|
||||
}
|
||||
|
||||
template <typename T> ErrorOr<FixVoid<T>> Conveyor<T>::take() {
|
||||
SAW_ASSERT(node) {
|
||||
return ErrorOr<FixVoid<T>>{criticalError("Conveyor in invalid state")};
|
||||
}
|
||||
ConveyorStorage *storage = node->next_storage();
|
||||
if (storage) {
|
||||
if (storage->queued() > 0) {
|
||||
ErrorOr<FixVoid<T>> result;
|
||||
node->getResult(result);
|
||||
node->get_result(result);
|
||||
return result;
|
||||
} else {
|
||||
return ErrorOr<FixVoid<T>>{
|
||||
recoverableError("Conveyor buffer has no elements")};
|
||||
}
|
||||
} else {
|
||||
return ErrorOr<FixVoid<T>>{criticalError("Conveyor in invalid state")};
|
||||
return ErrorOr<FixVoid<T>>{
|
||||
criticalError("Conveyor node has no child storage")};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> ConveyorAndFeeder<T> newConveyorAndFeeder() {
|
||||
Own<AdaptConveyorFeeder<FixVoid<T>>> feeder =
|
||||
heap<AdaptConveyorFeeder<FixVoid<T>>>();
|
||||
template <typename T> ConveyorAndFeeder<T> new_conveyor_and_feeder() {
|
||||
Own<adapt_conveyor_feeder<FixVoid<T>>> feeder =
|
||||
heap<adapt_conveyor_feeder<FixVoid<T>>>();
|
||||
Own<AdaptConveyorNode<FixVoid<T>>> node =
|
||||
heap<AdaptConveyorNode<FixVoid<T>>>();
|
||||
|
||||
feeder->setFeedee(node.get());
|
||||
node->setFeeder(feeder.get());
|
||||
|
||||
ConveyorStorage *storage_ptr = static_cast<ConveyorStorage *>(node.get());
|
||||
|
||||
return ConveyorAndFeeder<T>{
|
||||
std::move(feeder),
|
||||
Conveyor<T>::toConveyor(std::move(node), storage_ptr)};
|
||||
return ConveyorAndFeeder<T>{std::move(feeder),
|
||||
Conveyor<T>::toConveyor(std::move(node))};
|
||||
}
|
||||
|
||||
// QueueBuffer
|
||||
template <typename T> void QueueBufferConveyorNode<T>::fire() {
|
||||
if (child) {
|
||||
template <typename T> void queue_buffer_conveyor_node<T>::fire() {
|
||||
if (child_mixin.child) {
|
||||
if (!storage.empty()) {
|
||||
if (storage.front().isError()) {
|
||||
if (storage.front().error().isCritical()) {
|
||||
child = nullptr;
|
||||
child_storage = nullptr;
|
||||
child_mixin.child = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -183,51 +193,58 @@ template <typename T> void QueueBufferConveyorNode<T>::fire() {
|
|||
bool has_space_before_fire = space() > 0;
|
||||
|
||||
if (parent) {
|
||||
parent->childHasFired();
|
||||
parent->child_has_fired();
|
||||
if (!storage.empty() && parent->space() > 0) {
|
||||
armLater();
|
||||
arm_later();
|
||||
}
|
||||
}
|
||||
|
||||
if (child_storage && !has_space_before_fire) {
|
||||
child_storage->parentHasFired();
|
||||
if (!child_mixin.child) {
|
||||
while (!storage.empty()) {
|
||||
storage.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ConveyorStorage *ch_storage = child_mixin.child->next_storage();
|
||||
if (ch_storage && !has_space_before_fire) {
|
||||
ch_storage->parent_has_fired();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void QueueBufferConveyorNode<T>::getResult(ErrorOrValue &eov) noexcept {
|
||||
void queue_buffer_conveyor_node<T>::get_result(ErrorOrValue &eov) noexcept {
|
||||
ErrorOr<T> &err_or_val = eov.as<T>();
|
||||
err_or_val = std::move(storage.front());
|
||||
storage.pop();
|
||||
}
|
||||
|
||||
template <typename T> size_t QueueBufferConveyorNode<T>::space() const {
|
||||
template <typename T> size_t queue_buffer_conveyor_node<T>::space() const {
|
||||
return max_store - storage.size();
|
||||
}
|
||||
|
||||
template <typename T> size_t QueueBufferConveyorNode<T>::queued() const {
|
||||
template <typename T> size_t queue_buffer_conveyor_node<T>::queued() const {
|
||||
return storage.size();
|
||||
}
|
||||
|
||||
template <typename T> void QueueBufferConveyorNode<T>::childHasFired() {
|
||||
if (child && storage.size() < max_store) {
|
||||
template <typename T> void queue_buffer_conveyor_node<T>::child_has_fired() {
|
||||
if (child_mixin.child && storage.size() < max_store) {
|
||||
ErrorOr<T> eov;
|
||||
child->getResult(eov);
|
||||
child_mixin.child->get_result(eov);
|
||||
|
||||
if (eov.isError()) {
|
||||
if (eov.error().isCritical()) {
|
||||
child_storage = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
storage.push(std::move(eov));
|
||||
if (!isArmed()) {
|
||||
armLater();
|
||||
if (!is_armed()) {
|
||||
arm_later();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void QueueBufferConveyorNode<T>::parentHasFired() {
|
||||
template <typename T> void queue_buffer_conveyor_node<T>::parent_has_fired() {
|
||||
SAW_ASSERT(parent) { return; }
|
||||
|
||||
if (parent->space() == 0) {
|
||||
|
@ -235,57 +252,57 @@ template <typename T> void QueueBufferConveyorNode<T>::parentHasFired() {
|
|||
}
|
||||
|
||||
if (queued() > 0) {
|
||||
armLater();
|
||||
arm_later();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ImmediateConveyorNode<T>::ImmediateConveyorNode(FixVoid<T> &&val)
|
||||
immediate_conveyor_node<T>::immediate_conveyor_node(FixVoid<T> &&val)
|
||||
: value{std::move(val)}, retrieved{0} {}
|
||||
|
||||
template <typename T>
|
||||
ImmediateConveyorNode<T>::ImmediateConveyorNode(Error &&error)
|
||||
immediate_conveyor_node<T>::immediate_conveyor_node(Error &&error)
|
||||
: value{std::move(error)}, retrieved{0} {}
|
||||
|
||||
template <typename T> size_t ImmediateConveyorNode<T>::space() const {
|
||||
template <typename T> size_t immediate_conveyor_node<T>::space() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T> size_t ImmediateConveyorNode<T>::queued() const {
|
||||
template <typename T> size_t immediate_conveyor_node<T>::queued() const {
|
||||
return retrieved > 1 ? 0 : 1;
|
||||
}
|
||||
|
||||
template <typename T> void ImmediateConveyorNode<T>::childHasFired() {
|
||||
template <typename T> void immediate_conveyor_node<T>::child_has_fired() {
|
||||
// Impossible case
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <typename T> void ImmediateConveyorNode<T>::parentHasFired() {
|
||||
template <typename T> void immediate_conveyor_node<T>::parent_has_fired() {
|
||||
SAW_ASSERT(parent) { return; }
|
||||
assert(parent->space() > 0);
|
||||
|
||||
if (queued() > 0) {
|
||||
armNext();
|
||||
arm_next();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void ImmediateConveyorNode<T>::fire() {
|
||||
template <typename T> void immediate_conveyor_node<T>::fire() {
|
||||
|
||||
if (parent) {
|
||||
parent->childHasFired();
|
||||
parent->child_has_fired();
|
||||
if (queued() > 0 && parent->space() > 0) {
|
||||
armLast();
|
||||
arm_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
MergeConveyor<T>::MergeConveyor(Lent<MergeConveyorNodeData<T>> d)
|
||||
merge_conveyor<T>::merge_conveyor(Lent<MergeConveyorNodeData<T>> d)
|
||||
: data{std::move(d)} {}
|
||||
|
||||
template <typename T> MergeConveyor<T>::~MergeConveyor() {}
|
||||
template <typename T> merge_conveyor<T>::~merge_conveyor() {}
|
||||
|
||||
template <typename T> void MergeConveyor<T>::attach(Conveyor<T> conveyor) {
|
||||
template <typename T> void merge_conveyor<T>::attach(Conveyor<T> conveyor) {
|
||||
auto sp = data.lock();
|
||||
SAW_ASSERT(sp) { return; }
|
||||
|
||||
|
@ -293,17 +310,25 @@ template <typename T> void MergeConveyor<T>::attach(Conveyor<T> conveyor) {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
MergeConveyorNode<T>::MergeConveyorNode(Our<MergeConveyorNodeData<T>> d)
|
||||
merge_conveyor_node<T>::merge_conveyor_node(Our<MergeConveyorNodeData<T>> d)
|
||||
: data{d} {
|
||||
SAW_ASSERT(data) { return; }
|
||||
|
||||
data->merger = this;
|
||||
}
|
||||
|
||||
template <typename T> MergeConveyorNode<T>::~MergeConveyorNode() {}
|
||||
template <typename T> merge_conveyor_node<T>::~merge_conveyor_node() {}
|
||||
|
||||
template <typename T>
|
||||
void MergeConveyorNode<T>::getResult(ErrorOrValue &eov) noexcept {
|
||||
ErrorOr<Own<conveyor_node>>
|
||||
merge_conveyor_node<T>::swap_child(Own<conveyor_node> &&swapee_) noexcept {
|
||||
(void)swapee_;
|
||||
return criticalError(
|
||||
"MergeConveyorNode<T>::Appendage should block calls to this class");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void merge_conveyor_node<T>::get_result(ErrorOrValue &eov) noexcept {
|
||||
ErrorOr<FixVoid<T>> &err_or_val = eov.as<FixVoid<T>>();
|
||||
|
||||
SAW_ASSERT(data) { return; }
|
||||
|
@ -333,21 +358,21 @@ void MergeConveyorNode<T>::getResult(ErrorOrValue &eov) noexcept {
|
|||
err_or_val = criticalError("No value in Merge Appendages");
|
||||
}
|
||||
|
||||
template <typename T> void MergeConveyorNode<T>::fire() {
|
||||
template <typename T> void merge_conveyor_node<T>::fire() {
|
||||
SAW_ASSERT(queued() > 0) { return; }
|
||||
|
||||
if (parent) {
|
||||
parent->childHasFired();
|
||||
parent->child_has_fired();
|
||||
|
||||
if (queued() > 0 && parent->space() > 0) {
|
||||
armLater();
|
||||
arm_later();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> size_t MergeConveyorNode<T>::space() const { return 0; }
|
||||
template <typename T> size_t merge_conveyor_node<T>::space() const { return 0; }
|
||||
|
||||
template <typename T> size_t MergeConveyorNode<T>::queued() const {
|
||||
template <typename T> size_t merge_conveyor_node<T>::queued() const {
|
||||
SAW_ASSERT(data) { return 0; }
|
||||
|
||||
size_t queue_count = 0;
|
||||
|
@ -359,42 +384,39 @@ template <typename T> size_t MergeConveyorNode<T>::queued() const {
|
|||
return queue_count;
|
||||
}
|
||||
|
||||
template <typename T> void MergeConveyorNode<T>::childHasFired() {
|
||||
template <typename T> void merge_conveyor_node<T>::child_has_fired() {
|
||||
/// This can never happen
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <typename T> void MergeConveyorNode<T>::parentHasFired() {
|
||||
template <typename T> void merge_conveyor_node<T>::parent_has_fired() {
|
||||
SAW_ASSERT(parent) { return; }
|
||||
if (queued() > 0) {
|
||||
if (parent->space() > 0) {
|
||||
armLater();
|
||||
arm_later();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> size_t MergeConveyorNode<T>::Appendage::space() const {
|
||||
SAW_ASSERT(merger) { return 0; }
|
||||
/**
|
||||
* MergeConveyorNode<T>::Apendage
|
||||
*/
|
||||
|
||||
if (error_or_value.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
template <typename T>
|
||||
ErrorOr<Own<conveyor_node>>
|
||||
merge_conveyor_node<T>::appendage::swap_child(Own<conveyor_node> &&swapee_) {
|
||||
Own<conveyor_node> old_child = std::move(child);
|
||||
|
||||
return 1;
|
||||
}
|
||||
child = std::move(swapee_);
|
||||
|
||||
template <typename T> size_t MergeConveyorNode<T>::Appendage::queued() const {
|
||||
SAW_ASSERT(merger) { return 0; }
|
||||
// This case should never happen
|
||||
SAW_ASSERT(old_child) { return criticalError("No child exists"); }
|
||||
|
||||
if (error_or_value.has_value()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return old_child;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MergeConveyorNode<T>::Appendage::getAppendageResult(ErrorOrValue &eov) {
|
||||
void merge_conveyor_node<T>::appendage::get_result(ErrorOrValue &eov) {
|
||||
ErrorOr<FixVoid<T>> &err_or_val = eov.as<FixVoid<T>>();
|
||||
|
||||
SAW_ASSERT(queued() > 0) {
|
||||
|
@ -406,26 +428,64 @@ void MergeConveyorNode<T>::Appendage::getAppendageResult(ErrorOrValue &eov) {
|
|||
error_or_value = std::nullopt;
|
||||
}
|
||||
|
||||
template <typename T> void MergeConveyorNode<T>::Appendage::childHasFired() {
|
||||
template <typename T> size_t merge_conveyor_node<T>::appendage::space() const {
|
||||
SAW_ASSERT(merger) { return 0; }
|
||||
|
||||
if (error_or_value.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
template <typename T> size_t merge_conveyor_node<T>::appendage::queued() const {
|
||||
SAW_ASSERT(merger) { return 0; }
|
||||
|
||||
if (error_or_value.has_value()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// @todo delete this function. Replaced by the regular getResult
|
||||
template <typename T>
|
||||
void merge_conveyor_node<T>::appendage::get_appendage_result(
|
||||
ErrorOrValue &eov) {
|
||||
ErrorOr<FixVoid<T>> &err_or_val = eov.as<FixVoid<T>>();
|
||||
|
||||
SAW_ASSERT(queued() > 0) {
|
||||
err_or_val = criticalError("No element queued in Merge Appendage Node");
|
||||
return;
|
||||
}
|
||||
|
||||
err_or_val = std::move(error_or_value.value());
|
||||
error_or_value = std::nullopt;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void merge_conveyor_node<T>::appendage::child_has_fired() {
|
||||
SAW_ASSERT(!error_or_value.has_value()) { return; }
|
||||
ErrorOr<FixVoid<T>> eov;
|
||||
child->getResult(eov);
|
||||
child->get_result(eov);
|
||||
|
||||
error_or_value = std::move(eov);
|
||||
|
||||
if (!merger->isArmed()) {
|
||||
merger->armLater();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void MergeConveyorNode<T>::Appendage::parentHasFired() {
|
||||
if (child_storage) {
|
||||
child_storage->parentHasFired();
|
||||
if (!merger->is_armed()) {
|
||||
merger->arm_later();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void MergeConveyorNode<T>::Appendage::setParent(ConveyorStorage *par) {
|
||||
void merge_conveyor_node<T>::appendage::parent_has_fired() {
|
||||
ConveyorStorage *child_storage = child->next_storage();
|
||||
if (child_storage) {
|
||||
child_storage->parent_has_fired();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void merge_conveyor_node<T>::appendage::set_parent(ConveyorStorage *par) {
|
||||
SAW_ASSERT(merger) { return; }
|
||||
|
||||
SAW_ASSERT(child) { return; }
|
||||
|
@ -436,23 +496,38 @@ void MergeConveyorNode<T>::Appendage::setParent(ConveyorStorage *par) {
|
|||
template <typename T>
|
||||
void MergeConveyorNodeData<T>::attach(Conveyor<T> conveyor) {
|
||||
auto nas = Conveyor<T>::fromConveyor(std::move(conveyor));
|
||||
SAW_ASSERT(nas) { return; }
|
||||
ConveyorStorage *storage = nas->nextStorage();
|
||||
SAW_ASSERT(storage) { return; }
|
||||
|
||||
auto merge_node_appendage = heap<typename MergeConveyorNode<T>::Appendage>(
|
||||
nas.second, std::move(nas.first), *merger);
|
||||
auto merge_node_appendage =
|
||||
heap<typename merge_conveyor_node<T>::Appendage>(std::move(nas),
|
||||
*merger);
|
||||
auto merge_node_appendage_ptr = merge_node_appendage.get();
|
||||
|
||||
if (nas.second) {
|
||||
nas.second->setParent(merge_node_appendage.get());
|
||||
}
|
||||
storage->set_parent(merge_node_appendage.get());
|
||||
|
||||
SAW_ASSERT(merger) { return; }
|
||||
|
||||
ConveyorStorage *mrg_storage = merger->nextStorage();
|
||||
SAW_ASSERT(mrg_storage) { return; }
|
||||
|
||||
merge_node_appendage->setParent(mrg_storage);
|
||||
|
||||
appendages.push_back(std::move(merge_node_appendage));
|
||||
|
||||
/// @todo return this. necessary? maybe for the weird linking setup
|
||||
/// maybe not
|
||||
// return merge_node_appendage_ptr;
|
||||
}
|
||||
|
||||
template <typename T> void MergeConveyorNodeData<T>::governingNodeDestroyed() {
|
||||
template <typename T>
|
||||
void MergeConveyorNodeData<T>::governing_node_destroyed() {
|
||||
appendages.clear();
|
||||
merger = nullptr;
|
||||
}
|
||||
|
||||
template <typename T> AdaptConveyorFeeder<T>::~AdaptConveyorFeeder() {
|
||||
template <typename T> adapt_conveyor_feeder<T>::~adapt_conveyor_feeder() {
|
||||
if (feedee) {
|
||||
feedee->setFeeder(nullptr);
|
||||
feedee = nullptr;
|
||||
|
@ -460,30 +535,30 @@ template <typename T> AdaptConveyorFeeder<T>::~AdaptConveyorFeeder() {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void AdaptConveyorFeeder<T>::setFeedee(AdaptConveyorNode<T> *feedee_p) {
|
||||
void adapt_conveyor_feeder<T>::set_feedee(AdaptConveyorNode<T> *feedee_p) {
|
||||
feedee = feedee_p;
|
||||
}
|
||||
|
||||
template <typename T> void AdaptConveyorFeeder<T>::feed(T &&value) {
|
||||
template <typename T> void adapt_conveyor_feeder<T>::feed(T &&value) {
|
||||
if (feedee) {
|
||||
feedee->feed(std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void AdaptConveyorFeeder<T>::fail(Error &&error) {
|
||||
template <typename T> void adapt_conveyor_feeder<T>::fail(Error &&error) {
|
||||
if (feedee) {
|
||||
feedee->fail(std::move(error));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> size_t AdaptConveyorFeeder<T>::queued() const {
|
||||
template <typename T> size_t adapt_conveyor_feeder<T>::queued() const {
|
||||
if (feedee) {
|
||||
return feedee->queued();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T> size_t AdaptConveyorFeeder<T>::space() const {
|
||||
template <typename T> size_t adapt_conveyor_feeder<T>::space() const {
|
||||
if (feedee) {
|
||||
return feedee->space();
|
||||
}
|
||||
|
@ -491,7 +566,18 @@ template <typename T> size_t AdaptConveyorFeeder<T>::space() const {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
AdaptConveyorNode<T>::AdaptConveyorNode() : ConveyorEventStorage{nullptr} {}
|
||||
Error adapt_conveyor_feeder<T>::swap(Conveyor<T> &&conveyor) noexcept {
|
||||
SAW_ASSERT(feedee) { return criticalError("No feedee connected"); }
|
||||
|
||||
auto node = Conveyor<T>::fromConveyor(std::move(conveyor));
|
||||
|
||||
feedee->swapChild(std::move(node));
|
||||
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
AdaptConveyorNode<T>::AdaptConveyorNode() : conveyor_event_storage{} {}
|
||||
|
||||
template <typename T> AdaptConveyorNode<T>::~AdaptConveyorNode() {
|
||||
if (feeder) {
|
||||
|
@ -501,18 +587,45 @@ template <typename T> AdaptConveyorNode<T>::~AdaptConveyorNode() {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void AdaptConveyorNode<T>::setFeeder(AdaptConveyorFeeder<T> *feeder_p) {
|
||||
ErrorOr<Own<conveyor_node>>
|
||||
AdaptConveyorNode<T>::swap_child(Own<conveyor_node> &&swapee) noexcept {
|
||||
// This should return the owning pointer of this instance
|
||||
auto myself_err = parent_node.swap_child_of_parent(std::move(swapee));
|
||||
|
||||
if (myself_err.isError()) {
|
||||
return myself_err;
|
||||
}
|
||||
|
||||
auto &myself = myself_err.value();
|
||||
|
||||
assert(myself.get() == this);
|
||||
|
||||
return myself_err;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ConveyorStorage *AdaptConveyorNode<T>::next_storage() noexcept {
|
||||
return static_cast<ConveyorStorage *>(this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AdaptConveyorNode<T>::notify_parent_attached(conveyor_node &par) noexcept {
|
||||
parent_node.change_parent(&par);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void AdaptConveyorNode<T>::set_feeder(adapt_conveyor_feeder<T> *feeder_p) {
|
||||
feeder = feeder_p;
|
||||
}
|
||||
|
||||
template <typename T> void AdaptConveyorNode<T>::feed(T &&value) {
|
||||
storage.push(std::move(value));
|
||||
armNext();
|
||||
arm_next();
|
||||
}
|
||||
|
||||
template <typename T> void AdaptConveyorNode<T>::fail(Error &&error) {
|
||||
storage.push(std::move(error));
|
||||
armNext();
|
||||
arm_next();
|
||||
}
|
||||
|
||||
template <typename T> size_t AdaptConveyorNode<T>::queued() const {
|
||||
|
@ -524,7 +637,7 @@ template <typename T> size_t AdaptConveyorNode<T>::space() const {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void AdaptConveyorNode<T>::getResult(ErrorOrValue &err_or_val) {
|
||||
void AdaptConveyorNode<T>::get_result(ErrorOrValue &err_or_val) {
|
||||
if (!storage.empty()) {
|
||||
err_or_val.as<T>() = std::move(storage.front());
|
||||
storage.pop();
|
||||
|
@ -535,12 +648,12 @@ void AdaptConveyorNode<T>::getResult(ErrorOrValue &err_or_val) {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T> void AdaptConveyorNode<T>::childHasFired() {
|
||||
template <typename T> void AdaptConveyorNode<T>::child_has_fired() {
|
||||
// Adapt node has no children
|
||||
assert(false);
|
||||
}
|
||||
|
||||
template <typename T> void AdaptConveyorNode<T>::parentHasFired() {
|
||||
template <typename T> void AdaptConveyorNode<T>::parent_has_fired() {
|
||||
SAW_ASSERT(parent) { return; }
|
||||
|
||||
if (parent->space() == 0) {
|
||||
|
@ -550,15 +663,15 @@ template <typename T> void AdaptConveyorNode<T>::parentHasFired() {
|
|||
|
||||
template <typename T> void AdaptConveyorNode<T>::fire() {
|
||||
if (parent) {
|
||||
parent->childHasFired();
|
||||
parent->child_has_fired();
|
||||
|
||||
if (storage.size() > 0) {
|
||||
armLater();
|
||||
arm_later();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> OneTimeConveyorFeeder<T>::~OneTimeConveyorFeeder() {
|
||||
template <typename T> one_time_conveyor_feeder<T>::~one_time_conveyor_feeder() {
|
||||
if (feedee) {
|
||||
feedee->setFeeder(nullptr);
|
||||
feedee = nullptr;
|
||||
|
@ -566,30 +679,30 @@ template <typename T> OneTimeConveyorFeeder<T>::~OneTimeConveyorFeeder() {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void OneTimeConveyorFeeder<T>::setFeedee(OneTimeConveyorNode<T> *feedee_p) {
|
||||
void one_time_conveyor_feeder<T>::set_feedee(OneTimeConveyorNode<T> *feedee_p) {
|
||||
feedee = feedee_p;
|
||||
}
|
||||
|
||||
template <typename T> void OneTimeConveyorFeeder<T>::feed(T &&value) {
|
||||
template <typename T> void one_time_conveyor_feeder<T>::feed(T &&value) {
|
||||
if (feedee) {
|
||||
feedee->feed(std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> void OneTimeConveyorFeeder<T>::fail(Error &&error) {
|
||||
template <typename T> void one_time_conveyor_feeder<T>::fail(Error &&error) {
|
||||
if (feedee) {
|
||||
feedee->fail(std::move(error));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> size_t OneTimeConveyorFeeder<T>::queued() const {
|
||||
template <typename T> size_t one_time_conveyor_feeder<T>::queued() const {
|
||||
if (feedee) {
|
||||
return feedee->queued();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T> size_t OneTimeConveyorFeeder<T>::space() const {
|
||||
template <typename T> size_t one_time_conveyor_feeder<T>::space() const {
|
||||
if (feedee) {
|
||||
return feedee->space();
|
||||
}
|
||||
|
@ -604,18 +717,18 @@ template <typename T> OneTimeConveyorNode<T>::~OneTimeConveyorNode() {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void OneTimeConveyorNode<T>::setFeeder(OneTimeConveyorFeeder<T> *feeder_p) {
|
||||
void OneTimeConveyorNode<T>::set_feeder(one_time_conveyor_feeder<T> *feeder_p) {
|
||||
feeder = feeder_p;
|
||||
}
|
||||
|
||||
template <typename T> void OneTimeConveyorNode<T>::feed(T &&value) {
|
||||
storage = std::move(value);
|
||||
armNext();
|
||||
arm_next();
|
||||
}
|
||||
|
||||
template <typename T> void OneTimeConveyorNode<T>::fail(Error &&error) {
|
||||
storage = std::move(error);
|
||||
armNext();
|
||||
arm_next();
|
||||
}
|
||||
|
||||
template <typename T> size_t OneTimeConveyorNode<T>::queued() const {
|
||||
|
@ -627,7 +740,7 @@ template <typename T> size_t OneTimeConveyorNode<T>::space() const {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void OneTimeConveyorNode<T>::getResult(ErrorOrValue &err_or_val) {
|
||||
void OneTimeConveyorNode<T>::get_result(ErrorOrValue &err_or_val) {
|
||||
if (storage.has_value()) {
|
||||
err_or_val.as<T>() = std::move(storage.value());
|
||||
storage = std::nullopt;
|
||||
|
@ -640,7 +753,7 @@ void OneTimeConveyorNode<T>::getResult(ErrorOrValue &err_or_val) {
|
|||
|
||||
template <typename T> void OneTimeConveyorNode<T>::fire() {
|
||||
if (parent) {
|
||||
parent->childHasFired();
|
||||
parent->child_has_fired();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,223 +7,222 @@
|
|||
#include <sstream>
|
||||
|
||||
namespace saw {
|
||||
Error Buffer::push(const uint8_t &value) {
|
||||
size_t write_remain = writeCompositeLength();
|
||||
error buffer::push(const uint8_t &value) {
|
||||
size_t write_remain = write_composite_length();
|
||||
if (write_remain > 0) {
|
||||
write() = value;
|
||||
writeAdvance(1);
|
||||
write_advance(1);
|
||||
} else {
|
||||
return recoverableError("Buffer too small");
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
Error Buffer::push(const uint8_t &buffer, size_t size) {
|
||||
Error error = writeRequireLength(size);
|
||||
error buffer::push(const uint8_t &buffer, size_t size) {
|
||||
error error = write_require_length(size);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
const uint8_t *buffer_ptr = &buffer;
|
||||
while (size > 0) {
|
||||
size_t segment = std::min(writeSegmentLength(), size);
|
||||
size_t segment = std::min(write_segment_length(), size);
|
||||
memcpy(&write(), buffer_ptr, segment);
|
||||
writeAdvance(segment);
|
||||
write_advance(segment);
|
||||
size -= segment;
|
||||
buffer_ptr += segment;
|
||||
}
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
Error Buffer::pop(uint8_t &value) {
|
||||
if (readCompositeLength() > 0) {
|
||||
error buffer::pop(uint8_t &value) {
|
||||
if (read_composite_length() > 0) {
|
||||
value = read();
|
||||
readAdvance(1);
|
||||
read_advance(1);
|
||||
} else {
|
||||
return recoverableError("Buffer too small");
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
Error Buffer::pop(uint8_t &buffer, size_t size) {
|
||||
if (readCompositeLength() >= size) {
|
||||
error buffer::pop(uint8_t &buffer, size_t size) {
|
||||
if (read_composite_length() >= size) {
|
||||
uint8_t *buffer_ptr = &buffer;
|
||||
while (size > 0) {
|
||||
size_t segment = std::min(readSegmentLength(), size);
|
||||
size_t segment = std::min(read_segment_length(), size);
|
||||
memcpy(buffer_ptr, &read(), segment);
|
||||
readAdvance(segment);
|
||||
read_advance(segment);
|
||||
size -= segment;
|
||||
buffer_ptr += segment;
|
||||
}
|
||||
} else {
|
||||
return recoverableError("Buffer too small");
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
std::string Buffer::toString() const {
|
||||
std::string buffer::to_string() const {
|
||||
std::ostringstream oss;
|
||||
for (size_t i = 0; i < readCompositeLength(); ++i) {
|
||||
for (size_t i = 0; i < read_composite_length(); ++i) {
|
||||
oss << read(i);
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
std::string Buffer::toHex() const {
|
||||
std::string buffer::to_hex() const {
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::setfill('0');
|
||||
for (size_t i = 0; i < readCompositeLength(); ++i) {
|
||||
for (size_t i = 0; i < read_composite_length(); ++i) {
|
||||
oss << std::setw(2) << (uint16_t)read(i);
|
||||
if ((i + 1) < readCompositeLength()) {
|
||||
if ((i + 1) < read_composite_length()) {
|
||||
oss << ((i % 4 == 3) ? '\n' : ' ');
|
||||
}
|
||||
}
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
BufferView::BufferView(Buffer &buffer)
|
||||
buffer_view::buffer_view(::saw::buffer &buffer)
|
||||
: buffer{buffer}, read_offset{0}, write_offset{0} {}
|
||||
|
||||
size_t BufferView::readPosition() const {
|
||||
return read_offset + buffer.readPosition();
|
||||
size_t buffer_view::read_position() const {
|
||||
return read_offset + buffer.read_position();
|
||||
}
|
||||
|
||||
size_t BufferView::readCompositeLength() const {
|
||||
assert(read_offset <= buffer.readCompositeLength());
|
||||
if (read_offset > buffer.readCompositeLength()) {
|
||||
size_t buffer_view::read_composite_length() const {
|
||||
assert(read_offset <= buffer.read_composite_length());
|
||||
if (read_offset > buffer.read_composite_length()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buffer.readCompositeLength() - read_offset;
|
||||
return buffer.read_composite_length() - read_offset;
|
||||
}
|
||||
|
||||
size_t BufferView::readSegmentLength(size_t offset) const {
|
||||
size_t off = offset + read_offset;
|
||||
assert(off <= buffer.readCompositeLength());
|
||||
if (off > buffer.readCompositeLength()) {
|
||||
size_t buffer_view::read_segment_length(size_t offset) const {
|
||||
size_t off = offset + read_offset();
|
||||
assert(off <= buffer.read_composite_length());
|
||||
if (off > buffer.read_composite_length()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buffer.readSegmentLength(off);
|
||||
return buffer.read_segment_length(off);
|
||||
}
|
||||
|
||||
void BufferView::readAdvance(size_t bytes) {
|
||||
size_t offset = bytes + read_offset;
|
||||
assert(offset <= buffer.readCompositeLength());
|
||||
if (offset > buffer.readCompositeLength()) {
|
||||
read_offset += buffer.readCompositeLength();
|
||||
void buffer_view::read_advance(size_t bytes) {
|
||||
size_t offset = bytes + read_offset();
|
||||
assert(offset <= buffer.read_composite_length());
|
||||
if (offset > buffer.read_composite_length()) {
|
||||
read_offset += buffer.read_composite_length();
|
||||
return;
|
||||
}
|
||||
|
||||
read_offset += bytes;
|
||||
read_offset() += bytes;
|
||||
}
|
||||
|
||||
uint8_t &BufferView::read(size_t i) {
|
||||
size_t pos = i + read_offset;
|
||||
uint8_t &buffer_view::read(size_t i) {
|
||||
size_t pos = i + read_offset();
|
||||
|
||||
assert(pos < buffer.readCompositeLength());
|
||||
assert(pos < buffer.read_composite_length());
|
||||
|
||||
return buffer.read(pos);
|
||||
}
|
||||
|
||||
const uint8_t &BufferView::read(size_t i) const {
|
||||
size_t pos = i + read_offset;
|
||||
const uint8_t &buffer_view::read(size_t i) const {
|
||||
size_t pos = i + read_offset();
|
||||
|
||||
assert(pos < buffer.readCompositeLength());
|
||||
assert(pos < buffer.read_composite_length());
|
||||
|
||||
return buffer.read(pos);
|
||||
}
|
||||
|
||||
size_t BufferView::writePosition() const {
|
||||
return write_offset + buffer.writePosition();
|
||||
size_t buffer_view::write_position() const {
|
||||
return write_offset + buffer.write_position();
|
||||
}
|
||||
|
||||
size_t BufferView::writeCompositeLength() const {
|
||||
assert(write_offset <= buffer.writeCompositeLength());
|
||||
if (write_offset > buffer.writeCompositeLength()) {
|
||||
size_t buffer_view::write_composite_length() const {
|
||||
assert(write_offset <= buffer.write_composite_length());
|
||||
if (write_offset > buffer.write_composite_length()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buffer.writeCompositeLength() - write_offset;
|
||||
return buffer.write_composite_length() - write_offset;
|
||||
}
|
||||
|
||||
size_t BufferView::writeSegmentLength(size_t offset) const {
|
||||
size_t buffer_view::write_segment_length(size_t offset) const {
|
||||
size_t off = offset + write_offset;
|
||||
assert(off <= buffer.writeCompositeLength());
|
||||
if (off > buffer.writeCompositeLength()) {
|
||||
assert(off <= buffer.write_composite_length());
|
||||
if (off > buffer.write_composite_length()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return buffer.writeSegmentLength(off);
|
||||
return buffer.write_segment_length(off);
|
||||
}
|
||||
|
||||
void BufferView::writeAdvance(size_t bytes) {
|
||||
void buffer_view::write_advance(size_t bytes) {
|
||||
size_t offset = bytes + write_offset;
|
||||
assert(offset <= buffer.writeCompositeLength());
|
||||
if (offset > buffer.writeCompositeLength()) {
|
||||
write_offset += buffer.writeCompositeLength();
|
||||
assert(offset <= buffer.write_composite_length());
|
||||
if (offset > buffer.write_composite_length()) {
|
||||
write_offset += buffer.write_composite_length();
|
||||
return;
|
||||
}
|
||||
|
||||
write_offset += bytes;
|
||||
}
|
||||
|
||||
uint8_t &BufferView::write(size_t i) {
|
||||
uint8_t &buffer_view::write(size_t i) {
|
||||
size_t pos = i + write_offset;
|
||||
|
||||
assert(pos < buffer.writeCompositeLength());
|
||||
assert(pos < buffer.write_composite_length());
|
||||
|
||||
return buffer.write(pos);
|
||||
}
|
||||
|
||||
const uint8_t &BufferView::write(size_t i) const {
|
||||
const uint8_t &buffer_view::write(size_t i) const {
|
||||
size_t pos = i + write_offset;
|
||||
|
||||
assert(pos < buffer.writeCompositeLength());
|
||||
assert(pos < buffer.write_composite_length());
|
||||
|
||||
return buffer.write(pos);
|
||||
}
|
||||
|
||||
Error BufferView::writeRequireLength(size_t bytes) {
|
||||
return buffer.writeRequireLength(bytes + write_offset);
|
||||
error buffer_view::write_require_length(size_t bytes) {
|
||||
return buffer.write_require_length(bytes + write_offset);
|
||||
}
|
||||
|
||||
size_t BufferView::readOffset() const { return read_offset; }
|
||||
size_t buffer_view::read_offset() const { return read_offset; }
|
||||
|
||||
size_t BufferView::writeOffset() const { return write_offset; }
|
||||
size_t buffer_view::write_offset() const { return write_offset; }
|
||||
|
||||
RingBuffer::RingBuffer() : read_position{0}, write_position{0} {
|
||||
buffer.resize(RING_BUFFER_MAX_SIZE);
|
||||
}
|
||||
ring_buffer::ring_buffer() : ring_buffer(RING_BUFFER_MAX_SIZE) {}
|
||||
|
||||
RingBuffer::RingBuffer(size_t size) : read_position{0}, write_position{0} {
|
||||
ring_buffer::ring_buffer(size_t size)
|
||||
: m_read_position{0}, m_write_position{0} {
|
||||
buffer.resize(size);
|
||||
}
|
||||
|
||||
size_t RingBuffer::readPosition() const { return read_position; }
|
||||
size_t ring_buffer::read_position() const { return m_read_position; }
|
||||
|
||||
/*
|
||||
* If write is ahead of read it is a simple distance, but if read ist ahead of
|
||||
* write then there are two segments
|
||||
*
|
||||
*/
|
||||
size_t RingBuffer::readCompositeLength() const {
|
||||
return writePosition() < readPosition()
|
||||
? buffer.size() - (readPosition() - writePosition())
|
||||
size_t ring_buffer::read_composite_length() const {
|
||||
return write_position() < read_position()
|
||||
? buffer.size() - (read_position() - write_position())
|
||||
: (write_reached_read ? buffer.size()
|
||||
: writePosition() - readPosition());
|
||||
: write_position() - read_position());
|
||||
}
|
||||
|
||||
/*
|
||||
* If write is ahead then it's the simple distance again. If read is ahead it's
|
||||
* until the end of the buffer/segment
|
||||
*/
|
||||
size_t RingBuffer::readSegmentLength(size_t offset) const {
|
||||
size_t read_composite = readCompositeLength();
|
||||
size_t ring_buffer::read_segment_length(size_t offset) const {
|
||||
size_t read_composite = read_composite_length();
|
||||
assert(offset <= read_composite);
|
||||
offset = std::min(offset, read_composite);
|
||||
size_t remaining = read_composite - offset;
|
||||
|
||||
size_t read_offset = readPosition() + offset;
|
||||
size_t read_offset = read_position() + offset;
|
||||
read_offset = read_offset >= buffer.size() ? read_offset - buffer.size()
|
||||
: read_offset;
|
||||
|
||||
|
@ -233,11 +232,11 @@ size_t RingBuffer::readSegmentLength(size_t offset) const {
|
|||
// then it is set to zero by readCompositeLength()
|
||||
// case 3 write is located after read
|
||||
// since std::min you can use simple subtraction
|
||||
if (writePosition() < read_offset) {
|
||||
if (write_position() < read_offset) {
|
||||
return buffer.size() - read_offset;
|
||||
}
|
||||
|
||||
if (writePosition() == read_offset) {
|
||||
if (write_position() == read_offset) {
|
||||
if (remaining > 0) {
|
||||
return buffer.size() - read_offset;
|
||||
} else {
|
||||
|
@ -245,55 +244,55 @@ size_t RingBuffer::readSegmentLength(size_t offset) const {
|
|||
}
|
||||
}
|
||||
|
||||
return writePosition() - read_offset;
|
||||
return write_position() - read_offset;
|
||||
}
|
||||
|
||||
void RingBuffer::readAdvance(size_t bytes) {
|
||||
size_t read_composite = readCompositeLength();
|
||||
void ring_buffer::read_advance(size_t bytes) {
|
||||
size_t read_composite = read_composite_length();
|
||||
|
||||
assert(bytes <= read_composite);
|
||||
bytes = std::min(bytes, read_composite);
|
||||
size_t advanced = read_position + bytes;
|
||||
read_position = advanced >= buffer.size() ? advanced - buffer.size()
|
||||
: advanced;
|
||||
size_t advanced = read_position() + bytes;
|
||||
m_read_position = advanced >= buffer.size() ? advanced - buffer.size()
|
||||
: advanced;
|
||||
write_reached_read = bytes > 0 ? false : write_reached_read;
|
||||
}
|
||||
|
||||
uint8_t &RingBuffer::read(size_t i) {
|
||||
assert(i < readCompositeLength());
|
||||
size_t pos = read_position + i;
|
||||
uint8_t &ring_buffer::read(size_t i) {
|
||||
assert(i < read_composite_length());
|
||||
size_t pos = read_position() + i;
|
||||
pos = pos >= buffer.size() ? pos - buffer.size() : pos;
|
||||
return buffer[pos];
|
||||
}
|
||||
|
||||
const uint8_t &RingBuffer::read(size_t i) const {
|
||||
assert(i < readCompositeLength());
|
||||
size_t pos = read_position + i;
|
||||
const uint8_t &ring_buffer::read(size_t i) const {
|
||||
assert(i < read_composite_length());
|
||||
size_t pos = read_position() + i;
|
||||
pos = pos >= buffer.size() ? pos - buffer.size() : pos;
|
||||
return buffer[pos];
|
||||
}
|
||||
|
||||
size_t RingBuffer::writePosition() const { return write_position; }
|
||||
size_t ring_buffer::write_position() const { return m_write_position; }
|
||||
|
||||
size_t RingBuffer::writeCompositeLength() const {
|
||||
return readPosition() > writePosition()
|
||||
? (readPosition() - writePosition())
|
||||
size_t ring_buffer::write_composite_length() const {
|
||||
return read_position() > write_position()
|
||||
? (read_position() - write_position())
|
||||
: (write_reached_read
|
||||
? 0
|
||||
: buffer.size() - (writePosition() - readPosition()));
|
||||
: buffer.size() - (write_position() - read_position()));
|
||||
}
|
||||
|
||||
size_t RingBuffer::writeSegmentLength(size_t offset) const {
|
||||
size_t write_composite = writeCompositeLength();
|
||||
size_t ring_buffer::write_segment_length(size_t offset) const {
|
||||
size_t write_composite = write_composite_length();
|
||||
assert(offset <= write_composite);
|
||||
offset = std::min(offset, write_composite);
|
||||
|
||||
size_t write_offset = writePosition() + offset;
|
||||
size_t write_offset = write_position() + offset;
|
||||
write_offset = write_offset >= buffer.size() ? write_offset - buffer.size()
|
||||
: write_offset;
|
||||
|
||||
if (read_position > write_offset) {
|
||||
return read_position - write_offset;
|
||||
if (read_position() > write_offset) {
|
||||
return read_position() - write_offset;
|
||||
}
|
||||
|
||||
if (write_reached_read) {
|
||||
|
@ -303,26 +302,26 @@ size_t RingBuffer::writeSegmentLength(size_t offset) const {
|
|||
return buffer.size() - write_offset;
|
||||
}
|
||||
|
||||
void RingBuffer::writeAdvance(size_t bytes) {
|
||||
assert(bytes <= writeCompositeLength());
|
||||
size_t advanced = write_position + bytes;
|
||||
write_position = advanced >= buffer.size() ? advanced - buffer.size()
|
||||
: advanced;
|
||||
void ring_buffer::write_advance(size_t bytes) {
|
||||
assert(bytes <= write_composite_length());
|
||||
size_t advanced = write_position() + bytes;
|
||||
m_write_position = advanced >= buffer.size() ? advanced - buffer.size()
|
||||
: advanced;
|
||||
|
||||
write_reached_read =
|
||||
(write_position == read_position && bytes > 0 ? true : false);
|
||||
(write_position() == read_position() && bytes > 0 ? true : false);
|
||||
}
|
||||
|
||||
uint8_t &RingBuffer::write(size_t i) {
|
||||
assert(i < writeCompositeLength());
|
||||
size_t pos = write_position + i;
|
||||
uint8_t &ring_buffer::write(size_t i) {
|
||||
assert(i < write_composite_length());
|
||||
size_t pos = write_position() + i;
|
||||
pos = pos >= buffer.size() ? pos - buffer.size() : pos;
|
||||
return buffer[pos];
|
||||
}
|
||||
|
||||
const uint8_t &RingBuffer::write(size_t i) const {
|
||||
assert(i < writeCompositeLength());
|
||||
size_t pos = write_position + i;
|
||||
const uint8_t &ring_buffer::write(size_t i) const {
|
||||
assert(i < write_composite_length());
|
||||
size_t pos = write_position() + i;
|
||||
pos = pos >= buffer.size() ? pos - buffer.size() : pos;
|
||||
return buffer[pos];
|
||||
}
|
||||
|
@ -344,89 +343,90 @@ const uint8_t &RingBuffer::write(size_t i) const {
|
|||
return noError();
|
||||
}
|
||||
*/
|
||||
Error RingBuffer::writeRequireLength(size_t bytes) {
|
||||
size_t write_remain = writeCompositeLength();
|
||||
error ring_buffer::write_require_length(size_t bytes) {
|
||||
size_t write_remain = write_composite_length();
|
||||
if (bytes > write_remain) {
|
||||
return recoverableError("Buffer too small");
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
ArrayBuffer::ArrayBuffer(size_t size) : read_position{0}, write_position{0} {
|
||||
array_buffer::array_buffer(size_t size)
|
||||
: m_read_position{0}, m_write_position{0} {
|
||||
buffer.resize(size);
|
||||
}
|
||||
|
||||
size_t ArrayBuffer::readPosition() const { return read_position; }
|
||||
size_t array_buffer::read_position() const { return read_position(); }
|
||||
|
||||
size_t ArrayBuffer::readCompositeLength() const {
|
||||
return write_position - read_position;
|
||||
size_t array_buffer::read_composite_length() const {
|
||||
return write_position() - read_position();
|
||||
}
|
||||
|
||||
size_t ArrayBuffer::readSegmentLength(size_t offset) const {
|
||||
size_t read_composite = readCompositeLength();
|
||||
size_t array_buffer::read_segment_length(size_t offset) const {
|
||||
size_t read_composite = read_composite_length();
|
||||
assert(offset <= read_composite);
|
||||
|
||||
offset = std::min(read_composite, offset);
|
||||
size_t read_offset = read_position + offset;
|
||||
size_t read_offset = read_position() + offset;
|
||||
|
||||
return write_position - read_offset;
|
||||
return write_position() - read_offset;
|
||||
}
|
||||
|
||||
void ArrayBuffer::readAdvance(size_t bytes) {
|
||||
assert(bytes <= readCompositeLength());
|
||||
read_position += bytes;
|
||||
void array_buffer::read_advance(size_t bytes) {
|
||||
assert(bytes <= read_composite_length());
|
||||
m_read_position += bytes;
|
||||
}
|
||||
|
||||
uint8_t &ArrayBuffer::read(size_t i) {
|
||||
assert(i < readCompositeLength());
|
||||
uint8_t &array_buffer::read(size_t i) {
|
||||
assert(i < read_composite_length());
|
||||
|
||||
return buffer[i + read_position];
|
||||
return buffer[i + read_position()];
|
||||
}
|
||||
|
||||
const uint8_t &ArrayBuffer::read(size_t i) const {
|
||||
assert(i + read_position < buffer.size());
|
||||
const uint8_t &array_buffer::read(size_t i) const {
|
||||
assert(i + read_position() < buffer.size());
|
||||
|
||||
return buffer[i + read_position];
|
||||
return buffer[i + read_position()];
|
||||
}
|
||||
|
||||
size_t ArrayBuffer::writePosition() const { return write_position; }
|
||||
size_t array_buffer::write_position() const { return m_write_position; }
|
||||
|
||||
size_t ArrayBuffer::writeCompositeLength() const {
|
||||
assert(write_position <= buffer.size());
|
||||
return buffer.size() - write_position;
|
||||
size_t array_buffer::write_composite_length() const {
|
||||
assert(write_position() <= buffer.size());
|
||||
return buffer.size() - write_position();
|
||||
}
|
||||
|
||||
size_t ArrayBuffer::writeSegmentLength(size_t offset) const {
|
||||
assert(write_position <= buffer.size());
|
||||
size_t write_composite = writeCompositeLength();
|
||||
size_t array_buffer::write_segment_length(size_t offset) const {
|
||||
assert(write_position() <= buffer.size());
|
||||
size_t write_composite = write_composite_length();
|
||||
|
||||
assert(offset <= write_composite);
|
||||
offset = std::min(write_composite, offset);
|
||||
size_t write_offset = write_position + offset;
|
||||
size_t write_offset = write_position() + offset;
|
||||
|
||||
return buffer.size() - write_offset;
|
||||
}
|
||||
|
||||
void ArrayBuffer::writeAdvance(size_t bytes) {
|
||||
assert(bytes <= writeCompositeLength());
|
||||
write_position += bytes;
|
||||
void array_buffer::write_advance(size_t bytes) {
|
||||
assert(bytes <= write_composite_length());
|
||||
m_write_position += bytes;
|
||||
}
|
||||
|
||||
uint8_t &ArrayBuffer::write(size_t i) {
|
||||
assert(i < writeCompositeLength());
|
||||
return buffer[i + write_position];
|
||||
uint8_t &array_buffer::write(size_t i) {
|
||||
assert(i < write_composite_length());
|
||||
return buffer[i + write_position()];
|
||||
}
|
||||
|
||||
const uint8_t &ArrayBuffer::write(size_t i) const {
|
||||
assert(i < writeCompositeLength());
|
||||
return buffer[i + write_position];
|
||||
const uint8_t &array_buffer::write(size_t i) const {
|
||||
assert(i < write_composite_length());
|
||||
return buffer[i + write_position()];
|
||||
}
|
||||
Error ArrayBuffer::writeRequireLength(size_t bytes) {
|
||||
size_t write_remain = writeCompositeLength();
|
||||
error array_buffer::write_require_length(size_t bytes) {
|
||||
size_t write_remain = write_composite_length();
|
||||
if (bytes > write_remain) {
|
||||
return recoverableError("Buffer too small");
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
} // namespace saw
|
||||
|
|
|
@ -13,23 +13,23 @@ namespace saw {
|
|||
/*
|
||||
* Access class to reduce templated BufferSegments bloat
|
||||
*/
|
||||
class Buffer {
|
||||
class buffer {
|
||||
protected:
|
||||
~Buffer() = default;
|
||||
~buffer() = default;
|
||||
|
||||
public:
|
||||
virtual size_t readPosition() const = 0;
|
||||
virtual size_t readCompositeLength() const = 0;
|
||||
virtual size_t readSegmentLength(size_t offset = 0) const = 0;
|
||||
virtual void readAdvance(size_t bytes) = 0;
|
||||
virtual size_t read_position() const = 0;
|
||||
virtual size_t read_composite_length() const = 0;
|
||||
virtual size_t read_segment_length(size_t offset = 0) const = 0;
|
||||
virtual void read_advance(size_t bytes) = 0;
|
||||
|
||||
virtual uint8_t &read(size_t i = 0) = 0;
|
||||
virtual const uint8_t &read(size_t i = 0) const = 0;
|
||||
|
||||
virtual size_t writePosition() const = 0;
|
||||
virtual size_t writeCompositeLength() const = 0;
|
||||
virtual size_t writeSegmentLength(size_t offset = 0) const = 0;
|
||||
virtual void writeAdvance(size_t bytes) = 0;
|
||||
virtual size_t write_position() const = 0;
|
||||
virtual size_t write_composite_length() const = 0;
|
||||
virtual size_t write_segment_length(size_t offset = 0) const = 0;
|
||||
virtual void write_advance(size_t bytes) = 0;
|
||||
|
||||
virtual uint8_t &write(size_t i = 0) = 0;
|
||||
virtual const uint8_t &write(size_t i = 0) const = 0;
|
||||
|
@ -40,153 +40,153 @@ public:
|
|||
* There is nothing you can do if read hasn't been filled, but at
|
||||
* least write can be increased if it is demanded.
|
||||
*/
|
||||
virtual Error writeRequireLength(size_t bytes) = 0;
|
||||
virtual error write_require_length(size_t bytes) = 0;
|
||||
|
||||
Error push(const uint8_t &value);
|
||||
Error push(const uint8_t &buffer, size_t size);
|
||||
Error pop(uint8_t &value);
|
||||
Error pop(uint8_t &buffer, size_t size);
|
||||
error push(const uint8_t &value);
|
||||
error push(const uint8_t &buffer, size_t size);
|
||||
error pop(uint8_t &value);
|
||||
error pop(uint8_t &buffer, size_t size);
|
||||
|
||||
std::string toString() const;
|
||||
std::string toHex() const;
|
||||
std::string to_string() const;
|
||||
std::string to_hex() const;
|
||||
};
|
||||
|
||||
/*
|
||||
* A viewer class for buffers.
|
||||
* Working on the reference buffer invalidates the buffer view
|
||||
*/
|
||||
class BufferView : public Buffer {
|
||||
class buffer_view : public buffer {
|
||||
private:
|
||||
Buffer &buffer;
|
||||
size_t read_offset;
|
||||
size_t write_offset;
|
||||
buffer &m_buffer;
|
||||
size_t m_read_offset;
|
||||
size_t m_write_offset;
|
||||
|
||||
public:
|
||||
BufferView(Buffer &);
|
||||
buffer_view(class buffer &);
|
||||
|
||||
size_t readPosition() const override;
|
||||
size_t readCompositeLength() const override;
|
||||
size_t readSegmentLength(size_t offset = 0) const override;
|
||||
void readAdvance(size_t bytes) override;
|
||||
size_t read_position() const override;
|
||||
size_t read_composite_length() const override;
|
||||
size_t read_segment_length(size_t offset = 0) const override;
|
||||
void read_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &read(size_t i = 0) override;
|
||||
const uint8_t &read(size_t i = 0) const override;
|
||||
|
||||
size_t writePosition() const override;
|
||||
size_t writeCompositeLength() const override;
|
||||
size_t writeSegmentLength(size_t offset = 0) const override;
|
||||
void writeAdvance(size_t bytes) override;
|
||||
size_t write_position() const override;
|
||||
size_t write_composite_length() const override;
|
||||
size_t write_segment_length(size_t offset = 0) const override;
|
||||
void write_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &write(size_t i = 0) override;
|
||||
const uint8_t &write(size_t i = 0) const override;
|
||||
|
||||
Error writeRequireLength(size_t bytes) override;
|
||||
error write_require_length(size_t bytes) override;
|
||||
|
||||
size_t readOffset() const;
|
||||
size_t writeOffset() const;
|
||||
size_t read_offset() const;
|
||||
size_t write_offset() const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Buffer size meant for default allocation size of the ringbuffer since
|
||||
* this class currently doesn't support proper resizing
|
||||
*/
|
||||
constexpr size_t RING_BUFFER_MAX_SIZE = 4096;
|
||||
constexpr size_t ring_buffer_max_size = 4096;
|
||||
/*
|
||||
* Buffer wrapping around if read caught up
|
||||
*/
|
||||
class RingBuffer final : public Buffer {
|
||||
class ring_buffer final : public buffer {
|
||||
private:
|
||||
std::vector<uint8_t> buffer;
|
||||
size_t read_position;
|
||||
size_t write_position;
|
||||
bool write_reached_read = false;
|
||||
std::vector<uint8_t> m_buffer;
|
||||
size_t m_read_position;
|
||||
size_t m_write_position;
|
||||
bool m_write_reached_read = false;
|
||||
|
||||
public:
|
||||
RingBuffer();
|
||||
RingBuffer(size_t size);
|
||||
ring_buffer();
|
||||
ring_buffer(size_t size);
|
||||
|
||||
inline size_t size() const { return buffer.size(); }
|
||||
inline size_t size() const { return m_buffer.size(); }
|
||||
|
||||
inline uint8_t &operator[](size_t i) { return buffer[i]; }
|
||||
inline const uint8_t &operator[](size_t i) const { return buffer[i]; }
|
||||
inline uint8_t &operator[](size_t i) { return m_buffer[i]; }
|
||||
inline const uint8_t &operator[](size_t i) const { return m_buffer[i]; }
|
||||
|
||||
size_t readPosition() const override;
|
||||
size_t readCompositeLength() const override;
|
||||
size_t readSegmentLength(size_t offset = 0) const override;
|
||||
void readAdvance(size_t bytes) override;
|
||||
size_t read_position() const override;
|
||||
size_t read_composite_length() const override;
|
||||
size_t read_segment_length(size_t offset = 0) const override;
|
||||
void read_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &read(size_t i = 0) override;
|
||||
const uint8_t &read(size_t i = 0) const override;
|
||||
|
||||
size_t writePosition() const override;
|
||||
size_t writeCompositeLength() const override;
|
||||
size_t writeSegmentLength(size_t offset = 0) const override;
|
||||
void writeAdvance(size_t bytes) override;
|
||||
size_t write_position() const override;
|
||||
size_t write_composite_length() const override;
|
||||
size_t write_segment_length(size_t offset = 0) const override;
|
||||
void write_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &write(size_t i = 0) override;
|
||||
const uint8_t &write(size_t i = 0) const override;
|
||||
|
||||
Error writeRequireLength(size_t bytes) override;
|
||||
error write_require_length(size_t bytes) override;
|
||||
};
|
||||
|
||||
/*
|
||||
* One time buffer
|
||||
*/
|
||||
class ArrayBuffer : public Buffer {
|
||||
class array_buffer : public buffer {
|
||||
private:
|
||||
std::vector<uint8_t> buffer;
|
||||
std::vector<uint8_t> m_buffer;
|
||||
|
||||
size_t read_position;
|
||||
size_t write_position;
|
||||
size_t m_read_position;
|
||||
size_t m_write_position;
|
||||
|
||||
public:
|
||||
ArrayBuffer(size_t size);
|
||||
array_buffer(size_t size);
|
||||
|
||||
size_t readPosition() const override;
|
||||
size_t readCompositeLength() const override;
|
||||
size_t readSegmentLength(size_t offset = 0) const override;
|
||||
void readAdvance(size_t bytes) override;
|
||||
size_t read_position() const override;
|
||||
size_t read_composite_length() const override;
|
||||
size_t read_segment_length(size_t offset = 0) const override;
|
||||
void read_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &read(size_t i = 0) override;
|
||||
const uint8_t &read(size_t i = 0) const override;
|
||||
|
||||
size_t writePosition() const override;
|
||||
size_t writeCompositeLength() const override;
|
||||
size_t writeSegmentLength(size_t offset = 0) const override;
|
||||
void writeAdvance(size_t bytes) override;
|
||||
size_t write_position() const override;
|
||||
size_t write_composite_length() const override;
|
||||
size_t write_segment_length(size_t offset = 0) const override;
|
||||
void write_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &write(size_t i = 0) override;
|
||||
const uint8_t &write(size_t i = 0) const override;
|
||||
|
||||
Error writeRequireLength(size_t bytes) override;
|
||||
error write_require_length(size_t bytes) override;
|
||||
};
|
||||
|
||||
class ChainArrayBuffer : public Buffer {
|
||||
class chain_array_buffer : public buffer {
|
||||
private:
|
||||
std::deque<ArrayBuffer> buffer;
|
||||
std::deque<array_buffer> m_buffer;
|
||||
|
||||
size_t read_position;
|
||||
size_t write_position;
|
||||
size_t m_read_position;
|
||||
size_t m_write_position;
|
||||
|
||||
public:
|
||||
ChainArrayBuffer();
|
||||
chain_array_buffer();
|
||||
|
||||
size_t readPosition() const override;
|
||||
size_t readCompositeLength() const override;
|
||||
size_t readSegmentLength(size_t offset = 0) const override;
|
||||
void readAdvance(size_t bytes) override;
|
||||
size_t read_position() const override;
|
||||
size_t read_composite_length() const override;
|
||||
size_t read_segment_length(size_t offset = 0) const override;
|
||||
void read_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &read(size_t i = 0) override;
|
||||
const uint8_t &read(size_t i = 0) const override;
|
||||
|
||||
size_t writePosition() const override;
|
||||
size_t writeCompositeLength() const override;
|
||||
size_t writeSegmentLength(size_t offset = 0) const override;
|
||||
void writeAdvance(size_t bytes) override;
|
||||
size_t write_position() const override;
|
||||
size_t write_composite_length() const override;
|
||||
size_t write_segment_length(size_t offset = 0) const override;
|
||||
void write_advance(size_t bytes) override;
|
||||
|
||||
uint8_t &write(size_t i = 0) override;
|
||||
const uint8_t &write(size_t i = 0) const override;
|
||||
|
||||
Error writeRequireLength(size_t bytes) override;
|
||||
error write_require_length(size_t bytes) override;
|
||||
};
|
||||
} // namespace saw
|
||||
|
|
|
@ -27,9 +27,10 @@ namespace saw {
|
|||
classname(classname &&) = default; \
|
||||
classname &operator=(classname &&) = default
|
||||
|
||||
// In case of C++20
|
||||
#define SAW_ASSERT(expression) \
|
||||
assert(expression); \
|
||||
if (!(expression))
|
||||
if (!(expression)) [[unlikely]]
|
||||
|
||||
template <typename T> using Maybe = std::optional<T>;
|
||||
|
||||
|
@ -69,4 +70,6 @@ template <typename T> struct VoidUnfix { typedef T Type; };
|
|||
template <> struct VoidUnfix<Void> { typedef void Type; };
|
||||
template <typename T> using UnfixVoid = typename VoidUnfix<T>::Type;
|
||||
|
||||
template <typename... T> constexpr bool always_false = false;
|
||||
|
||||
} // namespace saw
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#include "error.h"
|
||||
|
||||
namespace saw {
|
||||
Error::Error() : error_{static_cast<Error::Code>(0)} {}
|
||||
error::error() : error_{static_cast<error::Code>(0)} {}
|
||||
|
||||
Error::Error(const std::string_view &msg, Error::Code code)
|
||||
: error_message{msg}, error_{static_cast<Error::Code>(code)} {}
|
||||
error::error(const std::string_view &msg, error::Code code)
|
||||
: m_error_message{msg}, error_{static_cast<error::Code>(code)} {}
|
||||
|
||||
Error::Error(std::string &&msg, Error::Code code)
|
||||
: error_message{std::move(msg)}, error_{static_cast<Error::Code>(code)} {}
|
||||
error::error(std::string &&msg, error::Code code)
|
||||
: m_error_message{std::move(msg)}, error_{static_cast<error::Code>(code)} {}
|
||||
|
||||
Error::Error(Error &&error)
|
||||
: error_message{std::move(error.error_message)}, error_{std::move(
|
||||
error.error_)} {}
|
||||
error::error(error &&error)
|
||||
: m_error_message{std::move(error.m_error_message)}, error_{std::move(
|
||||
error.error_)} {}
|
||||
|
||||
const std::string_view Error::message() const {
|
||||
const std::string_view error::message() const {
|
||||
|
||||
return std::visit(
|
||||
[this](auto &&arg) -> const std::string_view {
|
||||
|
@ -27,47 +27,51 @@ const std::string_view Error::message() const {
|
|||
return "Error in class Error. Good luck :)";
|
||||
}
|
||||
},
|
||||
error_message);
|
||||
m_error_message);
|
||||
}
|
||||
|
||||
bool Error::failed() const {
|
||||
return static_cast<std::underlying_type_t<Error::Code>>(error_) != 0;
|
||||
bool error::failed() const {
|
||||
return static_cast<std::underlying_type_t<error::Code>>(error_) != 0;
|
||||
}
|
||||
|
||||
bool Error::isCritical() const {
|
||||
return static_cast<std::underlying_type_t<Error::Code>>(error_) < 0;
|
||||
bool error::is_critical() const {
|
||||
return static_cast<std::underlying_type_t<error::Code>>(error_) < 0;
|
||||
}
|
||||
|
||||
bool Error::isRecoverable() const {
|
||||
return static_cast<std::underlying_type_t<Error::Code>>(error_) > 0;
|
||||
bool error::is_recoverable() const {
|
||||
return static_cast<std::underlying_type_t<error::Code>>(error_) > 0;
|
||||
}
|
||||
|
||||
Error Error::copyError() const {
|
||||
Error error;
|
||||
error error::copy_error() const {
|
||||
error error;
|
||||
error.error_ = error_;
|
||||
try {
|
||||
error.error_message = error_message;
|
||||
error.m_error_message = m_error_message;
|
||||
} catch (const std::bad_alloc &) {
|
||||
error.error_message =
|
||||
error.m_error_message =
|
||||
std::string_view{"Error while copying Error string. Out of memory"};
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
Error::Code Error::code() const { return static_cast<Error::Code>(error_); }
|
||||
error::Code error::code() const { return static_cast<error::Code>(error_); }
|
||||
|
||||
Error makeError(const std::string_view &generic, Error::Code code) {
|
||||
return Error{generic, code};
|
||||
error make_error(const std::string_view &generic, error::Code code) {
|
||||
return Error;
|
||||
{ generic, code; };
|
||||
}
|
||||
|
||||
Error criticalError(const std::string_view &generic, Error::Code c) {
|
||||
return makeError(generic, c);
|
||||
error critical_error(const std::string_view &generic, error::Code c) {
|
||||
return make_error(generic, c);
|
||||
}
|
||||
|
||||
Error recoverableError(const std::string_view &generic, Error::Code c) {
|
||||
return makeError(generic, c);
|
||||
error recoverable_error(const std::string_view &generic, error::Code c) {
|
||||
return make_error(generic, c);
|
||||
}
|
||||
|
||||
Error noError() { return Error{}; }
|
||||
error no_error() {
|
||||
return Error;
|
||||
{};
|
||||
}
|
||||
|
||||
} // namespace saw
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
namespace saw {
|
||||
|
@ -12,7 +14,7 @@ namespace saw {
|
|||
* critical and recoverable errors. Additional code ids can be provided to the
|
||||
* constructor if additional distinctions are necessary.
|
||||
*/
|
||||
class Error {
|
||||
class error {
|
||||
public:
|
||||
enum class Code : int16_t {
|
||||
GenericCritical = -1,
|
||||
|
@ -22,63 +24,64 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
std::variant<std::string_view, std::string> error_message;
|
||||
Code error_;
|
||||
std::variant<std::string_view, std::string> m_error_message;
|
||||
Code m_error;
|
||||
|
||||
public:
|
||||
Error();
|
||||
Error(const std::string_view &msg, Error::Code code);
|
||||
Error(std::string &&msg, Error::Code code);
|
||||
Error(Error &&error);
|
||||
error();
|
||||
error(const std::string_view &msg, error::Code code);
|
||||
error(std::string &&msg, error::Code code);
|
||||
error(error &&error);
|
||||
|
||||
SAW_FORBID_COPY(Error);
|
||||
SAW_FORBID_COPY(error);
|
||||
|
||||
Error &operator=(Error &&) = default;
|
||||
error &operator=(error &&) = default;
|
||||
|
||||
const std::string_view message() const;
|
||||
bool failed() const;
|
||||
|
||||
bool isCritical() const;
|
||||
bool isRecoverable() const;
|
||||
bool is_critical() const;
|
||||
bool is_recoverable() const;
|
||||
|
||||
Error copyError() const;
|
||||
error copy_error() const;
|
||||
|
||||
Code code() const;
|
||||
Code error_code() const;
|
||||
};
|
||||
|
||||
Error makeError(const std::string_view &generic, Error::Code c);
|
||||
error make_error(const std::string_view &generic, error::Code c);
|
||||
|
||||
template <typename Formatter>
|
||||
Error makeError(const Formatter &formatter, Error::Code code,
|
||||
const std::string_view &generic) {
|
||||
error make_error(const Formatter &formatter, error::Code code,
|
||||
const std::string_view &generic) {
|
||||
try {
|
||||
std::string error_msg = formatter();
|
||||
return Error{std::move(error_msg), code};
|
||||
return error{std::move(error_msg), code};
|
||||
} catch (std::bad_alloc &) {
|
||||
return Error{generic, code};
|
||||
return error{generic, code};
|
||||
}
|
||||
}
|
||||
|
||||
Error criticalError(const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericCritical);
|
||||
error critical_error(const std::string_view &generic,
|
||||
error::Code c = error::Code::GenericCritical);
|
||||
|
||||
template <typename Formatter>
|
||||
Error criticalError(const Formatter &formatter, const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericCritical) {
|
||||
error critical_error(const Formatter &formatter,
|
||||
const std::string_view &generic,
|
||||
error::Code c = error::Code::GenericCritical) {
|
||||
return makeError(formatter, c, generic);
|
||||
}
|
||||
|
||||
Error recoverableError(const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericRecoverable);
|
||||
error recoverable_error(const std::string_view &generic,
|
||||
error::Code c = error::Code::GenericRecoverable);
|
||||
|
||||
template <typename Formatter>
|
||||
Error recoverableError(const Formatter &formatter,
|
||||
const std::string_view &generic,
|
||||
Error::Code c = Error::Code::GenericRecoverable) {
|
||||
error recoverable_error(const Formatter &formatter,
|
||||
const std::string_view &generic,
|
||||
error::Code c = error::Code::GenericRecoverable) {
|
||||
return makeError(formatter, c, generic);
|
||||
}
|
||||
|
||||
Error noError();
|
||||
error no_error();
|
||||
|
||||
/**
|
||||
* Exception alternative. Since I code without exceptions this class is
|
||||
|
@ -86,9 +89,9 @@ Error noError();
|
|||
*/
|
||||
template <typename T> class ErrorOr;
|
||||
|
||||
class ErrorOrValue {
|
||||
class error_or_value {
|
||||
public:
|
||||
virtual ~ErrorOrValue() = default;
|
||||
virtual ~error_or_value() = default;
|
||||
|
||||
template <typename T> ErrorOr<UnfixVoid<T>> &as() {
|
||||
return static_cast<ErrorOr<UnfixVoid<T>> &>(*this);
|
||||
|
@ -99,37 +102,39 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename T> class ErrorOr final : public ErrorOrValue {
|
||||
template <typename T> class ErrorOr final : public error_or_value {
|
||||
private:
|
||||
std::variant<Error, FixVoid<T>> value_or_error;
|
||||
std::variant<error, FixVoid<T>> m_value_or_error_data;
|
||||
|
||||
static_assert(!std::is_same_v<T, Void>, "Don't use internal private types");
|
||||
|
||||
public:
|
||||
ErrorOr() = default;
|
||||
ErrorOr(const FixVoid<T> &value) : value_or_error{value} {}
|
||||
ErrorOr(const FixVoid<T> &value) : m_value_or_error_data{value} {}
|
||||
|
||||
ErrorOr(FixVoid<T> &&value) : value_or_error{std::move(value)} {}
|
||||
ErrorOr(FixVoid<T> &&value) : m_value_or_error_data{std::move(value)} {}
|
||||
|
||||
ErrorOr(const Error &error) : value_or_error{error} {}
|
||||
ErrorOr(Error &&error) : value_or_error{std::move(error)} {}
|
||||
ErrorOr(const error &error) : m_value_or_error_data{error} {}
|
||||
ErrorOr(error &&error) : m_value_or_error_data{std::move(error)} {}
|
||||
|
||||
bool isValue() const {
|
||||
return std::holds_alternative<FixVoid<T>>(value_or_error);
|
||||
bool is_value() const {
|
||||
return std::holds_alternative<FixVoid<T>>(m_value_or_error_data);
|
||||
}
|
||||
|
||||
bool isError() const {
|
||||
return std::holds_alternative<Error>(value_or_error);
|
||||
bool is_error() const {
|
||||
return std::holds_alternative<error>(m_value_or_error_data);
|
||||
}
|
||||
|
||||
Error &error() { return std::get<Error>(value_or_error); }
|
||||
class error &error() {
|
||||
return std::get<error>(m_value_or_error_data);
|
||||
}
|
||||
|
||||
const Error &error() const { return std::get<Error>(value_or_error); }
|
||||
const class error &error() const { return std::get<error>(m_value_or_error_data); }
|
||||
|
||||
FixVoid<T> &value() { return std::get<FixVoid<T>>(value_or_error); }
|
||||
FixVoid<T> &value() { return std::get<FixVoid<T>>(m_value_or_error_data); }
|
||||
|
||||
const FixVoid<T> &value() const {
|
||||
return std::get<FixVoid<T>>(value_or_error);
|
||||
return std::get<FixVoid<T>>(m_value_or_error_data);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@ public:
|
|||
|
||||
virtual ErrorOr<size_t> read(void *buffer, size_t length) = 0;
|
||||
|
||||
virtual Conveyor<void> readReady() = 0;
|
||||
virtual Conveyor<void> read_ready() = 0;
|
||||
|
||||
virtual Conveyor<void> onReadDisconnected() = 0;
|
||||
virtual Conveyor<void> on_read_disconnected() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -31,69 +31,70 @@ public:
|
|||
|
||||
virtual ErrorOr<size_t> write(const void *buffer, size_t length) = 0;
|
||||
|
||||
virtual Conveyor<void> writeReady() = 0;
|
||||
virtual Conveyor<void> write_ready() = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Io stream
|
||||
*/
|
||||
class IoStream : public InputStream, public OutputStream {
|
||||
class io_stream : public InputStream, public OutputStream {
|
||||
public:
|
||||
virtual ~IoStream() = default;
|
||||
virtual ~io_stream() = default;
|
||||
};
|
||||
|
||||
class AsyncInputStream {
|
||||
class async_input_stream {
|
||||
public:
|
||||
virtual ~AsyncInputStream() = default;
|
||||
virtual ~async_input_stream() = default;
|
||||
|
||||
virtual void read(void *buffer, size_t min_length, size_t max_length) = 0;
|
||||
|
||||
virtual Conveyor<size_t> readDone() = 0;
|
||||
virtual Conveyor<void> onReadDisconnected() = 0;
|
||||
virtual Conveyor<size_t> read_done() = 0;
|
||||
virtual Conveyor<void> on_read_disconnected() = 0;
|
||||
};
|
||||
|
||||
class AsyncOutputStream {
|
||||
class async_output_stream {
|
||||
public:
|
||||
virtual ~AsyncOutputStream() = default;
|
||||
virtual ~async_output_stream() = default;
|
||||
|
||||
virtual void write(const void *buffer, size_t length) = 0;
|
||||
|
||||
virtual Conveyor<size_t> writeDone() = 0;
|
||||
virtual Conveyor<size_t> write_done() = 0;
|
||||
};
|
||||
|
||||
class AsyncIoStream final : public AsyncInputStream, public AsyncOutputStream {
|
||||
class async_io_stream final : public async_input_stream,
|
||||
public async_output_stream {
|
||||
private:
|
||||
Own<IoStream> stream;
|
||||
Own<io_stream> m_stream;
|
||||
|
||||
SinkConveyor read_ready;
|
||||
SinkConveyor write_ready;
|
||||
SinkConveyor read_disconnected;
|
||||
ConveyorSink m_read_ready;
|
||||
ConveyorSink m_write_ready;
|
||||
ConveyorSink m_read_disconnected;
|
||||
|
||||
ReadTaskAndStepHelper read_stepper;
|
||||
WriteTaskAndStepHelper write_stepper;
|
||||
ReadTaskAndStepHelper m_read_stepper;
|
||||
WriteTaskAndStepHelper m_write_stepper;
|
||||
|
||||
public:
|
||||
AsyncIoStream(Own<IoStream> str);
|
||||
async_io_stream(Own<io_stream> str);
|
||||
|
||||
SAW_FORBID_COPY(AsyncIoStream);
|
||||
SAW_FORBID_MOVE(AsyncIoStream);
|
||||
SAW_FORBID_COPY(async_io_stream);
|
||||
SAW_FORBID_MOVE(async_io_stream);
|
||||
|
||||
void read(void *buffer, size_t length, size_t max_length) override;
|
||||
|
||||
Conveyor<size_t> readDone() override;
|
||||
Conveyor<size_t> read_done() override;
|
||||
|
||||
Conveyor<void> onReadDisconnected() override;
|
||||
Conveyor<void> on_read_disconnected() override;
|
||||
|
||||
void write(const void *buffer, size_t length) override;
|
||||
|
||||
Conveyor<size_t> writeDone() override;
|
||||
Conveyor<size_t> write_done() override;
|
||||
};
|
||||
|
||||
class Server {
|
||||
class server {
|
||||
public:
|
||||
virtual ~Server() = default;
|
||||
virtual ~server() = default;
|
||||
|
||||
virtual Conveyor<Own<IoStream>> accept() = 0;
|
||||
virtual Conveyor<Own<io_stream>> accept() = 0;
|
||||
};
|
||||
|
||||
class NetworkAddress;
|
||||
|
@ -102,16 +103,16 @@ class NetworkAddress;
|
|||
* datagram messages and send them as well as long as an address is provided as
|
||||
* well
|
||||
*/
|
||||
class Datagram {
|
||||
class datagram {
|
||||
public:
|
||||
virtual ~Datagram() = default;
|
||||
virtual ~datagram() = default;
|
||||
|
||||
virtual ErrorOr<size_t> read(void *buffer, size_t length) = 0;
|
||||
virtual Conveyor<void> readReady() = 0;
|
||||
virtual Conveyor<void> read_ready() = 0;
|
||||
|
||||
virtual ErrorOr<size_t> write(const void *buffer, size_t length,
|
||||
NetworkAddress &dest) = 0;
|
||||
virtual Conveyor<void> writeReady() = 0;
|
||||
virtual Conveyor<void> write_ready() = 0;
|
||||
};
|
||||
|
||||
class OsNetworkAddress;
|
||||
|
@ -139,8 +140,8 @@ public:
|
|||
|
||||
class StringNetworkAddress final : public NetworkAddress {
|
||||
private:
|
||||
std::string address_value;
|
||||
uint16_t port_value;
|
||||
std::string m_address_value;
|
||||
uint16_t m_port_value;
|
||||
|
||||
public:
|
||||
StringNetworkAddress(const std::string &address, uint16_t port);
|
||||
|
@ -151,46 +152,54 @@ public:
|
|||
NetworkAddress::ChildVariant representation() override { return this; }
|
||||
};
|
||||
|
||||
class Network {
|
||||
class network {
|
||||
public:
|
||||
virtual ~Network() = default;
|
||||
virtual ~network() = default;
|
||||
|
||||
/**
|
||||
* Resolve the provided string and uint16 to the preferred storage method
|
||||
*/
|
||||
virtual Conveyor<Own<NetworkAddress>>
|
||||
resolve_address(const std::string &addr, uint16_t port_hint = 0) = 0;
|
||||
|
||||
/**
|
||||
* Parse the provided string and uint16 to the preferred storage method
|
||||
* Since no dns request is made here, no async conveyors have to be used.
|
||||
*/
|
||||
virtual Conveyor<Own<NetworkAddress>>
|
||||
parseAddress(const std::string &addr, uint16_t port_hint = 0) = 0;
|
||||
/// @todo implement
|
||||
// virtual Own<NetworkAddress> parseAddress(const std::string& addr,
|
||||
// uint16_t port_hint = 0) = 0;
|
||||
|
||||
/**
|
||||
* Set up a listener on this address
|
||||
*/
|
||||
virtual Own<Server> listen(NetworkAddress &bind_addr) = 0;
|
||||
virtual Own<server> listen(NetworkAddress &bind_addr) = 0;
|
||||
|
||||
/**
|
||||
* Connect to a remote address
|
||||
*/
|
||||
virtual Conveyor<Own<IoStream>> connect(NetworkAddress &address) = 0;
|
||||
virtual Conveyor<Own<io_stream>> connect(NetworkAddress &address) = 0;
|
||||
|
||||
/**
|
||||
* Bind a datagram socket at this address.
|
||||
*/
|
||||
virtual Own<Datagram> datagram(NetworkAddress &address) = 0;
|
||||
virtual Own<datagram> datagram(NetworkAddress &address) = 0;
|
||||
};
|
||||
|
||||
class IoProvider {
|
||||
class io_provider {
|
||||
public:
|
||||
virtual ~IoProvider() = default;
|
||||
virtual ~io_provider() = default;
|
||||
|
||||
virtual Own<InputStream> wrapInputFd(int fd) = 0;
|
||||
virtual Own<InputStream> wrap_input_fd(int fd) = 0;
|
||||
|
||||
virtual Network &network() = 0;
|
||||
virtual network &network() = 0;
|
||||
};
|
||||
|
||||
struct AsyncIoContext {
|
||||
Own<IoProvider> io;
|
||||
Own<io_provider> io;
|
||||
EventLoop &event_loop;
|
||||
EventPort &event_port;
|
||||
};
|
||||
|
||||
ErrorOr<AsyncIoContext> setupAsyncIo();
|
||||
ErrorOr<AsyncIoContext> setup_async_io();
|
||||
} // namespace saw
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
#include "io_auth.h"
|
||||
|
||||
namespace saw {
|
||||
Peer::Peer(const std::string &identity_) : identity_value{identity_} {}
|
||||
Peer::Peer(std::string &&identity_) : identity_value{std::move(identity_)} {}
|
||||
|
||||
const std::string &Peer::identity() const { return identity_value; }
|
||||
} // namespace saw
|
|
@ -0,0 +1,53 @@
|
|||
#pragma once
|
||||
|
||||
#include "io.h"
|
||||
|
||||
namespace saw {
|
||||
class peer {
|
||||
public:
|
||||
peer(const std::string &ident);
|
||||
peer(std::string &&ident);
|
||||
|
||||
const std::string &identity() const;
|
||||
|
||||
private:
|
||||
std::string m_identity_value;
|
||||
};
|
||||
|
||||
class authenticated_io_stream {
|
||||
public:
|
||||
// This is the easiest way to implement Authenticated streams.
|
||||
// This is a simple pair of the stream and the peer.
|
||||
|
||||
Own<IoStream> stream;
|
||||
Maybe<Own<peer>> peer;
|
||||
};
|
||||
|
||||
class authenticated_server {
|
||||
public:
|
||||
virtual ~authenticated_server() = default;
|
||||
|
||||
virtual Conveyor<authenticated_io_stream> accept() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Authenticated Network class which provides a peer identity when connecting
|
||||
*/
|
||||
class authenticated_network {
|
||||
public:
|
||||
virtual ~authenticated_network() = default;
|
||||
|
||||
/**
|
||||
* Connects to the provided address.
|
||||
* Returns as soon as it is authenticated or fails
|
||||
*/
|
||||
virtual Conveyor<authenticated_io_stream>
|
||||
connect(NetworkAddress &address) = 0;
|
||||
|
||||
/**
|
||||
* Creates a server listening for connections
|
||||
*/
|
||||
virtual Own<authenticated_server> listen() = 0;
|
||||
};
|
||||
|
||||
} // namespace saw
|
|
@ -18,7 +18,7 @@ namespace saw {
|
|||
*/
|
||||
class InputStream;
|
||||
|
||||
class ReadTaskAndStepHelper {
|
||||
class read_task_and_step_helper {
|
||||
public:
|
||||
struct ReadIoTask {
|
||||
void *buffer;
|
||||
|
@ -32,12 +32,12 @@ public:
|
|||
Own<ConveyorFeeder<void>> on_read_disconnect = nullptr;
|
||||
|
||||
public:
|
||||
void readStep(InputStream &reader);
|
||||
void read_step(InputStream &reader);
|
||||
};
|
||||
|
||||
class OutputStream;
|
||||
|
||||
class WriteTaskAndStepHelper {
|
||||
class write_task_and_step_helper {
|
||||
public:
|
||||
struct WriteIoTask {
|
||||
const void *buffer;
|
||||
|
@ -48,6 +48,6 @@ public:
|
|||
Own<ConveyorFeeder<size_t>> write_done = nullptr;
|
||||
|
||||
public:
|
||||
void writeStep(OutputStream &writer);
|
||||
void write_step(OutputStream &writer);
|
||||
};
|
||||
} // namespace saw
|
||||
|
|
|
@ -1,41 +1,103 @@
|
|||
#pragma once
|
||||
|
||||
#include "async.h"
|
||||
#include "message.h"
|
||||
#include "buffer.h"
|
||||
#include "io.h"
|
||||
#include "message.h"
|
||||
|
||||
namespace saw {
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
class StreamingIoPeer {
|
||||
private:
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> incoming_feeder = nullptr;
|
||||
|
||||
Own<AsyncIoStream> io_stream;
|
||||
|
||||
Codec codec;
|
||||
|
||||
BufferT in_buffer;
|
||||
BufferT out_buffer;
|
||||
|
||||
SinkConveyor sink_read;
|
||||
SinkConveyor sink_write;
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer = MessageContainer<Incoming>,
|
||||
typename OutContainer = MessageContainer<Outgoing>,
|
||||
typename BufferT = RingBuffer>
|
||||
class streaming_io_peer {
|
||||
public:
|
||||
StreamingIoPeer(Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, Own<AsyncIoStream> stream, Codec codec, BufferT in, BufferT out);
|
||||
StreamingIoPeer(Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, Own<AsyncIoStream> stream);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
streaming_io_peer(
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
|
||||
Own<AsyncIoStream> stream, Codec codec, BufferT in, BufferT out);
|
||||
/**
|
||||
*
|
||||
*/
|
||||
streaming_io_peer(
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
|
||||
Own<AsyncIoStream> stream);
|
||||
|
||||
void send(HeapMessageRoot<Outgoing, OutContainer> builder);
|
||||
/**
|
||||
* Deleted copy and move constructors
|
||||
*/
|
||||
SAW_FORBID_COPY(streaming_io_peer);
|
||||
SAW_FORBID_MOVE(streaming_io_peer);
|
||||
|
||||
Conveyor<void> onReadDisconnected();
|
||||
/**
|
||||
* Send a message to the remote peer
|
||||
*/
|
||||
Error send(HeapMessageRoot<Outgoing, OutContainer> builder);
|
||||
|
||||
/**
|
||||
* A phantom conveyor feeder. Meant for interfacing with other components
|
||||
*/
|
||||
ConveyorFeeder<HeapMessageRoot<Outgoing, OutContainer>> &feeder();
|
||||
|
||||
Conveyor<void> on_read_disconnected();
|
||||
|
||||
private:
|
||||
/// @unimplemented
|
||||
class peer_conveyor_feeder final
|
||||
: public ConveyorFeeder<HeapMessageRoot<Outgoing, OutContainer>> {
|
||||
public:
|
||||
peer_conveyor_feeder(
|
||||
streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
|
||||
OutContainer, BufferT> &peer)
|
||||
: m_peer{peer} {}
|
||||
|
||||
void feed(HeapMessageRoot<Outgoing, OutContainer> &&data) override {
|
||||
(void)data;
|
||||
}
|
||||
|
||||
void fail(Error &&error) override { (void)error; }
|
||||
|
||||
size_t space() const override { return 0; }
|
||||
|
||||
size_t queued() const override { return 0; }
|
||||
|
||||
private:
|
||||
streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
|
||||
BufferT> &m_peer;
|
||||
};
|
||||
|
||||
private:
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>>
|
||||
m_incoming_feeder = nullptr;
|
||||
|
||||
Own<AsyncIoStream> m_io_stream;
|
||||
|
||||
Codec m_codec;
|
||||
|
||||
BufferT m_in_buffer;
|
||||
BufferT m_out_buffer;
|
||||
|
||||
ConveyorSink m_sink_read;
|
||||
ConveyorSink m_sink_write;
|
||||
|
||||
peer_conveyor_feeder m_conveyor_feeder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup new streaming io peer with the provided network protocols.
|
||||
* This is a convenience wrapper intended for a faster setup of
|
||||
* This is a convenience wrapper intended for a faster setup of this class
|
||||
*/
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
std::pair<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>, Conveyor<HeapMessageRoot<Incoming, InContainer>>> newStreamingIoPeer(Own<AsyncIoStream> stream);
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer = MessageContainer<Incoming>,
|
||||
typename OutContainer = MessageContainer<Outgoing>,
|
||||
typename BufferT = RingBuffer>
|
||||
std::pair<Own<streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
|
||||
OutContainer, BufferT>>,
|
||||
Conveyor<HeapMessageRoot<Incoming, InContainer>>>
|
||||
new_streaming_io_peer(Own<AsyncIoStream> stream);
|
||||
|
||||
} // namespace saw
|
||||
|
||||
|
|
|
@ -1,96 +1,115 @@
|
|||
namespace saw {
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::StreamingIoPeer(
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
|
||||
Own<AsyncIoStream> str
|
||||
):
|
||||
StreamingIoPeer{std::move(feed), std::move(str), {}, {}, {}}
|
||||
{
|
||||
}
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer, typename OutContainer, typename BufferT>
|
||||
streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
|
||||
BufferT>::
|
||||
streaming_io_peer(
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
|
||||
Own<AsyncIoStream> str)
|
||||
: streaming_io_peer{std::move(feed), std::move(str), {}, {}, {}} {}
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::StreamingIoPeer(
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
|
||||
Own<AsyncIoStream> str, Codec codec, BufferT in, BufferT out):
|
||||
incoming_feeder{std::move(feed)},
|
||||
io_stream{std::move(str)},
|
||||
codec{std::move(codec)},
|
||||
in_buffer{std::move(in)},
|
||||
out_buffer{std::move(out)},
|
||||
sink_read{
|
||||
io_stream->readDone().then([this](size_t bytes) -> ErrorOr<void> {
|
||||
in_buffer.writeAdvance(bytes);
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer, typename OutContainer, typename BufferT>
|
||||
streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
|
||||
BufferT>::
|
||||
streaming_io_peer(
|
||||
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed_,
|
||||
Own<AsyncIoStream> stream_, Codec codec_, BufferT in_, BufferT out_)
|
||||
: incoming_feeder{std::move(feed_)}, io_stream{std::move(stream_)},
|
||||
m_codec{std::move(codec_)}, m_in_buffer{std::move(in_)}, m_out_buffer{std::move(
|
||||
out_)},
|
||||
sink_read{io_stream->readDone()
|
||||
.then([streaming_io_peer](size_t bytes) -> ErrorOr<void> {
|
||||
in_buffer.writeAdvance(bytes);
|
||||
|
||||
if(in_buffer.writeSegmentLength() == 0){
|
||||
return criticalError("Message too long");
|
||||
}
|
||||
if (in_buffer.writeSegmentLength() == 0) {
|
||||
return criticalError("Message too long");
|
||||
}
|
||||
|
||||
io_stream->read(&in_buffer.write(), 1, in_buffer.writeSegmentLength());
|
||||
io_stream->read(&in_buffer.write(), 1,
|
||||
in_buffer.writeSegmentLength());
|
||||
|
||||
while(true){
|
||||
auto root = heapMessageRoot<Incoming, InContainer>();
|
||||
auto builder = root.build();
|
||||
while (true) {
|
||||
auto root =
|
||||
heapMessageRoot<Incoming, InContainer>();
|
||||
auto builder = root.build();
|
||||
|
||||
Error error = codec.template decode<Incoming, InContainer>(builder, in_buffer);
|
||||
if(error.isCritical()){
|
||||
return error;
|
||||
}
|
||||
Error error =
|
||||
codec.template decode<Incoming, InContainer>(
|
||||
builder, in_buffer);
|
||||
if (error.isCritical()) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if(!error.failed()){
|
||||
incoming_feeder->handle(std::move(root));
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!error.failed()) {
|
||||
incoming_feeder->feed(std::move(root));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Void{};
|
||||
}).sink([this](Error error){
|
||||
incoming_feeder->fail(error);
|
||||
return Void{};
|
||||
})
|
||||
.sink([streaming_io_peer](Error error) {
|
||||
incoming_feeder->fail(error.copyError());
|
||||
|
||||
return error;
|
||||
})
|
||||
},
|
||||
sink_write{
|
||||
io_stream->writeDone().then([this](size_bytes) -> ErrorOr<void> {
|
||||
out_buffer.readAdvance(bytes);
|
||||
if(out_buffer.readCompositeLength() > 0){
|
||||
io_stream->write(&out_buffer.read(), out_buffer.readSegmengtLength());
|
||||
}
|
||||
return error;
|
||||
})},
|
||||
sink_write{io_stream->writeDone()
|
||||
.then([streaming_io_peer](size_t bytes) -> ErrorOr<void> {
|
||||
out_buffer.readAdvance(bytes);
|
||||
if (out_buffer.readCompositeLength() > 0) {
|
||||
io_stream->write(&out_buffer.read(),
|
||||
out_buffer.readSegmentLength());
|
||||
}
|
||||
|
||||
return Void{};
|
||||
}).sink();
|
||||
}
|
||||
{
|
||||
return Void{};
|
||||
})
|
||||
.sink()} {
|
||||
io_stream->read(&in_buffer.write(), 1, in_buffer.writeSegmentLength());
|
||||
}
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
void StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::send(HeapMessageRoot<Outgoing, OutContainer> msg){
|
||||
bool restart_write = out_buffer.readSegmentLength() == 0;
|
||||
|
||||
Error error = codec.template encode<Outgoing, OutContainer>(msg.read(), out_buffer);
|
||||
if(error.failed()){
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer, typename OutContainer, typename BufferT>
|
||||
Error streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
|
||||
BufferT>::send(HeapMessageRoot<Outgoing, OutContainer>
|
||||
msg) {
|
||||
bool restart_write = m_out_buffer.readSegmentLength() == 0;
|
||||
|
||||
Error error =
|
||||
codec.template encode<Outgoing, OutContainer>(msg.read(), out_buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
||||
if(restart_write){
|
||||
if (restart_write) {
|
||||
io_stream->write(&out_buffer.read(), out_buffer.readSegmentLength());
|
||||
}
|
||||
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
Conveyor<void> StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::onReadDisconnected(){
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer, typename OutContainer, typename BufferT>
|
||||
Conveyor<void>
|
||||
streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
|
||||
BufferT>::on_read_disconnected() {
|
||||
return io_stream->onReadDisconnected();
|
||||
}
|
||||
|
||||
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
|
||||
std::pair<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>, Conveyor<HeapMessageRoot<Incoming, InContainer>>> newStreamingIoPeer(Own<AsyncIoStream> stream){
|
||||
template <typename Codec, typename Incoming, typename Outgoing,
|
||||
typename InContainer, typename OutContainer, typename BufferT>
|
||||
std::pair<Own<streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
|
||||
OutContainer, BufferT>>,
|
||||
Conveyor<HeapMessageRoot<Incoming, InContainer>>>
|
||||
new_streaming_io_peer(Own<AsyncIoStream> stream) {
|
||||
auto caf = newConveyorAndFeeder<HeapMessageRoot<Incoming, InContainer>>();
|
||||
|
||||
return {{std::move(caf.feeder), std::move(stream)}, std::move(caf.conveyor)};
|
||||
return {heap<streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
|
||||
OutContainer, BufferT>>(
|
||||
std::move(caf.feeder), std::move(stream)),
|
||||
std::move(caf.conveyor)};
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace saw
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
namespace saw {
|
||||
LogIo::LogIo(EventLoop &loop) : loop{loop} {}
|
||||
|
||||
Log::Log(LogIo ¢ral, EventLoop &loop) : central{central}, loop{loop} {}
|
||||
log::log(LogIo ¢ral, EventLoop &loop) : central{central}, loop{loop} {}
|
||||
} // namespace saw
|
|
@ -5,20 +5,20 @@
|
|||
namespace saw {
|
||||
class EventLoop;
|
||||
class LogIo;
|
||||
class Log {
|
||||
class log {
|
||||
public:
|
||||
enum class Type : uint8_t { Info, Warning, Error, Debug };
|
||||
|
||||
private:
|
||||
LogIo ¢ral;
|
||||
EventLoop &loop;
|
||||
LogIo &m_central;
|
||||
EventLoop &m_loop;
|
||||
|
||||
public:
|
||||
Log(LogIo ¢ral, EventLoop &loop);
|
||||
log(LogIo ¢ral, EventLoop &loop);
|
||||
};
|
||||
class LogIo {
|
||||
private:
|
||||
EventLoop &loop;
|
||||
EventLoop &m_loop;
|
||||
|
||||
public:
|
||||
LogIo(EventLoop &loop);
|
||||
|
|
|
@ -15,18 +15,18 @@
|
|||
#include "string_literal.h"
|
||||
|
||||
namespace saw {
|
||||
class MessageBase {
|
||||
class message_base {
|
||||
protected:
|
||||
bool set_explicitly = false;
|
||||
|
||||
public:
|
||||
template <class T> T &as() {
|
||||
static_assert(std::is_base_of<MessageBase, T>());
|
||||
static_assert(std::is_base_of<message_base, T>());
|
||||
return dynamic_cast<T &>(*this);
|
||||
}
|
||||
|
||||
template <class T> const T &as() const {
|
||||
static_assert(std::is_base_of<MessageBase, T>());
|
||||
static_assert(std::is_base_of<message_base, T>());
|
||||
return dynamic_cast<const T &>(*this);
|
||||
}
|
||||
};
|
||||
|
@ -46,11 +46,11 @@ public:
|
|||
*/
|
||||
template <class... V, StringLiteral... Keys, class Container>
|
||||
class Message<schema::Struct<schema::NamedMember<V, Keys>...>, Container> final
|
||||
: public MessageBase {
|
||||
: public message_base {
|
||||
private:
|
||||
using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>;
|
||||
using MessageType = Message<SchemaType, Container>;
|
||||
Container container;
|
||||
Container m_container;
|
||||
|
||||
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
|
||||
"Container should have same the schema as Message");
|
||||
|
@ -60,26 +60,26 @@ private:
|
|||
|
||||
public:
|
||||
class Reader;
|
||||
class Builder {
|
||||
class builder {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Builder(MessageType &msg) : message{msg} {}
|
||||
builder(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
Reader as_reader() { return Reader{m_message}; }
|
||||
|
||||
/*
|
||||
* Initialize a member by index
|
||||
*/
|
||||
template <size_t i>
|
||||
template <size_t I>
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
typename MessageParameterPackType<I, V...>::Type>::Value,
|
||||
typename Container::template ElementType<I>::Builder>::type
|
||||
init() {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>()};
|
||||
return typename Container::template ElementType<I>::Builder{
|
||||
m_message.m_container.template get<I>()};
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -101,15 +101,15 @@ public:
|
|||
return init<i>();
|
||||
}
|
||||
|
||||
template <size_t i>
|
||||
template <size_t I>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
typename MessageParameterPackType<I, V...>::Type>::Value,
|
||||
typename Container::template ElementType<I>::Builder>::type
|
||||
init(size_t size = 0) {
|
||||
auto array_builder =
|
||||
typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>(), size};
|
||||
typename Container::template ElementType<I>::Builder{
|
||||
m_message.m_container.template get<I>(), size};
|
||||
return array_builder;
|
||||
}
|
||||
|
||||
|
@ -134,20 +134,20 @@ public:
|
|||
|
||||
class Reader {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Reader(MessageType &msg) : message{msg} {}
|
||||
Reader(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Builder asBuilder() { return Builder{message}; }
|
||||
builder as_builder() { return builder{m_message}; }
|
||||
|
||||
/*
|
||||
* Get member by index
|
||||
*/
|
||||
template <size_t i>
|
||||
typename Container::template ElementType<i>::Reader get() {
|
||||
return typename Container::template ElementType<i>::Reader{
|
||||
message.container.template get<i>()};
|
||||
template <size_t I>
|
||||
typename Container::template ElementType<I>::Reader get() {
|
||||
return typename Container::template ElementType<I>::Reader{
|
||||
m_message.m_container.template get<I>()};
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -166,7 +166,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
Builder build() { return Builder{*this}; }
|
||||
builder build() { return builder{*this}; }
|
||||
|
||||
Reader read() { return Reader{*this}; }
|
||||
};
|
||||
|
@ -176,12 +176,12 @@ public:
|
|||
*/
|
||||
template <class... V, StringLiteral... Keys, class Container>
|
||||
class Message<schema::Union<schema::NamedMember<V, Keys>...>, Container> final
|
||||
: public MessageBase {
|
||||
: public message_base {
|
||||
private:
|
||||
using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>;
|
||||
using MessageType = Message<SchemaType, Container>;
|
||||
|
||||
Container container;
|
||||
Container m_container;
|
||||
|
||||
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
|
||||
"Container should have same the schema as Message");
|
||||
|
@ -191,24 +191,24 @@ private:
|
|||
|
||||
public:
|
||||
class Reader;
|
||||
class Builder {
|
||||
class builder {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Builder(MessageType &msg) : message{msg} {}
|
||||
builder(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
Reader as_reader() { return Reader{m_message}; }
|
||||
|
||||
template <size_t i>
|
||||
template <size_t I>
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
typename MessageParameterPackType<I, V...>::Type>::Value,
|
||||
typename Container::template ElementType<I>::Builder>::type
|
||||
|
||||
init() {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>()};
|
||||
return typename Container::template ElementType<I>::Builder{
|
||||
m_message.m_container.template get<I>()};
|
||||
}
|
||||
|
||||
template <StringLiteral Literal>
|
||||
|
@ -229,14 +229,14 @@ public:
|
|||
/*
|
||||
* If Schema is Array
|
||||
*/
|
||||
template <size_t i>
|
||||
template <size_t I>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<
|
||||
typename MessageParameterPackType<i, V...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
typename MessageParameterPackType<I, V...>::Type>::Value,
|
||||
typename Container::template ElementType<I>::Builder>::type
|
||||
init(size_t size = 0) {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>(), size};
|
||||
return typename Container::template ElementType<I>::Builder{
|
||||
m_message.m_container.template get<I>(), size};
|
||||
}
|
||||
|
||||
template <StringLiteral Literal>
|
||||
|
@ -257,17 +257,17 @@ public:
|
|||
|
||||
class Reader {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Reader(MessageType &msg) : message{msg} {}
|
||||
Reader(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Builder asBuilder() { return Builder{message}; }
|
||||
builder as_builder() { return builder{m_message}; }
|
||||
|
||||
template <size_t i>
|
||||
typename Container::template ElementType<i>::Reader get() {
|
||||
return typename Container::template ElementType<i>::Reader{
|
||||
message.container.template get<i>()};
|
||||
template <size_t I>
|
||||
typename Container::template ElementType<I>::Reader get() {
|
||||
return typename Container::template ElementType<I>::Reader{
|
||||
m_message.m_container.template get<I>()};
|
||||
}
|
||||
|
||||
template <StringLiteral Literal>
|
||||
|
@ -282,13 +282,13 @@ public:
|
|||
}
|
||||
|
||||
template <StringLiteral Literal>
|
||||
constexpr size_t toIndex() const noexcept {
|
||||
static constexpr size_t to_index() noexcept {
|
||||
return MessageParameterKeyPackIndex<Literal, Keys...>::Value;
|
||||
}
|
||||
|
||||
size_t index() const noexcept { return message.container.index(); }
|
||||
size_t index() const noexcept { return m_message.m_container.index(); }
|
||||
|
||||
template <StringLiteral Literal> bool hasAlternative() const {
|
||||
template <StringLiteral Literal> bool has_alternative() const {
|
||||
return index() == toIndex<Literal>();
|
||||
}
|
||||
};
|
||||
|
@ -298,12 +298,12 @@ public:
|
|||
* Array message class. Wrapper around an array schema element
|
||||
*/
|
||||
template <class T, class Container>
|
||||
class Message<schema::Array<T>, Container> final : public MessageBase {
|
||||
class Message<schema::Array<T>, Container> final : public message_base {
|
||||
private:
|
||||
using SchemaType = schema::Array<T>;
|
||||
using MessageType = Message<SchemaType, Container>;
|
||||
|
||||
Container container;
|
||||
Container m_container;
|
||||
|
||||
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
|
||||
"Container should have same Schema as Message");
|
||||
|
@ -313,44 +313,44 @@ private:
|
|||
|
||||
public:
|
||||
class Reader;
|
||||
class Builder {
|
||||
class builder {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Builder(MessageType &msg, size_t size) : message{msg} {
|
||||
builder(MessageType &msg, size_t size) : m_message{msg} {
|
||||
if (size > 0) {
|
||||
message.container.resize(size);
|
||||
m_message.m_container.resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
Reader as_reader() { return Reader{m_message}; }
|
||||
|
||||
typename Container::ElementType::Builder init(size_t i) {
|
||||
return typename Container::ElementType::Builder{
|
||||
message.container.get(i)};
|
||||
m_message.m_container.get(i)};
|
||||
}
|
||||
|
||||
size_t size() const { return message.container.size(); }
|
||||
size_t size() const { return m_message.m_container.size(); }
|
||||
|
||||
void resize(size_t size) { message.container.resize(size); }
|
||||
void resize(size_t size) { m_message.m_container.resize(size); }
|
||||
};
|
||||
|
||||
class Reader {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Reader(MessageType &msg) : message{msg} {}
|
||||
Reader(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Builder asBuilder() { return Builder{message, 0}; }
|
||||
builder as_builder() { return builder{m_message, 0}; }
|
||||
|
||||
typename Container::ElementType::Reader get(size_t i) {
|
||||
return typename Container::ElementType::Reader{
|
||||
message.container.get(i)};
|
||||
m_message.m_container.get(i)};
|
||||
}
|
||||
|
||||
size_t size() const { return message.container.size(); }
|
||||
size_t size() const { return m_message.m_container.size(); }
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -358,12 +358,12 @@ public:
|
|||
* Tuple message class. Wrapper around a tuple schema
|
||||
*/
|
||||
template <class... T, class Container>
|
||||
class Message<schema::Tuple<T...>, Container> final : public MessageBase {
|
||||
class Message<schema::Tuple<T...>, Container> final : public message_base {
|
||||
private:
|
||||
using SchemaType = schema::Tuple<T...>;
|
||||
using MessageType = Message<SchemaType, Container>;
|
||||
|
||||
Container container;
|
||||
Container m_container;
|
||||
|
||||
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
|
||||
"Container should have same the schema as Message");
|
||||
|
@ -373,47 +373,47 @@ private:
|
|||
|
||||
public:
|
||||
class Reader;
|
||||
class Builder {
|
||||
MessageType &message;
|
||||
class builder {
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Builder(MessageType &msg) : message{msg} {}
|
||||
builder(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
Reader as_reader() { return Reader{m_message}; }
|
||||
|
||||
template <size_t i>
|
||||
template <size_t I>
|
||||
typename std::enable_if<
|
||||
!SchemaIsArray<
|
||||
typename MessageParameterPackType<i, T...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
typename MessageParameterPackType<I, T...>::Type>::Value,
|
||||
typename Container::template ElementType<I>::Builder>::type
|
||||
init() {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>()};
|
||||
return typename Container::template ElementType<I>::Builder{
|
||||
m_message.m_container.template get<I>()};
|
||||
}
|
||||
|
||||
template <size_t i>
|
||||
template <size_t I>
|
||||
typename std::enable_if<
|
||||
SchemaIsArray<
|
||||
typename MessageParameterPackType<i, T...>::Type>::Value,
|
||||
typename Container::template ElementType<i>::Builder>::type
|
||||
typename MessageParameterPackType<I, T...>::Type>::Value,
|
||||
typename Container::template ElementType<I>::Builder>::type
|
||||
init(size_t size = 0) {
|
||||
return typename Container::template ElementType<i>::Builder{
|
||||
message.container.template get<i>(), size};
|
||||
return typename Container::template ElementType<I>::Builder{
|
||||
m_message.m_container.template get<I>(), size};
|
||||
}
|
||||
};
|
||||
class Reader {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Reader(MessageType &msg) : message{msg} {}
|
||||
Reader(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Builder asBuilder() { return Builder{message}; }
|
||||
builder as_builder() { return builder{m_message}; }
|
||||
|
||||
template <size_t i>
|
||||
typename Container::template ElementType<i>::Reader get() {
|
||||
return typename Container::template ElementType<i>::Reader{
|
||||
message.container.template get<i>()};
|
||||
template <size_t I>
|
||||
typename Container::template ElementType<I>::Reader get() {
|
||||
return typename Container::template ElementType<I>::Reader{
|
||||
m_message.m_container.template get<I>()};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
@ -423,12 +423,12 @@ public:
|
|||
* int16_t, int32_t, int64_t) message class
|
||||
*/
|
||||
template <class T, size_t N, class Container>
|
||||
class Message<schema::Primitive<T, N>, Container> final : public MessageBase {
|
||||
class Message<schema::Primitive<T, N>, Container> final : public message_base {
|
||||
private:
|
||||
using SchemaType = schema::Primitive<T, N>;
|
||||
using MessageType = Message<SchemaType, Container>;
|
||||
|
||||
Container container;
|
||||
Container m_container;
|
||||
|
||||
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
|
||||
"Container should have same the schema as Message");
|
||||
|
@ -438,42 +438,42 @@ private:
|
|||
|
||||
public:
|
||||
class Reader;
|
||||
class Builder {
|
||||
class builder {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Builder(MessageType &msg) : message{msg} {}
|
||||
builder(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
Reader as_reader() { return Reader{m_message}; }
|
||||
|
||||
void set(const typename Container::ValueType &value) {
|
||||
message.container.set(value);
|
||||
m_message.m_container.set(value);
|
||||
}
|
||||
};
|
||||
|
||||
class Reader {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Reader(Message &msg) : message{msg} {}
|
||||
Reader(Message &msg) : m_message{msg} {}
|
||||
|
||||
Builder asBuilder() { return Builder{message}; }
|
||||
builder as_builder() { return builder{m_message}; }
|
||||
|
||||
const typename Container::ValueType &get() const {
|
||||
return message.container.get();
|
||||
return m_message.m_container.get();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
class Message<schema::String, Container> final : public MessageBase {
|
||||
class Message<schema::String, Container> final : public message_base {
|
||||
private:
|
||||
using SchemaType = schema::String;
|
||||
using MessageType = Message<SchemaType, Container>;
|
||||
|
||||
Container container;
|
||||
Container m_container;
|
||||
|
||||
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
|
||||
"Container should have same the schema as Message");
|
||||
|
@ -483,40 +483,40 @@ private:
|
|||
|
||||
public:
|
||||
class Reader;
|
||||
class Builder {
|
||||
class builder {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Builder(MessageType &msg) : message{msg} {}
|
||||
builder(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Reader asReader() { return Reader{message}; }
|
||||
Reader as_reader() { return Reader{m_message}; }
|
||||
|
||||
void set(std::string &&str) { message.container.set(std::move(str)); }
|
||||
void set(const std::string_view str) { message.container.set(str); }
|
||||
void set(std::string &&str) { m_message.m_container.set(std::move(str)); }
|
||||
void set(const std::string_view str) { m_message.m_container.set(str); }
|
||||
void set(const char *str) { set(std::string_view{str}); }
|
||||
};
|
||||
|
||||
class Reader {
|
||||
private:
|
||||
MessageType &message;
|
||||
MessageType &m_message;
|
||||
|
||||
public:
|
||||
Reader(MessageType &msg) : message{msg} {}
|
||||
Reader(MessageType &msg) : m_message{msg} {}
|
||||
|
||||
Builder asBuilder() { return Builder{message}; }
|
||||
builder as_builder() { return builder{m_message}; }
|
||||
|
||||
const std::string_view get() const { return message.container.get(); }
|
||||
const std::string_view get() const { return m_message.m_container.get(); }
|
||||
};
|
||||
};
|
||||
|
||||
template <class Schema, class Container = MessageContainer<Schema>>
|
||||
class HeapMessageRoot {
|
||||
class heap_message_root {
|
||||
private:
|
||||
Own<Message<Schema, Container>> root;
|
||||
Own<Message<Schema, Container>> m_root;
|
||||
|
||||
public:
|
||||
HeapMessageRoot(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
|
||||
heap_message_root(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
|
||||
|
||||
typename Message<Schema, Container>::Builder build() {
|
||||
assert(root);
|
||||
|
@ -530,15 +530,15 @@ public:
|
|||
};
|
||||
|
||||
template <class T, class Container>
|
||||
class HeapMessageRoot<schema::Array<T>, Container> {
|
||||
class heap_message_root<schema::Array<T>, Container> {
|
||||
public:
|
||||
using Schema = schema::Array<T>;
|
||||
|
||||
private:
|
||||
Own<Message<Schema, Container>> root;
|
||||
Own<Message<Schema, Container>> m_root;
|
||||
|
||||
public:
|
||||
HeapMessageRoot(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
|
||||
heap_message_root(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
|
||||
|
||||
typename Message<Schema, Container>::Builder build(size_t size) {
|
||||
assert(root);
|
||||
|
@ -555,8 +555,8 @@ public:
|
|||
* Minor helper for creating a message root
|
||||
*/
|
||||
template <class Schema, class Container = MessageContainer<Schema>>
|
||||
inline HeapMessageRoot<Schema, Container> heapMessageRoot() {
|
||||
inline heap_message_root<Schema, Container> heap_message_root() {
|
||||
Own<Message<Schema, Container>> root = heap<Message<Schema, Container>>();
|
||||
return HeapMessageRoot<Schema, Container>{std::move(root)};
|
||||
return heap_message_root<Schema, Container>{std::move(root)};
|
||||
}
|
||||
} // namespace saw
|
||||
|
|
|
@ -5,16 +5,12 @@
|
|||
#include "stream_endian.h"
|
||||
|
||||
namespace saw {
|
||||
/// @todo replace types with these
|
||||
/*
|
||||
* I'm not really sure if anyone will use a union which is
|
||||
* bigger than uint32_t max. At least I hope noone would do this
|
||||
*/
|
||||
using msg_union_id_t = uint32_t;
|
||||
using msg_array_length_t = uint64_t;
|
||||
using msg_packet_length_t = uint64_t;
|
||||
class proto_kel_codec {
|
||||
public:
|
||||
using UnionIdT = uint32_t;
|
||||
using ArrayLengthT = uint64_t;
|
||||
using PacketLengthT = uint64_t;
|
||||
|
||||
class ProtoKelCodec {
|
||||
private:
|
||||
struct ReadContext {
|
||||
Buffer &buffer;
|
||||
|
@ -27,10 +23,10 @@ private:
|
|||
|
||||
public:
|
||||
struct Limits {
|
||||
msg_packet_length_t packet_size;
|
||||
proto_kel_codec::PacketLengthT packet_size;
|
||||
|
||||
Limits() : packet_size{4096} {}
|
||||
Limits(msg_packet_length_t ps) : packet_size{ps} {}
|
||||
Limits(proto_kel_codec::PacketLengthT ps) : packet_size{ps} {}
|
||||
};
|
||||
|
||||
struct Version {
|
||||
|
@ -101,17 +97,18 @@ struct ProtoKelEncodeImpl<Message<schema::String, Container>> {
|
|||
|
||||
template <class... T, class Container>
|
||||
struct ProtoKelEncodeImpl<Message<schema::Tuple<T...>, Container>> {
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<i == sizeof...(T), Error>::type
|
||||
encodeMembers(typename Message<schema::Tuple<T...>, Container>::Reader,
|
||||
Buffer &) {
|
||||
encode_members(typename Message<schema::Tuple<T...>, Container>::Reader,
|
||||
Buffer &) {
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<(i < sizeof...(T)), Error>::type
|
||||
encodeMembers(typename Message<schema::Tuple<T...>, Container>::Reader data,
|
||||
Buffer &buffer) {
|
||||
encode_members(
|
||||
typename Message<schema::Tuple<T...>, Container>::Reader data,
|
||||
Buffer &buffer) {
|
||||
Error error =
|
||||
ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
|
||||
encode(data.template get<i>(), buffer);
|
||||
|
@ -128,19 +125,19 @@ struct ProtoKelEncodeImpl<Message<schema::Tuple<T...>, Container>> {
|
|||
return encodeMembers<0>(data, buffer);
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
static typename std::enable_if<i == sizeof...(T), size_t>::type
|
||||
sizeMembers(typename Message<schema::Tuple<T...>, Container>::Reader) {
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<I == sizeof...(T), size_t>::type
|
||||
size_members(typename Message<schema::Tuple<T...>, Container>::Reader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(T), size_t>::type sizeMembers(
|
||||
I<sizeof...(T), size_t>::type size_members(
|
||||
typename Message<schema::Tuple<T...>, Container>::Reader reader) {
|
||||
return ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
|
||||
size(reader.template get<i>()) +
|
||||
sizeMembers<i + 1>(reader);
|
||||
return ProtoKelEncodeImpl<typename Container::template ElementType<I>>::
|
||||
size(reader.template get<I>()) +
|
||||
sizeMembers<I + 1>(reader);
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
@ -152,16 +149,17 @@ struct ProtoKelEncodeImpl<Message<schema::Tuple<T...>, Container>> {
|
|||
template <typename... V, StringLiteral... K, class Container>
|
||||
struct ProtoKelEncodeImpl<
|
||||
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> {
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<i == sizeof...(V), Error>::type
|
||||
encodeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader,
|
||||
Buffer &) {
|
||||
encode_members(
|
||||
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader,
|
||||
Buffer &) {
|
||||
return noError();
|
||||
}
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(V), Error>::type encodeMembers(
|
||||
i<sizeof...(V), Error>::type encode_members(
|
||||
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader data,
|
||||
Buffer &buffer) {
|
||||
|
@ -182,21 +180,21 @@ struct ProtoKelEncodeImpl<
|
|||
return encodeMembers<0>(data, buffer);
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
static typename std::enable_if<i == sizeof...(V), size_t>::type
|
||||
sizeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader) {
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<I == sizeof...(V), size_t>::type
|
||||
size_members(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(V), size_t>::type sizeMembers(
|
||||
I<sizeof...(V), size_t>::type size_members(
|
||||
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader reader) {
|
||||
return ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
|
||||
size(reader.template get<i>()) +
|
||||
sizeMembers<i + 1>(reader);
|
||||
return ProtoKelEncodeImpl<typename Container::template ElementType<I>>::
|
||||
size(reader.template get<I>()) +
|
||||
sizeMembers<I + 1>(reader);
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
@ -210,22 +208,23 @@ template <typename... V, StringLiteral... K, class Container>
|
|||
struct ProtoKelEncodeImpl<
|
||||
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> {
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<i == sizeof...(V), Error>::type
|
||||
encodeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader,
|
||||
Buffer &) {
|
||||
encode_members(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader,
|
||||
Buffer &) {
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(V), Error>::type encodeMembers(
|
||||
i<sizeof...(V), Error>::type encode_members(
|
||||
typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader reader,
|
||||
Buffer &buffer) {
|
||||
if (reader.index() == i) {
|
||||
Error error = StreamValue<msg_union_id_t>::encode(i, buffer);
|
||||
if (reader.index() == I) {
|
||||
Error error =
|
||||
StreamValue<proto_kel_codec::UnionIdT>::encode(i, buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -242,23 +241,23 @@ struct ProtoKelEncodeImpl<
|
|||
return encodeMembers<0>(reader, buffer);
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
static typename std::enable_if<i == sizeof...(V), size_t>::type
|
||||
sizeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader) {
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<I == sizeof...(V), size_t>::type
|
||||
size_members(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(V), size_t>::type sizeMembers(
|
||||
I<sizeof...(V), size_t>::type size_members(
|
||||
typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader reader) {
|
||||
if (reader.index() == i) {
|
||||
if (reader.index() == I) {
|
||||
return ProtoKelEncodeImpl<typename Container::template ElementType<
|
||||
i>>::size(reader.template get<i>());
|
||||
I>>::size(reader.template get<I>());
|
||||
}
|
||||
return sizeMembers<i + 1>(reader);
|
||||
return sizeMembers<I + 1>(reader);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -267,7 +266,7 @@ struct ProtoKelEncodeImpl<
|
|||
static size_t
|
||||
size(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Reader reader) {
|
||||
return sizeof(msg_union_id_t) + sizeMembers<0>(reader);
|
||||
return sizeof(proto_kel_codec::UnionIdT) + sizeMembers<0>(reader);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -276,10 +275,10 @@ struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> {
|
|||
static Error
|
||||
encode(typename Message<schema::Array<T>, Container>::Reader data,
|
||||
Buffer &buffer) {
|
||||
msg_array_length_t array_length = data.size();
|
||||
proto_kel_codec::ArrayLengthT array_length = data.size();
|
||||
{
|
||||
Error error =
|
||||
StreamValue<msg_array_length_t>::encode(array_length, buffer);
|
||||
Error error = StreamValue<proto_kel_codec::ArrayLengthT>::encode(
|
||||
array_length, buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -301,7 +300,7 @@ struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> {
|
|||
*/
|
||||
static size_t
|
||||
size(typename Message<schema::Array<T>, Container>::Reader data) {
|
||||
size_t members = sizeof(msg_array_length_t);
|
||||
size_t members = sizeof(proto_kel_codec::ArrayLengthT);
|
||||
for (size_t i = 0; i < data.size(); ++i) {
|
||||
members +=
|
||||
ProtoKelEncodeImpl<typename Container::ElementType>::size(
|
||||
|
@ -366,16 +365,16 @@ struct ProtoKelDecodeImpl<Message<schema::String, Container>> {
|
|||
|
||||
template <class... T, class Container>
|
||||
struct ProtoKelDecodeImpl<Message<schema::Tuple<T...>, Container>> {
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<i == sizeof...(T), Error>::type
|
||||
decodeMembers(typename Message<schema::Tuple<T...>, Container>::Builder,
|
||||
Buffer &) {
|
||||
decode_members(typename Message<schema::Tuple<T...>, Container>::Builder,
|
||||
Buffer &) {
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(T), Error>::type decodeMembers(
|
||||
i<sizeof...(T), Error>::type decode_members(
|
||||
typename Message<schema::Tuple<T...>, Container>::Builder builder,
|
||||
Buffer &buffer) {
|
||||
|
||||
|
@ -399,17 +398,18 @@ template <class... V, StringLiteral... K, class Container>
|
|||
struct ProtoKelDecodeImpl<
|
||||
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> {
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<i == sizeof...(V), Error>::type
|
||||
decodeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder,
|
||||
Buffer &) {
|
||||
decode_members(
|
||||
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder,
|
||||
Buffer &) {
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(V), Error>::type decodeMembers(
|
||||
i<sizeof...(V), Error>::type decode_members(
|
||||
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder builder,
|
||||
Buffer &buffer) {
|
||||
|
@ -434,22 +434,22 @@ struct ProtoKelDecodeImpl<
|
|||
template <class... V, StringLiteral... K, class Container>
|
||||
struct ProtoKelDecodeImpl<
|
||||
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> {
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if<i == sizeof...(V), Error>::type
|
||||
decodeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder,
|
||||
Buffer &, msg_union_id_t) {
|
||||
decode_members(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder,
|
||||
Buffer &, proto_kel_codec::UnionIdT) {
|
||||
return noError();
|
||||
}
|
||||
|
||||
template <size_t i = 0>
|
||||
template <size_t I = 0>
|
||||
static typename std::enable_if <
|
||||
i<sizeof...(V), Error>::type decodeMembers(
|
||||
i<sizeof...(V), Error>::type decode_members(
|
||||
typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder builder,
|
||||
Buffer &buffer, msg_union_id_t id) {
|
||||
Buffer &buffer, proto_kel_codec::UnionIdT id) {
|
||||
|
||||
if (id == i) {
|
||||
if (id == I) {
|
||||
Error error =
|
||||
ProtoKelDecodeImpl<typename Container::template ElementType<
|
||||
i>>::decode(builder.template init<i>(), buffer);
|
||||
|
@ -464,8 +464,9 @@ struct ProtoKelDecodeImpl<
|
|||
decode(typename Message<schema::Union<schema::NamedMember<V, K>...>,
|
||||
Container>::Builder builder,
|
||||
Buffer &buffer) {
|
||||
msg_union_id_t id = 0;
|
||||
Error error = StreamValue<msg_union_id_t>::decode(id, buffer);
|
||||
proto_kel_codec::UnionIdT id = 0;
|
||||
Error error =
|
||||
StreamValue<proto_kel_codec::UnionIdT>::decode(id, buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -482,10 +483,10 @@ struct ProtoKelDecodeImpl<Message<schema::Array<T>, Container>> {
|
|||
static Error
|
||||
decode(typename Message<schema::Array<T>, Container>::Builder data,
|
||||
Buffer &buffer) {
|
||||
msg_array_length_t array_length = 0;
|
||||
proto_kel_codec::ArrayLengthT array_length = 0;
|
||||
{
|
||||
Error error =
|
||||
StreamValue<msg_array_length_t>::decode(array_length, buffer);
|
||||
Error error = StreamValue<proto_kel_codec::ArrayLengthT>::decode(
|
||||
array_length, buffer);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -506,24 +507,24 @@ struct ProtoKelDecodeImpl<Message<schema::Array<T>, Container>> {
|
|||
};
|
||||
|
||||
template <class Schema, class Container>
|
||||
Error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader,
|
||||
Buffer &buffer) {
|
||||
Error proto_kel_codec::encode(
|
||||
typename Message<Schema, Container>::Reader reader, Buffer &buffer) {
|
||||
BufferView view{buffer};
|
||||
|
||||
msg_packet_length_t packet_length =
|
||||
proto_kel_codec::PacketLengthT packet_length =
|
||||
ProtoKelEncodeImpl<Message<Schema, Container>>::size(reader);
|
||||
// Check the size of the packet for the first
|
||||
// message length description
|
||||
|
||||
Error error =
|
||||
view.writeRequireLength(packet_length + sizeof(msg_packet_length_t));
|
||||
Error error = view.writeRequireLength(
|
||||
packet_length + sizeof(proto_kel_codec::PacketLengthT));
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
||||
{
|
||||
Error error =
|
||||
StreamValue<msg_packet_length_t>::encode(packet_length, view);
|
||||
Error error = StreamValue<proto_kel_codec::PacketLengthT>::encode(
|
||||
packet_length, view);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -541,15 +542,15 @@ Error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader,
|
|||
}
|
||||
|
||||
template <class Schema, class Container>
|
||||
Error ProtoKelCodec::decode(
|
||||
Error proto_kel_codec::decode(
|
||||
typename Message<Schema, Container>::Builder builder, Buffer &buffer,
|
||||
const Limits &limits) {
|
||||
BufferView view{buffer};
|
||||
|
||||
msg_packet_length_t packet_length = 0;
|
||||
proto_kel_codec::PacketLengthT packet_length = 0;
|
||||
{
|
||||
Error error =
|
||||
StreamValue<msg_packet_length_t>::decode(packet_length, view);
|
||||
Error error = StreamValue<proto_kel_codec::PacketLengthT>::decode(
|
||||
packet_length, view);
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -557,7 +558,7 @@ Error ProtoKelCodec::decode(
|
|||
|
||||
if (packet_length > limits.packet_size) {
|
||||
return criticalError(
|
||||
[packet_length]() {
|
||||
[proto_kel_codec]() {
|
||||
return std::string{"Packet size too big: "} +
|
||||
std::to_string(packet_length);
|
||||
},
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#pragma once
|
||||
|
||||
namespace saw {
|
||||
template<typename Codec, typename Schema> class Rpc;
|
||||
|
||||
/**
|
||||
* Provides the interface for messages with an rpc type behaviour
|
||||
*/
|
||||
template<typename Codec, typename... Responses, typename... Requests, StringLiteral... Literals>
|
||||
class Rpc<schema::Interface<schema::Function<Responses, Requests, Literals>...>> {
|
||||
public:
|
||||
|
||||
class Client {
|
||||
public:
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template<StringLiteral FunctionLiteral>
|
||||
Conveyor<Message<FunctionResponse>> request(Message<FunctionRequest> parameters);
|
||||
};
|
||||
|
||||
class Service {
|
||||
public:
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template<StringLiteral FunctionLiteral>
|
||||
Conveyor<Message<FunctionResponse>> handle(Message<FunctionRequest> request);
|
||||
};
|
||||
|
||||
class Server {
|
||||
|
||||
};
|
||||
};
|
||||
}
|
|
@ -1,24 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "string_literal.h"
|
||||
|
||||
namespace saw {
|
||||
namespace schema {
|
||||
|
||||
template <class T, StringLiteral Literal> struct NamedMember {};
|
||||
template <typename T, StringLiteral Literal> struct NamedMember {};
|
||||
|
||||
template <class... T> struct Struct;
|
||||
template <typename... T> struct Struct {
|
||||
static_assert(
|
||||
always_false<T...>,
|
||||
"This schema template doesn't support this type of template argument");
|
||||
};
|
||||
|
||||
template <class... V, StringLiteral... K>
|
||||
template <typename... V, StringLiteral... K>
|
||||
struct Struct<NamedMember<V, K>...> {};
|
||||
|
||||
template <class... T> struct Union;
|
||||
template <typename... T> struct Union {
|
||||
static_assert(
|
||||
always_false<T...>,
|
||||
"This schema template doesn't support this type of template argument");
|
||||
};
|
||||
|
||||
template <class... V, StringLiteral... K> struct Union<NamedMember<V, K>...> {};
|
||||
template <typename... V, StringLiteral... K>
|
||||
struct Union<NamedMember<V, K>...> {};
|
||||
|
||||
template <class T> struct Array {};
|
||||
template <typename T> struct Array {};
|
||||
|
||||
template <class... T> struct Tuple {};
|
||||
template <typename... T> struct Tuple {};
|
||||
|
||||
struct String {};
|
||||
|
||||
|
@ -47,5 +57,20 @@ using UInt64 = Primitive<UnsignedInteger, 8>;
|
|||
using Float32 = Primitive<FloatingPoint, 4>;
|
||||
using Float64 = Primitive<FloatingPoint, 8>;
|
||||
|
||||
/**
|
||||
* Classes enabling Rpc calls
|
||||
*/
|
||||
template <class Request, class Response, StringLiteral Literal>
|
||||
struct Function {};
|
||||
|
||||
template <class... T> struct Interface {
|
||||
static_assert(
|
||||
always_false<T...>,
|
||||
"This schema template doesn't support this type of template argument");
|
||||
};
|
||||
|
||||
template <class... Request, class... Response, StringLiteral... Literal>
|
||||
struct Interface<Function<Request, Response, Literal>...> {};
|
||||
|
||||
} // namespace schema
|
||||
} // namespace saw
|
||||
|
|
|
@ -15,16 +15,16 @@ namespace saw {
|
|||
* platform independent. So it does not matter if the memory layout is
|
||||
* little endian or big endian
|
||||
*/
|
||||
template <typename T, size_t size = sizeof(T)> class ShiftStreamValue;
|
||||
template <typename T, size_t Size = sizeof(T)> class ShiftStreamValue;
|
||||
|
||||
template <typename T> class ShiftStreamValue<T, 1> {
|
||||
public:
|
||||
inline static Error decode(T &val, Buffer &buffer) {
|
||||
inline static error decode(T &val, buffer &buffer) {
|
||||
uint8_t &raw = reinterpret_cast<uint8_t &>(val);
|
||||
return buffer.pop(raw, sizeof(T));
|
||||
}
|
||||
|
||||
inline static Error encode(const T &val, Buffer &buffer) {
|
||||
inline static error encode(const T &val, buffer &buffer) {
|
||||
const uint8_t &raw = reinterpret_cast<const uint8_t &>(val);
|
||||
return buffer.push(raw, sizeof(T));
|
||||
}
|
||||
|
@ -34,9 +34,9 @@ public:
|
|||
|
||||
template <typename T> class ShiftStreamValue<T, 2> {
|
||||
public:
|
||||
inline static Error decode(T &val, Buffer &buffer) {
|
||||
if (buffer.readCompositeLength() < sizeof(T)) {
|
||||
return recoverableError("Buffer too small");
|
||||
inline static error decode(T &val, buffer &buffer) {
|
||||
if (buffer.read_composite_length() < sizeof(T)) {
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
|
||||
uint16_t raw = 0;
|
||||
|
@ -45,13 +45,13 @@ public:
|
|||
raw |= (static_cast<uint16_t>(buffer.read(i)) << (i * 8));
|
||||
}
|
||||
memcpy(&val, &raw, sizeof(T));
|
||||
buffer.readAdvance(sizeof(T));
|
||||
buffer.read_advance(sizeof(T));
|
||||
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
inline static Error encode(const T &val, Buffer &buffer) {
|
||||
Error error = buffer.writeRequireLength(sizeof(T));
|
||||
inline static error encode(const T &val, buffer &buffer) {
|
||||
error error = buffer.write_require_length(sizeof(T));
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ public:
|
|||
buffer.write(i) = raw >> (i * 8);
|
||||
}
|
||||
|
||||
buffer.writeAdvance(sizeof(T));
|
||||
return noError();
|
||||
buffer.write_advance(sizeof(T));
|
||||
return no_error();
|
||||
}
|
||||
|
||||
inline static size_t size() { return sizeof(T); }
|
||||
|
@ -72,9 +72,9 @@ public:
|
|||
|
||||
template <typename T> class ShiftStreamValue<T, 4> {
|
||||
public:
|
||||
inline static Error decode(T &val, Buffer &buffer) {
|
||||
if (buffer.readCompositeLength() < sizeof(T)) {
|
||||
return recoverableError("Buffer too small");
|
||||
inline static error decode(T &val, buffer &buffer) {
|
||||
if (buffer.read_composite_length() < sizeof(T)) {
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
|
||||
uint32_t raw = 0;
|
||||
|
@ -83,13 +83,13 @@ public:
|
|||
raw |= (static_cast<uint32_t>(buffer.read(i)) << (i * 8));
|
||||
}
|
||||
memcpy(&val, &raw, sizeof(T));
|
||||
buffer.readAdvance(sizeof(T));
|
||||
buffer.read_advance(sizeof(T));
|
||||
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
inline static Error encode(const T &val, Buffer &buffer) {
|
||||
Error error = buffer.writeRequireLength(sizeof(T));
|
||||
inline static error encode(const T &val, buffer &buffer) {
|
||||
error error = buffer.write_require_length(sizeof(T));
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ public:
|
|||
buffer.write(i) = raw >> (i * 8);
|
||||
}
|
||||
|
||||
buffer.writeAdvance(sizeof(T));
|
||||
return noError();
|
||||
buffer.write_advance(sizeof(T));
|
||||
return no_error();
|
||||
}
|
||||
|
||||
inline static size_t size() { return sizeof(T); }
|
||||
|
@ -110,9 +110,9 @@ public:
|
|||
|
||||
template <typename T> class ShiftStreamValue<T, 8> {
|
||||
public:
|
||||
inline static Error decode(T &val, Buffer &buffer) {
|
||||
if (buffer.readCompositeLength() < sizeof(T)) {
|
||||
return recoverableError("Buffer too small");
|
||||
inline static error decode(T &val, buffer &buffer) {
|
||||
if (buffer.read_composite_length() < sizeof(T)) {
|
||||
return recoverable_error("Buffer too small");
|
||||
}
|
||||
|
||||
uint64_t raw = 0;
|
||||
|
@ -122,13 +122,13 @@ public:
|
|||
}
|
||||
|
||||
memcpy(&val, &raw, sizeof(T));
|
||||
buffer.readAdvance(sizeof(T));
|
||||
buffer.read_advance(sizeof(T));
|
||||
|
||||
return noError();
|
||||
return no_error();
|
||||
}
|
||||
|
||||
inline static Error encode(const T &val, Buffer &buffer) {
|
||||
Error error = buffer.writeRequireLength(sizeof(T));
|
||||
inline static error encode(const T &val, buffer &buffer) {
|
||||
error error = buffer.write_require_length(sizeof(T));
|
||||
if (error.failed()) {
|
||||
return error;
|
||||
}
|
||||
|
@ -140,8 +140,8 @@ public:
|
|||
buffer.write(i) = raw >> (i * 8);
|
||||
}
|
||||
|
||||
buffer.writeAdvance(sizeof(T));
|
||||
return noError();
|
||||
buffer.write_advance(sizeof(T));
|
||||
return no_error();
|
||||
}
|
||||
|
||||
inline static size_t size() { return sizeof(T); }
|
||||
|
|
|
@ -9,9 +9,9 @@ namespace saw {
|
|||
* literal. It guarantees compile time uniqueness and thus allows using strings
|
||||
* in template parameters.
|
||||
*/
|
||||
template <class CharT, size_t N> class StringLiteral {
|
||||
template <class CharT, size_t N> class string_literal {
|
||||
public:
|
||||
constexpr StringLiteral(const CharT (&input)[N]) noexcept {
|
||||
constexpr string_literal(const CharT (&input)[N]) noexcept {
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
data[i] = input[i];
|
||||
}
|
||||
|
@ -23,18 +23,18 @@ public:
|
|||
return std::string_view{data.data()};
|
||||
}
|
||||
|
||||
constexpr bool
|
||||
operator==(const StringLiteral<CharT, N> &) const noexcept = default;
|
||||
constexpr bool operator==(
|
||||
const ::saw::string_literal<CharT, N> &) const noexcept = default;
|
||||
|
||||
template <class CharTR, size_t NR>
|
||||
constexpr bool
|
||||
operator==(const StringLiteral<CharTR, NR> &) const noexcept {
|
||||
operator==(const ::saw::string_literal<CharTR, NR> &) const noexcept {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, T... Chars>
|
||||
constexpr StringLiteral<T, sizeof...(Chars)> operator""_key() {
|
||||
return StringLiteral<T, sizeof...(Chars) + 1u>{Chars..., '\0'};
|
||||
constexpr string_literal<T, sizeof...(Chars)> operator""_key() {
|
||||
return string_literal<T, sizeof...(Chars) + 1u>{Chars..., '\0'};
|
||||
}
|
||||
} // namespace saw
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#!/bin/false
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import glob
|
||||
|
||||
|
||||
Import('base_lib_env');
|
||||
Import('env');
|
||||
|
||||
dir_path = Dir('.').abspath
|
||||
|
||||
env.tls_sources += sorted(glob.glob(dir_path + "/*.cpp"))
|
||||
env.tls_headers += sorted(glob.glob(dir_path + "/*.h"))
|
||||
|
||||
tls_lib_env = base_lib_env.Clone();
|
||||
|
||||
tls_lib_env.Append(LIBS=['gnutls']);
|
||||
|
||||
### Shared lib
|
||||
|
||||
objects_shared = []
|
||||
tls_lib_env.add_source_files(objects_shared, env.tls_sources, shared=True);
|
||||
env.tls_library_shared = tls_lib_env.SharedLibrary('#build/forstio-tls', [objects_shared, env.library_shared]);
|
||||
|
||||
### Static lib
|
||||
|
||||
objects_static = []
|
||||
tls_lib_env.add_source_files(objects_static, env.tls_sources, shared=False);
|
||||
env.tls_library_static = tls_lib_env.StaticLibrary('#build/forstio-tls', [objects_static, env.library_static]);
|
||||
|
||||
|
||||
### Set alias
|
||||
env.Alias('library_tls', [env.tls_library_shared + env.tls_library_static]);
|
||||
|
|
@ -90,7 +90,7 @@ public:
|
|||
TlsServer::TlsServer(Own<Server> srv) : internal{std::move(srv)} {}
|
||||
|
||||
Conveyor<Own<IoStream>> TlsServer::accept() {
|
||||
SAW_ASSERT(internal) { return Conveyor<Own<IoStream>>{nullptr, nullptr}; }
|
||||
SAW_ASSERT(internal) { return Conveyor<Own<IoStream>>{FixVoid<Own<IoStream>>{nullptr}}; }
|
||||
return internal->accept().then([](Own<IoStream> stream) -> Own<IoStream> {
|
||||
/// @todo handshake
|
||||
|
||||
|
@ -106,9 +106,9 @@ namespace {
|
|||
struct TlsClientStreamHelper {
|
||||
public:
|
||||
Own<ConveyorFeeder<Own<IoStream>>> feeder;
|
||||
SinkConveyor connection_sink;
|
||||
SinkConveyor stream_reader;
|
||||
SinkConveyor stream_writer;
|
||||
ConveyorSink connection_sink;
|
||||
ConveyorSink stream_reader;
|
||||
ConveyorSink stream_writer;
|
||||
|
||||
Own<TlsIoStream> stream = nullptr;
|
||||
public:
|
||||
|
@ -235,13 +235,13 @@ static ssize_t forst_tls_pull_func(gnutls_transport_ptr_t p, void *data, size_t
|
|||
return static_cast<ssize_t>(length.value());
|
||||
}
|
||||
|
||||
TlsNetwork::TlsNetwork(Network &network) : internal{network} {}
|
||||
TlsNetwork::TlsNetwork(Tls& tls_, Network &network) : tls{tls_},internal{network} {}
|
||||
|
||||
Conveyor<Own<NetworkAddress>> TlsNetwork::parseAddress(const std::string &addr,
|
||||
Conveyor<Own<NetworkAddress>> TlsNetwork::resolveAddress(const std::string &addr,
|
||||
uint16_t port) {
|
||||
/// @todo tls server name needed. Check validity. Won't matter later on, because gnutls should fail anyway. But
|
||||
/// it's better to find the error source sooner rather than later
|
||||
return internal.parseAddress(addr, port);
|
||||
return internal.resolveAddress(addr, port);
|
||||
}
|
||||
|
||||
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network) {
|
||||
|
|
|
@ -7,21 +7,7 @@
|
|||
#include <variant>
|
||||
|
||||
namespace saw {
|
||||
class Tls {
|
||||
private:
|
||||
class Impl;
|
||||
Own<Impl> impl;
|
||||
|
||||
public:
|
||||
Tls();
|
||||
~Tls();
|
||||
|
||||
class Options {
|
||||
public:
|
||||
};
|
||||
|
||||
Impl &getImpl();
|
||||
};
|
||||
class Tls;
|
||||
|
||||
class TlsServer final : public Server {
|
||||
private:
|
||||
|
@ -35,13 +21,12 @@ public:
|
|||
|
||||
class TlsNetwork final : public Network {
|
||||
private:
|
||||
Tls tls;
|
||||
Tls& tls;
|
||||
Network &internal;
|
||||
|
||||
public:
|
||||
TlsNetwork(Network &network);
|
||||
TlsNetwork(Tls& tls_, Network &network_);
|
||||
|
||||
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &addr, uint16_t port = 0) override;
|
||||
Conveyor<Own<NetworkAddress>> resolveAddress(const std::string &addr, uint16_t port = 0) override;
|
||||
|
||||
Own<Server> listen(NetworkAddress& address) override;
|
||||
|
||||
|
@ -50,6 +35,36 @@ public:
|
|||
Own<Datagram> datagram(NetworkAddress& address) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tls context class.
|
||||
* Provides tls network class which ensures the usage of tls encrypted connections
|
||||
*/
|
||||
class Tls {
|
||||
private:
|
||||
class Impl;
|
||||
Own<Impl> impl;
|
||||
public:
|
||||
Tls();
|
||||
~Tls();
|
||||
|
||||
struct Version {
|
||||
struct Tls_1_0{};
|
||||
struct Tls_1_1{};
|
||||
struct Tls_1_2{};
|
||||
};
|
||||
|
||||
struct Options {
|
||||
public:
|
||||
Version version;
|
||||
};
|
||||
|
||||
Network& tlsNetwork();
|
||||
|
||||
Impl &getImpl();
|
||||
private:
|
||||
Options options;
|
||||
};
|
||||
|
||||
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network);
|
||||
|
||||
} // namespace saw
|
||||
|
|
|
@ -227,4 +227,36 @@ SAW_TEST("Async Merge"){
|
|||
SAW_EXPECT(!wrong_value, std::string{"Expected values 10 or 11"});
|
||||
SAW_EXPECT(elements_passed == 3, std::string{"Expected 2 passed elements, got only "} + std::to_string(elements_passed));
|
||||
}
|
||||
|
||||
SAW_TEST("Async Connect"){
|
||||
using namespace saw;
|
||||
|
||||
EventLoop event_loop;
|
||||
WaitScope wait_scope{event_loop};
|
||||
|
||||
auto caf1 = newConveyorAndFeeder<int>();
|
||||
|
||||
auto caf2 = newConveyorAndFeeder<float>();
|
||||
|
||||
bool val_passed = false;
|
||||
auto conveyor1 = caf1.conveyor.then([&val_passed](int val) -> float{
|
||||
val_passed = (val == 10);
|
||||
|
||||
return static_cast<float>(val);
|
||||
}).buffer(1);
|
||||
|
||||
bool val_passed_2 = false;
|
||||
auto sink = caf2.conveyor.then([&val_passed_2](float val) {
|
||||
val_passed_2 = (val == 10.f);
|
||||
}).sink();
|
||||
|
||||
caf1.feeder->feed(10);
|
||||
|
||||
caf2.feeder->swap(std::move(conveyor1));
|
||||
|
||||
wait_scope.poll();
|
||||
|
||||
SAW_EXPECT(val_passed, std::string{"Expected value 10"});
|
||||
SAW_EXPECT(val_passed_2, std::string{"Expected value 10.f"});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,8 +38,8 @@ SAW_TEST("Primitive Encoding"){
|
|||
Error error = codec.encode<TestSize>(root.read(), temp_buffer);
|
||||
|
||||
SAW_EXPECT(!error.failed(), error.message());
|
||||
SAW_EXPECT(temp_buffer.readCompositeLength() == (sizeof(value)+sizeof(msg_packet_length_t)), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength()));
|
||||
constexpr size_t pkt_shift = sizeof(msg_packet_length_t);
|
||||
SAW_EXPECT(temp_buffer.readCompositeLength() == (sizeof(value)+sizeof(ProtoKelCodec::PacketLengthT)), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength()));
|
||||
constexpr size_t pkt_shift = sizeof(ProtoKelCodec::PacketLengthT);
|
||||
SAW_EXPECT(temp_buffer[pkt_shift] == 5 && temp_buffer[pkt_shift+1] == 0 && temp_buffer[pkt_shift+2] == 0 && temp_buffer[pkt_shift+3] == 0, "Wrong encoded values");
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <forstio/error.h>
|
||||
|
||||
namespace saw {
|
||||
namespace tools {
|
||||
/// @todo implement from test code base
|
||||
template<typename Schema, typename Codec>
|
||||
Error cliMessageAnalyzer(Codec& codec, int argc, char** argv){
|
||||
// Parse Args
|
||||
|
||||
// If read is required
|
||||
// Read file into buffer
|
||||
|
||||
// If read is required
|
||||
// Decode file
|
||||
|
||||
// Execute commands
|
||||
|
||||
// If write is required
|
||||
// Encode into buffer
|
||||
// Write to file from buffer
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue