Compare commits

...

9 Commits

35 changed files with 3322 additions and 3254 deletions

View File

@ -1,26 +1,9 @@
Checks: '-*,clang-analyzer-*,clang-analyzer-cplusplus*,readability-identifier-naming' Checks: '-*,readability-identifier-naming'
CheckOptions: CheckOptions:
- { key: readability-identifier-naming.AggressiveDependentMemberLookup, value: true } - { key: readability-identifier-naming.PrivateMemberSuffix, value: "_" }
- { key: readability-identifier-naming.NamespaceCase, value: lower_case } - { key: readability-identifier-naming.AggressiveDependentMemberLookup, value: true }
- { key: readability-identifier-naming.EnumCase, value: lower_case } - { key: readability-identifier-naming.ProtectedMemberSuffix, value: "_" }
- { key: readability-identifier-naming.ConstexprFunctionCase, value: lower_case } - { key: readability-identifier-naming.ClassCase, value: "lower_case" }
- { key: readability-identifier-naming.ConstexprMethodCase, value: lower_case } - { key: readability-identifier-naming.StructCase, value: "lower_case" }
- { key: readability-identifier-naming.ConstexprVariableCase, value: lower_case } - { key: readability-identifier-naming.FunctionCase, value: "lower_case" }
- { key: readability-identifier-naming.EnumConstantCase, value: lower_case } - { key: readability-identifier-naming.MethodCase, value: "lower_case" }
- { key: readability-identifier-naming.ScopedEnumConstantCase, value: lower_case }
- { key: readability-identifier-naming.AbstractClassCase, value: lower_case }
- { key: readability-identifier-naming.ClassCase, value: lower_case }
- { key: readability-identifier-naming.ClassMethod, value: lower_case }
- { key: readability-identifier-naming.VirtualMethodCase, value: lower_case }
- { key: readability-identifier-naming.MemberCase, value: lower_case }
- { key: readability-identifier-naming.TemplateParameterCase, value: CamelCase }
- { key: readability-identifier-naming.ValueTemplateParameterCase, value: lower_case }
- { key: readability-identifier-naming.TypeTemplateParameterCase, 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.TypeAliasCase, value: lower_case }
- { key: readability-identifier-naming.VariableCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberCase, value: lower_case }
- { key: readability-identifier-naming.PrivateMemberSuffix, value: '_' }
- { key: readability-identifier-naming.ProtectedMemberSuffix, value: '_' }

View File

@ -73,15 +73,25 @@ env.Alias('test', env.test_program)
# Clang format part # Clang format part
env.Append(BUILDERS={'ClangFormat' : Builder(action = 'clang-format --style=file -i $SOURCE')}) env.Append(BUILDERS={'ClangFormat' : Builder(action = 'clang-format --style=file -i $SOURCE')})
env.format_actions = [] env.format_actions = [];
def format_iter(env,files): def format_iter(env,files):
for f in files: for f in files:
env.format_actions.append(env.AlwaysBuild(env.ClangFormat(target=f+"-clang-format",source=f))) env.format_actions.append(env.AlwaysBuild(env.ClangFormat(target=f+"-clang-format",source=f)))
pass pass
env.Append(BUILDERS={'ClangTidy' : Builder(action = 'clang-tidy -extra-arg-before=-xc++ $SOURCE')})
env.tidy_actions = [];
def tidy_iter(env,files):
string_of_files = "";
for f in files:
if(f != "/home/keldu/workspace/forstio/forstio/source/forstio/async.tmpl.h" and f != "/home/keldu/workspace/forstio/forstio/source/forstio/io_peer.tmpl.h" ):
env.tidy_actions.append(env.AlwaysBuild(env.ClangTidy(target=f+"-clang-tidy",source=f)));
pass
format_iter(env,env.sources + env.driver_sources + env.headers + env.driver_headers) format_iter(env,env.sources + env.driver_sources + env.headers + env.driver_headers);
tidy_iter(env,env.sources + env.driver_sources + env.headers + env.driver_headers);
env.Alias('format', env.format_actions) env.Alias('format', env.format_actions);
env.Alias('tidy', env.tidy_actions);
env.Alias('cdb', env.cdb); env.Alias('cdb', env.cdb);
env.Alias('all', ['format', 'library', 'test']) env.Alias('all', ['format', 'library', 'test'])

View File

@ -1,422 +0,0 @@
#include "io-unix.h"
#include <sstream>
namespace saw {
namespace unix {
IFdOwner::IFdOwner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask)
: event_port{event_port}, file_descriptor{file_descriptor},
fd_flags{fd_flags}, event_mask{event_mask} {
event_port.subscribe(*this, file_descriptor, event_mask);
}
IFdOwner::~IFdOwner() {
if (file_descriptor >= 0) {
event_port.unsubscribe(file_descriptor);
::close(file_descriptor);
}
}
ssize_t unixRead(int fd, void *buffer, size_t length) {
return ::recv(fd, buffer, length, 0);
}
ssize_t unixWrite(int fd, const void *buffer, size_t length) {
return ::send(fd, buffer, length, 0);
}
UnixIoStream::UnixIoStream(UnixEventPort &event_port, int file_descriptor,
int fd_flags, uint32_t event_mask)
: IFdOwner{event_port, file_descriptor, fd_flags, event_mask | EPOLLRDHUP} {
}
ErrorOr<size_t> UnixIoStream::read(void *buffer, size_t length) {
ssize_t read_bytes = unixRead(fd(), buffer, length);
if (read_bytes > 0) {
return static_cast<size_t>(read_bytes);
} else if (read_bytes == 0) {
return criticalError("Disconnected", Error::Code::Disconnected);
}
return recoverableError("Currently busy");
}
Conveyor<void> UnixIoStream::readReady() {
auto caf = newConveyorAndFeeder<void>();
read_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
Conveyor<void> UnixIoStream::onReadDisconnected() {
auto caf = newConveyorAndFeeder<void>();
on_read_disconnect = std::move(caf.feeder);
return std::move(caf.conveyor);
}
ErrorOr<size_t> UnixIoStream::write(const void *buffer, size_t length) {
ssize_t write_bytes = unixWrite(fd(), buffer, length);
if (write_bytes > 0) {
return static_cast<size_t>(write_bytes);
}
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return recoverableError("Currently busy");
}
return criticalError("Disconnected", Error::Code::Disconnected);
}
Conveyor<void> UnixIoStream::writeReady() {
auto caf = newConveyorAndFeeder<void>();
write_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
void UnixIoStream::notify(uint32_t mask) {
if (mask & EPOLLOUT) {
if (write_ready) {
write_ready->feed();
}
}
if (mask & EPOLLIN) {
if (read_ready) {
read_ready->feed();
}
}
if (mask & EPOLLRDHUP) {
if (on_read_disconnect) {
on_read_disconnect->feed();
}
}
}
UnixServer::UnixServer(UnixEventPort &event_port, int file_descriptor,
int fd_flags)
: IFdOwner{event_port, file_descriptor, fd_flags, EPOLLIN} {}
Conveyor<Own<IoStream>> UnixServer::accept() {
auto caf = newConveyorAndFeeder<Own<IoStream>>();
accept_feeder = std::move(caf.feeder);
return std::move(caf.conveyor);
}
void UnixServer::notify(uint32_t mask) {
if (mask & EPOLLIN) {
if (accept_feeder) {
struct ::sockaddr_storage address;
socklen_t address_length = sizeof(address);
int accept_fd =
::accept4(fd(), reinterpret_cast<struct ::sockaddr *>(&address),
&address_length, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (accept_fd < 0) {
return;
}
auto fd_stream = heap<UnixIoStream>(event_port, accept_fd, 0,
EPOLLIN | EPOLLOUT);
accept_feeder->feed(std::move(fd_stream));
}
}
}
UnixDatagram::UnixDatagram(UnixEventPort &event_port, int file_descriptor,
int fd_flags)
: IFdOwner{event_port, file_descriptor, fd_flags, EPOLLIN | EPOLLOUT} {}
namespace {
ssize_t unixReadMsg(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,
reinterpret_cast<struct ::sockaddr *>(&their_addr),
&addr_len);
}
ssize_t unixWriteMsg(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);
if (read_bytes > 0) {
return static_cast<size_t>(read_bytes);
}
return recoverableError("Currently busy");
}
Conveyor<void> UnixDatagram::readReady() {
auto caf = newConveyorAndFeeder<void>();
read_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
ErrorOr<size_t> UnixDatagram::write(const void *buffer, size_t length,
NetworkAddress &dest) {
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);
if (write_bytes > 0) {
return static_cast<size_t>(write_bytes);
}
return recoverableError("Currently busy");
}
Conveyor<void> UnixDatagram::writeReady() {
auto caf = newConveyorAndFeeder<void>();
write_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
void UnixDatagram::notify(uint32_t mask) {
if (mask & EPOLLOUT) {
if (write_ready) {
write_ready->feed();
}
}
if (mask & EPOLLIN) {
if (read_ready) {
read_ready->feed();
}
}
}
namespace {
bool beginsWith(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) {
auto addr_variant = addr.representation();
std::variant<UnixNetworkAddress, UnixNetworkAddress *> os_addr = std::visit(
[](auto &arg)
-> std::variant<UnixNetworkAddress, UnixNetworkAddress *> {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, OsNetworkAddress *>) {
return static_cast<UnixNetworkAddress *>(arg);
}
auto sock_addrs = SocketAddress::resolve(
std::string_view{arg->address()}, arg->port());
return UnixNetworkAddress{arg->address(), arg->port(),
std::move(sock_addrs)};
},
addr_variant);
return os_addr;
}
UnixNetworkAddress &translateToUnixAddressRef(
std::variant<UnixNetworkAddress, UnixNetworkAddress *> &addr_variant) {
return std::visit(
[](auto &arg) -> UnixNetworkAddress & {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, UnixNetworkAddress>) {
return arg;
} else if constexpr (std::is_same_v<T, UnixNetworkAddress *>) {
return *arg;
} else {
static_assert(true, "Cases exhausted");
}
},
addr_variant);
}
} // namespace
Own<Server> UnixNetwork::listen(NetworkAddress &addr) {
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
assert(address.unixAddressSize() > 0);
if (address.unixAddressSize() == 0) {
return nullptr;
}
int fd = address.unixAddress(0).socket(SOCK_STREAM);
if (fd < 0) {
return nullptr;
}
int val = 1;
int rc = ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if (rc < 0) {
::close(fd);
return nullptr;
}
bool failed = address.unixAddress(0).bind(fd);
if (failed) {
::close(fd);
return nullptr;
}
::listen(fd, SOMAXCONN);
return heap<UnixServer>(event_port, fd, 0);
}
Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
assert(address.unixAddressSize() > 0);
if (address.unixAddressSize() == 0) {
return Conveyor<Own<IoStream>>{criticalError("No address found")};
}
int fd = address.unixAddress(0).socket(SOCK_STREAM);
if (fd < 0) {
return Conveyor<Own<IoStream>>{criticalError("Couldn't open socket")};
}
Own<UnixIoStream> io_stream =
heap<UnixIoStream>(event_port, fd, 0, EPOLLIN | EPOLLOUT);
bool success = false;
for (size_t i = 0; i < address.unixAddressSize(); ++i) {
SocketAddress &addr_iter = address.unixAddress(i);
int status =
::connect(fd, addr_iter.getRaw(), addr_iter.getRawLength());
if (status < 0) {
int error = errno;
/*
* It's not connected yet...
* But edge triggered epolling means that it'll
* be ready when the signal is triggered
*/
/// @todo Add limit node when implemented
if (error == EINPROGRESS) {
/*
Conveyor<void> write_ready = io_stream->writeReady();
return write_ready.then(
[ios{std::move(io_stream)}]() mutable {
ios->write_ready = nullptr;
return std::move(ios);
});
*/
success = true;
break;
} else if (error != EINTR) {
/// @todo Push error message from
return Conveyor<Own<IoStream>>{
criticalError("Couldn't connect")};
}
} else {
success = true;
break;
}
}
if (!success) {
return criticalError("Couldn't connect");
}
return Conveyor<Own<IoStream>>{std::move(io_stream)};
}
Own<Datagram> UnixNetwork::datagram(NetworkAddress &addr) {
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
SAW_ASSERT(address.unixAddressSize() > 0) { return nullptr; }
int fd = address.unixAddress(0).socket(SOCK_DGRAM);
int optval = 1;
int rc =
::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (rc < 0) {
::close(fd);
return nullptr;
}
bool failed = address.unixAddress(0).bind(fd);
if (failed) {
::close(fd);
return nullptr;
}
/// @todo
return heap<UnixDatagram>(event_port, fd, 0);
}
const std::string &UnixNetworkAddress::address() const { return path; }
uint16_t UnixNetworkAddress::port() const { return port_hint; }
SocketAddress &UnixNetworkAddress::unixAddress(size_t i) {
assert(i < addresses.size());
/// @todo change from list to vector?
return addresses.at(i);
}
size_t UnixNetworkAddress::unixAddressSize() const { return addresses.size(); }
UnixNetwork::UnixNetwork(UnixEventPort &event) : event_port{event} {}
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)) {
addr_view.remove_prefix(begins_with.size());
}
}
std::vector<SocketAddress> addresses =
SocketAddress::resolve(addr_view, port_hint);
return Conveyor<Own<NetworkAddress>>{
heap<UnixNetworkAddress>(path, port_hint, std::move(addresses))};
}
UnixIoProvider::UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port)
: event_port{port_ref}, event_loop{std::move(port)}, unix_network{
port_ref} {}
Own<InputStream> UnixIoProvider::wrapInputFd(int fd) {
return heap<UnixIoStream>(event_port, fd, 0, EPOLLIN);
}
Network &UnixIoProvider::network() {
return static_cast<Network &>(unix_network);
}
EventLoop &UnixIoProvider::eventLoop() { return event_loop; }
} // namespace unix
ErrorOr<AsyncIoContext> setupAsyncIo() {
using namespace unix;
try {
Own<UnixEventPort> prt = heap<UnixEventPort>();
UnixEventPort &prt_ref = *prt;
Own<UnixIoProvider> io_provider =
heap<UnixIoProvider>(prt_ref, std::move(prt));
EventLoop &loop_ref = io_provider->eventLoop();
return {{std::move(io_provider), loop_ref, prt_ref}};
} catch (std::bad_alloc &) {
return criticalError("Out of memory");
}
}
} // namespace saw

View File

@ -1,465 +0,0 @@
#pragma once
#ifndef SAW_UNIX
#error "Don't include this"
#endif
#include <csignal>
#include <sys/signalfd.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <cassert>
#include <cstring>
#include <errno.h>
#include <unistd.h>
#include <queue>
#include <unordered_map>
#include <vector>
#include "forstio/io.h"
namespace saw {
namespace unix {
constexpr int MAX_EPOLL_EVENTS = 256;
class UnixEventPort;
class IFdOwner {
protected:
UnixEventPort &event_port;
private:
int file_descriptor;
int fd_flags;
uint32_t event_mask;
public:
IFdOwner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask);
virtual ~IFdOwner();
virtual void notify(uint32_t mask) = 0;
int fd() const { return file_descriptor; }
};
class UnixEventPort final : public EventPort {
private:
int epoll_fd;
int signal_fd;
sigset_t signal_fd_set;
std::unordered_multimap<Signal, Own<ConveyorFeeder<void>>> signal_conveyors;
int pipefds[2];
std::vector<int> toUnixSignal(Signal signal) const {
switch (signal) {
case Signal::User1:
return {SIGUSR1};
case Signal::Terminate:
default:
return {SIGTERM, SIGQUIT, SIGINT};
}
}
Signal fromUnixSignal(int signal) const {
switch (signal) {
case SIGUSR1:
return Signal::User1;
case SIGTERM:
case SIGINT:
case SIGQUIT:
default:
return Signal::Terminate;
}
}
void notifySignalListener(int sig) {
Signal signal = fromUnixSignal(sig);
auto equal_range = signal_conveyors.equal_range(signal);
for (auto iter = equal_range.first; iter != equal_range.second;
++iter) {
if (iter->second) {
if (iter->second->space() > 0) {
iter->second->feed();
}
}
}
}
bool pollImpl(int time) {
epoll_event events[MAX_EPOLL_EVENTS];
int nfds = 0;
do {
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, time);
if (nfds < 0) {
/// @todo error_handling
return false;
}
for (int i = 0; i < nfds; ++i) {
if (events[i].data.u64 == 0) {
while (1) {
struct ::signalfd_siginfo siginfo;
ssize_t n =
::read(signal_fd, &siginfo, sizeof(siginfo));
if (n < 0) {
break;
}
assert(n == sizeof(siginfo));
notifySignalListener(siginfo.ssi_signo);
}
} else if (events[i].data.u64 == 1) {
uint8_t i;
if (pipefds[0] < 0) {
continue;
}
while (1) {
ssize_t n = ::recv(pipefds[0], &i, sizeof(i), 0);
if (n < 0) {
break;
}
}
} else {
IFdOwner *owner =
reinterpret_cast<IFdOwner *>(events[i].data.ptr);
if (owner) {
owner->notify(events[i].events);
}
}
}
} while (nfds == MAX_EPOLL_EVENTS);
return true;
}
public:
UnixEventPort() : epoll_fd{-1}, signal_fd{-1} {
::signal(SIGPIPE, SIG_IGN);
epoll_fd = ::epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd < 0) {
return;
}
::sigemptyset(&signal_fd_set);
signal_fd = ::signalfd(-1, &signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd < 0) {
return;
}
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.u64 = 0;
::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, signal_fd, &event);
int rc = ::pipe2(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);
}
~UnixEventPort() {
::close(epoll_fd);
::close(signal_fd);
::close(pipefds[0]);
::close(pipefds[1]);
}
Conveyor<void> onSignal(Signal signal) override {
auto caf = newConveyorAndFeeder<void>();
signal_conveyors.insert(std::make_pair(signal, std::move(caf.feeder)));
std::vector<int> sig = toUnixSignal(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);
auto node = Conveyor<void>::fromConveyor(std::move(caf.conveyor));
return Conveyor<void>::toConveyor(std::move(node));
}
void poll() override { pollImpl(0); }
void wait() override { pollImpl(-1); }
void wait(const std::chrono::steady_clock::duration &duration) override {
pollImpl(std::chrono::duration_cast<std::chrono::milliseconds>(duration)
.count());
}
void
wait(const std::chrono::steady_clock::time_point &time_point) override {
auto now = std::chrono::steady_clock::now();
if (time_point <= now) {
poll();
} else {
pollImpl(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) {
return;
}
uint8_t i = 0;
::send(pipefds[1], &i, sizeof(i), MSG_DONTWAIT);
}
void subscribe(IFdOwner &owner, int fd, uint32_t event_mask) {
if (epoll_fd < 0 || fd < 0) {
return;
}
::epoll_event event;
memset(&event, 0, sizeof(event));
event.events = event_mask | EPOLLET;
event.data.ptr = &owner;
if (::epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event) < 0) {
/// @todo error_handling
return;
}
}
void unsubscribe(int fd) {
if (epoll_fd < 0 || fd < 0) {
return;
}
if (::epoll_ctl(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);
class UnixIoStream final : public IoStream, public IFdOwner {
private:
Own<ConveyorFeeder<void>> read_ready = nullptr;
Own<ConveyorFeeder<void>> on_read_disconnect = nullptr;
Own<ConveyorFeeder<void>> write_ready = nullptr;
public:
UnixIoStream(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> onReadDisconnected() override;
ErrorOr<size_t> write(const void *buffer, size_t length) override;
Conveyor<void> writeReady() override;
/*
void read(void *buffer, size_t min_length, size_t max_length) override;
Conveyor<size_t> readDone() override;
Conveyor<void> readReady() override;
Conveyor<void> onReadDisconnected() override;
void write(const void *buffer, size_t length) override;
Conveyor<size_t> writeDone() override;
Conveyor<void> writeReady() override;
*/
void notify(uint32_t mask) override;
};
class UnixServer final : public Server, public IFdOwner {
private:
Own<ConveyorFeeder<Own<IoStream>>> accept_feeder = nullptr;
public:
UnixServer(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 {
private:
Own<ConveyorFeeder<void>> read_ready = nullptr;
Own<ConveyorFeeder<void>> write_ready = nullptr;
public:
UnixDatagram(UnixEventPort &event_port, int file_descriptor, int fd_flags);
ErrorOr<size_t> read(void *buffer, size_t length) override;
Conveyor<void> readReady() override;
ErrorOr<size_t> write(const void *buffer, size_t length,
NetworkAddress &dest) override;
Conveyor<void> writeReady() override;
void notify(uint32_t mask) override;
};
/**
* Helper class which provides potential addresses to NetworkAddress
*/
class SocketAddress {
private:
union {
struct sockaddr generic;
struct sockaddr_un unix;
struct sockaddr_in inet;
struct sockaddr_in6 inet6;
struct sockaddr_storage storage;
} address;
socklen_t address_length;
bool wildcard;
SocketAddress() : 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);
}
int socket(int type) const {
type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
int result = ::socket(address.generic.sa_family, type, 0);
return result;
}
bool bind(int fd) const {
if (wildcard) {
int value = 0;
::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
}
int error = ::bind(fd, &address.generic, address_length);
return error < 0;
}
struct ::sockaddr *getRaw() {
return &address.generic;
}
const struct ::sockaddr *getRaw() const { return &address.generic; }
socklen_t getRawLength() const { return address_length; }
static std::vector<SocketAddress> resolve(std::string_view str,
uint16_t port_hint) {
std::vector<SocketAddress> results;
struct ::addrinfo *head;
struct ::addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
std::string port_string = std::to_string(port_hint);
bool wildcard = str == "*" || str == "::";
std::string address_string{str};
int error = ::getaddrinfo(address_string.c_str(), port_string.c_str(),
&hints, &head);
if (error) {
return {};
}
for (struct ::addrinfo *it = head; it != nullptr; it = it->ai_next) {
if (it->ai_addrlen > sizeof(SocketAddress::address)) {
continue;
}
results.push_back({it->ai_addr, it->ai_addrlen, wildcard});
}
::freeaddrinfo(head);
return results;
}
};
class UnixNetworkAddress final : public OsNetworkAddress {
private:
const std::string path;
uint16_t port_hint;
std::vector<SocketAddress> 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)} {}
const std::string &address() const override;
uint16_t port() const override;
// Custom address info
SocketAddress &unixAddress(size_t i = 0);
size_t unixAddressSize() const;
};
class UnixNetwork final : public Network {
private:
UnixEventPort &event_port;
public:
UnixNetwork(UnixEventPort &event_port);
Conveyor<Own<NetworkAddress>>
resolveAddress(const std::string &address, uint16_t port_hint = 0) override;
Own<Server> listen(NetworkAddress &addr) override;
Conveyor<Own<IoStream>> connect(NetworkAddress &addr) override;
Own<Datagram> datagram(NetworkAddress &addr) override;
};
class UnixIoProvider final : public IoProvider {
private:
UnixEventPort &event_port;
EventLoop event_loop;
UnixNetwork unix_network;
public:
UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port);
Network &network() override;
Own<InputStream> wrapInputFd(int fd) override;
EventLoop &eventLoop();
};
} // namespace unix
} // namespace saw

434
driver/io_unix.cpp Normal file
View File

@ -0,0 +1,434 @@
#include "io_unix.h"
#include <sstream>
namespace saw {
namespace unix {
i_fd_owner::i_fd_owner(unix_event_port &event_port, int file_descriptor,
int fd_flags, uint32_t event_mask)
: event_port_{event_port}, file_descriptor_{file_descriptor},
fd_flags_{fd_flags}, event_mask_{event_mask} {
event_port_.subscribe(*this, file_descriptor, event_mask);
}
i_fd_owner::~i_fd_owner() {
if (file_descriptor_ >= 0) {
event_port_.unsubscribe(file_descriptor_);
::close(file_descriptor_);
}
}
ssize_t unix_read(int fd, void *buffer, size_t length) {
return ::recv(fd, buffer, length, 0);
}
ssize_t unix_write(int fd, const void *buffer, size_t length) {
return ::send(fd, buffer, length, 0);
}
unix_io_stream::unix_io_stream(unix_event_port &event_port, int file_descriptor,
int fd_flags, uint32_t event_mask)
: i_fd_owner{event_port, file_descriptor, fd_flags,
event_mask | EPOLLRDHUP} {}
error_or<size_t> unix_io_stream::read(void *buffer, size_t length) {
ssize_t read_bytes = unix_read(fd(), buffer, length);
if (read_bytes > 0) {
return static_cast<size_t>(read_bytes);
} else if (read_bytes == 0) {
return critical_error("Disconnected", error::code::Disconnected);
}
return recoverable_error("Currently busy");
}
conveyor<void> unix_io_stream::read_ready() {
auto caf = new_conveyor_and_feeder<void>();
read_ready_ = std::move(caf.feeder);
return std::move(caf.conveyor);
}
conveyor<void> unix_io_stream::on_read_disconnected() {
auto caf = new_conveyor_and_feeder<void>();
on_read_disconnect_ = std::move(caf.feeder);
return std::move(caf.conveyor);
}
error_or<size_t> unix_io_stream::write(const void *buffer, size_t length) {
ssize_t write_bytes = unix_write(fd(), buffer, length);
if (write_bytes > 0) {
return static_cast<size_t>(write_bytes);
}
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return recoverable_error("Currently busy");
}
return critical_error("Disconnected", error::code::Disconnected);
}
conveyor<void> unix_io_stream::write_ready() {
auto caf = new_conveyor_and_feeder<void>();
write_ready_ = std::move(caf.feeder);
return std::move(caf.conveyor);
}
void unix_io_stream::notify(uint32_t mask) {
if (mask & EPOLLOUT) {
if (write_ready_) {
write_ready_->feed();
}
}
if (mask & EPOLLIN) {
if (read_ready_) {
read_ready_->feed();
}
}
if (mask & EPOLLRDHUP) {
if (on_read_disconnect_) {
on_read_disconnect_->feed();
}
}
}
unix_server::unix_server(unix_event_port &event_port, int file_descriptor,
int fd_flags)
: i_fd_owner{event_port, file_descriptor, fd_flags, EPOLLIN} {}
conveyor<own<io_stream>> unix_server::accept() {
auto caf = new_conveyor_and_feeder<own<io_stream>>();
accept_feeder_ = std::move(caf.feeder);
return std::move(caf.conveyor);
}
void unix_server::notify(uint32_t mask) {
if (mask & EPOLLIN) {
if (accept_feeder_) {
struct ::sockaddr_storage address;
socklen_t address_length = sizeof(address);
int accept_fd =
::accept4(fd(), reinterpret_cast<struct ::sockaddr *>(&address),
&address_length, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (accept_fd < 0) {
return;
}
auto fd_stream = heap<unix_io_stream>(event_port_, accept_fd, 0,
EPOLLIN | EPOLLOUT);
accept_feeder_->feed(std::move(fd_stream));
}
}
}
unix_datagram::unix_datagram(unix_event_port &event_port, int file_descriptor,
int fd_flags)
: i_fd_owner{event_port, file_descriptor, fd_flags, EPOLLIN | EPOLLOUT} {}
namespace {
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,
reinterpret_cast<struct ::sockaddr *>(&their_addr),
&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
error_or<size_t> unix_datagram::read(void *buffer, size_t length) {
ssize_t read_bytes = unix_read_msg(fd(), buffer, length);
if (read_bytes > 0) {
return static_cast<size_t>(read_bytes);
}
return recoverable_error("Currently busy");
}
conveyor<void> unix_datagram::read_ready() {
auto caf = new_conveyor_and_feeder<void>();
read_ready_ = std::move(caf.feeder);
return std::move(caf.conveyor);
}
error_or<size_t> unix_datagram::write(const void *buffer, size_t length,
network_address &dest) {
unix_network_address &unix_dest = static_cast<unix_network_address &>(dest);
socket_address &sock_addr = unix_dest.unix_address();
socklen_t sock_addr_length = sock_addr.get_raw_length();
ssize_t write_bytes = unix_write_msg(fd(), buffer, length,
sock_addr.get_raw(), sock_addr_length);
if (write_bytes > 0) {
return static_cast<size_t>(write_bytes);
}
return recoverable_error("Currently busy");
}
conveyor<void> unix_datagram::write_ready() {
auto caf = new_conveyor_and_feeder<void>();
write_ready_ = std::move(caf.feeder);
return std::move(caf.conveyor);
}
void unix_datagram::notify(uint32_t mask) {
if (mask & EPOLLOUT) {
if (write_ready_) {
write_ready_->feed();
}
}
if (mask & EPOLLIN) {
if (read_ready_) {
read_ready_->feed();
}
}
}
namespace {
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<unix_network_address, unix_network_address *>
translate_network_address_to_unix_network_address(network_address &addr) {
auto addr_variant = addr.representation();
std::variant<unix_network_address, unix_network_address *> os_addr =
std::visit(
[](auto &arg)
-> std::variant<unix_network_address, unix_network_address *> {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, os_network_address *>) {
return static_cast<unix_network_address *>(arg);
}
auto sock_addrs = socket_address::resolve(
std::string_view{arg->address()}, arg->port());
return unix_network_address{arg->address(), arg->port(),
std::move(sock_addrs)};
},
addr_variant);
return os_addr;
}
unix_network_address &translate_to_unix_address_ref(
std::variant<unix_network_address, unix_network_address *> &addr_variant) {
return std::visit(
[](auto &arg) -> unix_network_address & {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, unix_network_address>) {
return arg;
} else if constexpr (std::is_same_v<T, unix_network_address *>) {
return *arg;
} else {
static_assert(true, "Cases exhausted");
}
},
addr_variant);
}
} // namespace
own<server> unix_network::listen(network_address &addr) {
auto unix_addr_storage =
translate_network_address_to_unix_network_address(addr);
unix_network_address &address =
translate_to_unix_address_ref(unix_addr_storage);
assert(address.unix_address_size() > 0);
if (address.unix_address_size() == 0) {
return nullptr;
}
int fd = address.unix_address(0).socket(SOCK_STREAM);
if (fd < 0) {
return nullptr;
}
int val = 1;
int rc = ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
if (rc < 0) {
::close(fd);
return nullptr;
}
bool failed = address.unix_address(0).bind(fd);
if (failed) {
::close(fd);
return nullptr;
}
::listen(fd, SOMAXCONN);
return heap<unix_server>(event_port_, fd, 0);
}
conveyor<own<io_stream>> unix_network::connect(network_address &addr) {
auto unix_addr_storage =
translate_network_address_to_unix_network_address(addr);
unix_network_address &address =
translate_to_unix_address_ref(unix_addr_storage);
assert(address.unix_address_size() > 0);
if (address.unix_address_size() == 0) {
return conveyor<own<io_stream>>{critical_error("No address found")};
}
int fd = address.unix_address(0).socket(SOCK_STREAM);
if (fd < 0) {
return conveyor<own<io_stream>>{critical_error("Couldn't open socket")};
}
own<unix_io_stream> io_str =
heap<unix_io_stream>(event_port_, fd, 0, EPOLLIN | EPOLLOUT);
bool success = false;
for (size_t i = 0; i < address.unix_address_size(); ++i) {
socket_address &addr_iter = address.unix_address(i);
int status =
::connect(fd, addr_iter.get_raw(), addr_iter.get_raw_length());
if (status < 0) {
int error = errno;
/*
* It's not connected yet...
* But edge triggered epolling means that it'll
* be ready when the signal is triggered
*/
/// @todo Add limit node when implemented
if (error == EINPROGRESS) {
/*
Conveyor<void> write_ready = io_stream->writeReady();
return write_ready.then(
[ios{std::move(io_stream)}]() mutable {
ios->write_ready = nullptr;
return std::move(ios);
});
*/
success = true;
break;
} else if (error != EINTR) {
/// @todo Push error message from
return conveyor<own<io_stream>>{
critical_error("Couldn't connect")};
}
} else {
success = true;
break;
}
}
if (!success) {
return critical_error("Couldn't connect");
}
return conveyor<own<io_stream>>{std::move(io_str)};
}
own<datagram> unix_network::datagram(network_address &addr) {
auto unix_addr_storage =
translate_network_address_to_unix_network_address(addr);
unix_network_address &address =
translate_to_unix_address_ref(unix_addr_storage);
SAW_ASSERT(address.unix_address_size() > 0) { return nullptr; }
int fd = address.unix_address(0).socket(SOCK_DGRAM);
int optval = 1;
int rc =
::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
if (rc < 0) {
::close(fd);
return nullptr;
}
bool failed = address.unix_address(0).bind(fd);
if (failed) {
::close(fd);
return nullptr;
}
/// @todo
return heap<unix_datagram>(event_port_, fd, 0);
}
const std::string &unix_network_address::address() const { return path_; }
uint16_t unix_network_address::port() const { return port_hint_; }
socket_address &unix_network_address::unix_address(size_t i) {
assert(i < addresses_.size());
/// @todo change from list to vector?
return addresses_.at(i);
}
size_t unix_network_address::unix_address_size() const {
return addresses_.size();
}
unix_network::unix_network(unix_event_port &event) : event_port_{event} {}
conveyor<own<network_address>>
unix_network::resolve_address(const std::string &path, uint16_t port_hint) {
std::string_view addr_view{path};
{
std::string_view str_begins_with = "unix:";
if (begins_with(addr_view, str_begins_with)) {
addr_view.remove_prefix(str_begins_with.size());
}
}
std::vector<socket_address> addresses =
socket_address::resolve(addr_view, port_hint);
return conveyor<own<network_address>>{
heap<unix_network_address>(path, port_hint, std::move(addresses))};
}
unix_io_provider::unix_io_provider(unix_event_port &port_ref,
own<event_port> port)
: event_port_{port_ref}, event_loop_{std::move(port)}, unix_network_{
port_ref} {}
own<input_stream> unix_io_provider::wrap_input_fd(int fd) {
return heap<unix_io_stream>(event_port_, fd, 0, EPOLLIN);
}
class network &unix_io_provider::network() {
return static_cast<class network &>(unix_network_);
}
class event_loop &unix_io_provider::event_loop() {
return event_loop_;
}
} // namespace unix
error_or<async_io_context> setup_async_io() {
using namespace unix;
try {
own<unix_event_port> prt = heap<unix_event_port>();
unix_event_port &prt_ref = *prt;
own<unix_io_provider> io_provider =
heap<unix_io_provider>(prt_ref, std::move(prt));
event_loop &loop_ref = io_provider->event_loop();
return {{std::move(io_provider), loop_ref, prt_ref}};
} catch (std::bad_alloc &) {
return critical_error("Out of memory");
}
}
} // namespace saw

470
driver/io_unix.h Normal file
View File

@ -0,0 +1,470 @@
#pragma once
#ifndef SAW_UNIX
#error "Don't include this"
#endif
#include <csignal>
#include <sys/signalfd.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <cassert>
#include <cstring>
#include <errno.h>
#include <unistd.h>
#include <queue>
#include <unordered_map>
#include <vector>
#include "io.h"
namespace saw {
namespace unix {
constexpr int MAX_EPOLL_EVENTS = 256;
class unix_event_port;
class i_fd_owner {
protected:
unix_event_port &event_port_;
private:
int file_descriptor_;
int fd_flags_;
uint32_t event_mask_;
public:
i_fd_owner(unix_event_port &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask);
virtual ~i_fd_owner();
virtual void notify(uint32_t mask) = 0;
int fd() const { return file_descriptor_; }
};
class unix_event_port final : public event_port {
private:
int epoll_fd_;
int signal_fd_;
sigset_t signal_fd_set_;
std::unordered_multimap<Signal, own<conveyor_feeder<void>>>
signal_conveyors_;
int pipefds_[2];
std::vector<int> to_unix_signal(Signal signal) const {
switch (signal) {
case Signal::User1:
return {SIGUSR1};
case Signal::Terminate:
default:
return {SIGTERM, SIGQUIT, SIGINT};
}
}
Signal from_unix_signal(int signal) const {
switch (signal) {
case SIGUSR1:
return Signal::User1;
case SIGTERM:
case SIGINT:
case SIGQUIT:
default:
return Signal::Terminate;
}
}
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;
++iter) {
if (iter->second) {
if (iter->second->space() > 0) {
iter->second->feed();
}
}
}
}
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);
if (nfds < 0) {
/// @todo error_handling
return false;
}
for (int i = 0; i < nfds; ++i) {
if (events[i].data.u64 == 0) {
while (1) {
struct ::signalfd_siginfo siginfo;
ssize_t n =
::read(signal_fd_, &siginfo, sizeof(siginfo));
if (n < 0) {
break;
}
assert(n == sizeof(siginfo));
notify_signal_listener(siginfo.ssi_signo);
}
} else if (events[i].data.u64 == 1) {
uint8_t i;
if (pipefds_[0] < 0) {
continue;
}
while (1) {
ssize_t n = ::recv(pipefds_[0], &i, sizeof(i), 0);
if (n < 0) {
break;
}
}
} else {
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);
return true;
}
public:
unix_event_port() : epoll_fd_{-1}, signal_fd_{-1} {
::signal(SIGPIPE, SIG_IGN);
epoll_fd_ = ::epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd_ < 0) {
return;
}
::sigemptyset(&signal_fd_set_);
signal_fd_ =
::signalfd(-1, &signal_fd_set_, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd_ < 0) {
return;
}
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.u64 = 0;
::epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, signal_fd_, &event);
int rc = ::pipe2(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);
}
~unix_event_port() {
::close(epoll_fd_);
::close(signal_fd_);
::close(pipefds_[0]);
::close(pipefds_[1]);
}
conveyor<void> on_signal(Signal signal) override {
auto caf = new_conveyor_and_feeder<void>();
signal_conveyors_.insert(std::make_pair(signal, std::move(caf.feeder)));
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);
auto node = conveyor<void>::from_conveyor(std::move(caf.conveyor));
return conveyor<void>::to_conveyor(std::move(node));
}
void poll() override { poll_impl(0); }
void wait() override { poll_impl(-1); }
void wait(const std::chrono::steady_clock::duration &duration) override {
poll_impl(
std::chrono::duration_cast<std::chrono::milliseconds>(duration)
.count());
}
void
wait(const std::chrono::steady_clock::time_point &time_point) override {
auto now = std::chrono::steady_clock::now();
if (time_point <= now) {
poll();
} else {
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) {
return;
}
uint8_t i = 0;
::send(pipefds_[1], &i, sizeof(i), MSG_DONTWAIT);
}
void subscribe(i_fd_owner &owner, int fd, uint32_t event_mask) {
if (epoll_fd_ < 0 || fd < 0) {
return;
}
::epoll_event event;
memset(&event, 0, sizeof(event));
event.events = event_mask | EPOLLET;
event.data.ptr = &owner;
if (::epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event) < 0) {
/// @todo error_handling
return;
}
}
void unsubscribe(int fd) {
if (epoll_fd_ < 0 || fd < 0) {
return;
}
if (::epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, nullptr) < 0) {
/// @todo error_handling
return;
}
}
};
ssize_t unix_read(int fd, void *buffer, size_t length);
ssize_t unix_write(int fd, const void *buffer, size_t length);
class unix_io_stream final : public io_stream, public i_fd_owner {
private:
own<conveyor_feeder<void>> read_ready_ = nullptr;
own<conveyor_feeder<void>> on_read_disconnect_ = nullptr;
own<conveyor_feeder<void>> write_ready_ = nullptr;
public:
unix_io_stream(unix_event_port &event_port, int file_descriptor,
int fd_flags, uint32_t event_mask);
error_or<size_t> read(void *buffer, size_t length) override;
conveyor<void> read_ready() override;
conveyor<void> on_read_disconnected() override;
error_or<size_t> write(const void *buffer, size_t length) override;
conveyor<void> write_ready() override;
/*
void read(void *buffer, size_t min_length, size_t max_length) override;
Conveyor<size_t> readDone() override;
Conveyor<void> readReady() override;
Conveyor<void> onReadDisconnected() override;
void write(const void *buffer, size_t length) override;
Conveyor<size_t> writeDone() override;
Conveyor<void> writeReady() override;
*/
void notify(uint32_t mask) override;
};
class unix_server final : public server, public i_fd_owner {
private:
own<conveyor_feeder<own<io_stream>>> accept_feeder_ = nullptr;
public:
unix_server(unix_event_port &event_port, int file_descriptor, int fd_flags);
conveyor<own<io_stream>> accept() override;
void notify(uint32_t mask) override;
};
class unix_datagram final : public datagram, public i_fd_owner {
private:
own<conveyor_feeder<void>> read_ready_ = nullptr;
own<conveyor_feeder<void>> write_ready_ = nullptr;
public:
unix_datagram(unix_event_port &event_port, int file_descriptor,
int fd_flags);
error_or<size_t> read(void *buffer, size_t length) override;
conveyor<void> read_ready() override;
error_or<size_t> write(const void *buffer, size_t length,
network_address &dest) override;
conveyor<void> write_ready() override;
void notify(uint32_t mask) override;
};
/**
* Helper class which provides potential addresses to NetworkAddress
*/
class socket_address {
private:
union {
struct sockaddr generic;
struct sockaddr_un unix;
struct sockaddr_in inet;
struct sockaddr_in6 inet6;
struct sockaddr_storage storage;
} address_;
socklen_t address_length_;
bool wildcard_;
socket_address() : wildcard_{false} {}
public:
socket_address(const void *sockaddr, socklen_t len, bool wildcard)
: address_length_{len}, wildcard_{wildcard} {
assert(len <= sizeof(address_));
memcpy(&address_.generic, sockaddr, len);
}
int socket(int type) const {
type |= SOCK_NONBLOCK | SOCK_CLOEXEC;
int result = ::socket(address_.generic.sa_family, type, 0);
return result;
}
bool bind(int fd) const {
if (wildcard_) {
int value = 0;
::setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &value, sizeof(value));
}
int error = ::bind(fd, &address_.generic, address_length_);
return error < 0;
}
struct ::sockaddr *get_raw() {
return &address_.generic;
}
const struct ::sockaddr *get_raw() const { return &address_.generic; }
socklen_t get_raw_length() const { return address_length_; }
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;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
std::string port_string = std::to_string(port_hint);
bool wildcard = str == "*" || str == "::";
std::string address_string{str};
int error = ::getaddrinfo(address_string.c_str(), port_string.c_str(),
&hints, &head);
if (error) {
return {};
}
for (struct ::addrinfo *it = head; it != nullptr; it = it->ai_next) {
if (it->ai_addrlen > sizeof(socket_address::address_)) {
continue;
}
results.push_back({it->ai_addr, it->ai_addrlen, wildcard});
}
::freeaddrinfo(head);
return results;
}
};
class unix_network_address final : public os_network_address {
private:
const std::string path_;
uint16_t port_hint_;
std::vector<socket_address> addresses_;
public:
unix_network_address(const std::string &path, uint16_t port_hint,
std::vector<socket_address> &&addr)
: path_{path}, port_hint_{port_hint}, addresses_{std::move(addr)} {}
const std::string &address() const override;
uint16_t port() const override;
// Custom address info
socket_address &unix_address(size_t i = 0);
size_t unix_address_size() const;
};
class unix_network final : public network {
private:
unix_event_port &event_port_;
public:
unix_network(unix_event_port &event_port);
conveyor<own<network_address>>
resolve_address(const std::string &address,
uint16_t port_hint = 0) override;
own<server> listen(network_address &addr) override;
conveyor<own<io_stream>> connect(network_address &addr) override;
own<class datagram> datagram(network_address &addr) override;
};
class unix_io_provider final : public io_provider {
private:
unix_event_port &event_port_;
class event_loop event_loop_;
unix_network unix_network_;
public:
unix_io_provider(unix_event_port &port_ref, own<event_port> port);
class network &network() override;
own<input_stream> wrap_input_fd(int fd) override;
class event_loop &event_loop();
};
} // namespace unix
} // namespace saw

View File

@ -7,38 +7,38 @@
namespace saw { namespace saw {
namespace { namespace {
thread_local EventLoop *local_loop = nullptr; thread_local event_loop *local_loop = nullptr;
EventLoop &currentEventLoop() { event_loop &current_event_loop() {
EventLoop *loop = local_loop; event_loop *loop = local_loop;
assert(loop); assert(loop);
return *loop; return *loop;
} }
} // namespace } // namespace
ConveyorNode::ConveyorNode() {} conveyor_node::conveyor_node() {}
ConveyorNodeWithChildMixin::ConveyorNodeWithChildMixin( conveyor_node_with_child_mixin::conveyor_node_with_child_mixin(
Own<ConveyorNode> &&child_, ConveyorNode &owner) own<conveyor_node> &&child_, conveyor_node &owner)
: child{std::move(child_)} { : child{std::move(child_)} {
assert(child); assert(child);
child->notifyParentAttached(owner); child->notify_parent_attached(owner);
} }
ErrorOr<Own<ConveyorNode>> error_or<own<conveyor_node>>
ConveyorNodeWithChildMixin::swapChild(Own<ConveyorNode> &&swapee) { conveyor_node_with_child_mixin::swap_child(own<conveyor_node> &&swapee) {
SAW_ASSERT(child) { SAW_ASSERT(child) {
return criticalError("Child should exist if this function is called"); return critical_error("Child should exist if this function is called");
} }
Own<ConveyorNode> old_child = std::move(child); own<conveyor_node> old_child = std::move(child);
/** /**
* We need the parent of the old_child's next storage * We need the parent of the old_child's next storage
*/ */
ConveyorStorage *old_storage = old_child->nextStorage(); conveyor_storage *old_storage = old_child->next_storage();
ConveyorStorage *old_storage_parent = old_storage ? old_storage->getParent() conveyor_storage *old_storage_parent =
: nullptr; old_storage ? old_storage->get_parent() : nullptr;
/** /**
* Swap in the new child * Swap in the new child
@ -51,176 +51,176 @@ ConveyorNodeWithChildMixin::swapChild(Own<ConveyorNode> &&swapee) {
* storage has a nullptr set And if the old_storage_parent is a nullptr, * 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 * then it doesn't matter. So we don't check for it
*/ */
ConveyorStorage *swapee_storage = child->nextStorage(); conveyor_storage *swapee_storage = child->next_storage();
if (swapee_storage) { if (swapee_storage) {
swapee_storage->setParent(old_storage_parent); swapee_storage->set_parent(old_storage_parent);
} }
} }
return old_child; return old_child;
} }
ConveyorStorage::ConveyorStorage() {} conveyor_storage::conveyor_storage() {}
ConveyorStorage::~ConveyorStorage() {} conveyor_storage::~conveyor_storage() {}
ConveyorStorage *ConveyorStorage::getParent() const { return parent; } conveyor_storage *conveyor_storage::get_parent() const { return parent_; }
void ConveyorEventStorage::setParent(ConveyorStorage *p) { void conveyor_event_storage::set_parent(conveyor_storage *p) {
/* /*
* parent check isn't needed, but is used * parent check isn't needed, but is used
* for the assert, because the storage should * for the assert, because the storage should
* be armed if there was an element present * be armed if there was an element present
* and a valid parent * and a valid parent
*/ */
if (/*!parent && */ p && !isArmed() && queued() > 0) { if (/*!parent && */ p && !is_armed() && queued() > 0) {
assert(!parent); assert(!parent_);
if (p->space() > 0) { if (p->space() > 0) {
armLater(); arm_later();
} }
} }
parent = p; parent_ = p;
} }
ConveyorEventStorage::ConveyorEventStorage() : ConveyorStorage{} {} conveyor_event_storage::conveyor_event_storage() : conveyor_storage{} {}
ConveyorBase::ConveyorBase(Own<ConveyorNode> &&node_p) conveyor_base::conveyor_base(own<conveyor_node> &&node_p)
: node{std::move(node_p)} {} : node_{std::move(node_p)} {}
Error PropagateError::operator()(const Error &error) const { error propagate_error::operator()(const error &error) const {
return error.copyError(); return error.copy_error();
} }
Error PropagateError::operator()(Error &&error) { return std::move(error); } error propagate_error::operator()(error &&err) { return std::move(err); }
Event::Event() : Event(currentEventLoop()) {} event::event() : event(current_event_loop()) {}
Event::Event(EventLoop &loop) : loop{loop} {} event::event(event_loop &loop) : loop_{loop} {}
Event::~Event() { disarm(); } event::~event() { disarm(); }
void Event::armNext() { void event::arm_next() {
assert(&loop == local_loop); assert(&loop_ == local_loop);
if (prev == nullptr) { if (prev_ == nullptr) {
// Push the next_insert_point back by one // Push the next_insert_point back by one
// and inserts itself before that // and inserts itself before that
next = *loop.next_insert_point; next_ = *loop_.next_insert_point_;
prev = loop.next_insert_point; prev_ = loop_.next_insert_point_;
*prev = this; *prev_ = this;
if (next) { if (next_) {
next->prev = &next; next_->prev_ = &next_;
} }
// Set the new insertion ptr location to next // Set the new insertion ptr location to next
loop.next_insert_point = &next; loop_.next_insert_point_ = &next_;
// Pushes back the later insert point if it was pointing at the // Pushes back the later insert point if it was pointing at the
// previous event // previous event
if (loop.later_insert_point == prev) { if (loop_.later_insert_point_ == prev_) {
loop.later_insert_point = &next; loop_.later_insert_point_ = &next_;
} }
// If tail points at the same location then // If tail_ points at the same location then
// we are at the end and have to update tail then. // we are at the end and have to update tail_ then.
// Technically should be possible by checking if // Technically should be possible by checking if
// next is a `nullptr` // next is a `nullptr`
if (loop.tail == prev) { if (loop_.tail_ == prev_) {
loop.tail = &next; loop_.tail_ = &next_;
} }
loop.setRunnable(true); loop_.set_runnable(true);
} }
} }
void Event::armLater() { void event::arm_later() {
assert(&loop == local_loop); assert(&loop_ == local_loop);
if (prev == nullptr) { if (prev_ == nullptr) {
next = *loop.later_insert_point; next_ = *loop_.later_insert_point_;
prev = loop.later_insert_point; prev_ = loop_.later_insert_point_;
*prev = this; *prev_ = this;
if (next) { if (next_) {
next->prev = &next; next_->prev_ = &next_;
} }
loop.later_insert_point = &next; loop_.later_insert_point_ = &next_;
if (loop.tail == prev) { if (loop_.tail_ == prev_) {
loop.tail = &next; loop_.tail_ = &next_;
} }
loop.setRunnable(true); loop_.set_runnable(true);
} }
} }
void Event::armLast() { void event::arm_last() {
assert(&loop == local_loop); assert(&loop_ == local_loop);
if (prev == nullptr) { if (prev_ == nullptr) {
next = *loop.later_insert_point; next_ = *loop_.later_insert_point_;
prev = loop.later_insert_point; prev_ = loop_.later_insert_point_;
*prev = this; *prev_ = this;
if (next) { if (next_) {
next->prev = &next; next_->prev_ = &next_;
} }
if (loop.tail == prev) { if (loop_.tail_ == prev_) {
loop.tail = &next; loop_.tail_ = &next_;
} }
loop.setRunnable(true); loop_.set_runnable(true);
} }
} }
void Event::disarm() { void event::disarm() {
if (prev != nullptr) { if (prev_ != nullptr) {
if (loop.tail == &next) { if (loop_.tail_ == &next_) {
loop.tail = prev; loop_.tail_ = prev_;
} }
if (loop.next_insert_point == &next) { if (loop_.next_insert_point_ == &next_) {
loop.next_insert_point = prev; loop_.next_insert_point_ = prev_;
} }
*prev = next; *prev_ = next_;
if (next) { if (next_) {
next->prev = prev; next_->prev_ = prev_;
} }
prev = nullptr; prev_ = nullptr;
next = nullptr; next_ = nullptr;
} }
} }
bool Event::isArmed() const { return prev != nullptr; } bool event::is_armed() const { return prev_ != nullptr; }
ConveyorSink::ConveyorSink() : node{nullptr} {} conveyor_sink::conveyor_sink() : node_{nullptr} {}
ConveyorSink::ConveyorSink(Own<ConveyorNode> &&node_p) conveyor_sink::conveyor_sink(own<conveyor_node> &&node_p)
: node{std::move(node_p)} {} : node_{std::move(node_p)} {}
void EventLoop::setRunnable(bool runnable) { is_runnable = runnable; } void event_loop::set_runnable(bool runnable) { is_runnable_ = runnable; }
EventLoop::EventLoop() {} event_loop::event_loop() {}
EventLoop::EventLoop(Own<EventPort> &&event_port) event_loop::event_loop(own<class event_port> &&ep)
: event_port{std::move(event_port)} {} : event_port_{std::move(ep)} {}
EventLoop::~EventLoop() { assert(local_loop != this); } event_loop::~event_loop() { assert(local_loop != this); }
void EventLoop::enterScope() { void event_loop::enter_scope() {
assert(!local_loop); assert(!local_loop);
local_loop = this; local_loop = this;
} }
void EventLoop::leaveScope() { void event_loop::leave_scope() {
assert(local_loop == this); assert(local_loop == this);
local_loop = nullptr; local_loop = nullptr;
} }
bool EventLoop::turnLoop() { bool event_loop::turn_loop() {
size_t turn_step = 0; size_t turn_step = 0;
while (head && turn_step < 65536) { while (head_ && turn_step < 65536) {
if (!turn()) { if (!turn()) {
return false; return false;
} }
@ -229,187 +229,191 @@ bool EventLoop::turnLoop() {
return true; return true;
} }
bool EventLoop::turn() { bool event_loop::turn() {
Event *event = head; event *event = head_;
if (!event) { if (!event) {
return false; return false;
} }
head = event->next; head_ = event->next_;
if (head) { if (head_) {
head->prev = &head; head_->prev_ = &head_;
} }
next_insert_point = &head; next_insert_point_ = &head_;
if (later_insert_point == &event->next) { if (later_insert_point_ == &event->next_) {
later_insert_point = &head; later_insert_point_ = &head_;
} }
if (tail == &event->next) { if (tail_ == &event->next_) {
tail = &head; tail_ = &head_;
} }
event->next = nullptr; event->next_ = nullptr;
event->prev = nullptr; event->prev_ = nullptr;
next_insert_point = &head; next_insert_point_ = &head_;
event->fire(); event->fire();
return true; return true;
} }
bool EventLoop::wait(const std::chrono::steady_clock::duration &duration) { bool event_loop::wait(const std::chrono::steady_clock::duration &duration) {
if (event_port) { if (event_port_) {
event_port->wait(duration); event_port_->wait(duration);
} }
return turnLoop(); return turn_loop();
} }
bool EventLoop::wait(const std::chrono::steady_clock::time_point &time_point) { bool event_loop::wait(const std::chrono::steady_clock::time_point &time_point) {
if (event_port) { if (event_port_) {
event_port->wait(time_point); event_port_->wait(time_point);
} }
return turnLoop(); return turn_loop();
} }
bool EventLoop::wait() { bool event_loop::wait() {
if (event_port) { if (event_port_) {
event_port->wait(); event_port_->wait();
} }
return turnLoop(); return turn_loop();
} }
bool EventLoop::poll() { bool event_loop::poll() {
if (event_port) { if (event_port_) {
event_port->poll(); event_port_->poll();
} }
return turnLoop(); return turn_loop();
} }
EventPort *EventLoop::eventPort() { return event_port.get(); } event_port *event_loop::event_port() { return event_port_.get(); }
ConveyorSinkSet &EventLoop::daemon() { conveyor_sink_set &event_loop::daemon() {
if (!daemon_sink) { if (!daemon_sink_) {
daemon_sink = heap<ConveyorSinkSet>(); daemon_sink_ = heap<conveyor_sink_set>();
} }
return *daemon_sink; return *daemon_sink_;
} }
WaitScope::WaitScope(EventLoop &loop) : loop{loop} { loop.enterScope(); } wait_scope::wait_scope(event_loop &loop) : loop_{loop} { loop_.enter_scope(); }
WaitScope::~WaitScope() { loop.leaveScope(); } wait_scope::~wait_scope() { loop_.leave_scope(); }
void WaitScope::wait() { loop.wait(); } void wait_scope::wait() { loop_.wait(); }
void WaitScope::wait(const std::chrono::steady_clock::duration &duration) { void wait_scope::wait(const std::chrono::steady_clock::duration &duration) {
loop.wait(duration); loop_.wait(duration);
} }
void WaitScope::wait(const std::chrono::steady_clock::time_point &time_point) { void wait_scope::wait(const std::chrono::steady_clock::time_point &time_point) {
loop.wait(time_point); loop_.wait(time_point);
} }
void WaitScope::poll() { loop.poll(); } void wait_scope::poll() { loop_.poll(); }
ErrorOr<Own<ConveyorNode>> error_or<own<conveyor_node>>
ConvertConveyorNodeBase::swapChild(Own<ConveyorNode> &&swapee) noexcept { convert_conveyor_node_base::swap_child(own<conveyor_node> &&swapee) noexcept {
return child_mixin.swapChild(std::move(swapee)); return child_mixin_.swap_child(std::move(swapee));
} }
ConveyorStorage *ConvertConveyorNodeBase::nextStorage() noexcept { conveyor_storage *convert_conveyor_node_base::next_storage() noexcept {
if (!child_mixin.child) { if (!child_mixin_.child) {
return nullptr; return nullptr;
} }
return child_mixin.child->nextStorage(); return child_mixin_.child->next_storage();
} }
ImmediateConveyorNodeBase::ImmediateConveyorNodeBase() immediate_conveyor_node_base::immediate_conveyor_node_base()
: ConveyorEventStorage{} {} : conveyor_event_storage{} {}
MergeConveyorNodeBase::MergeConveyorNodeBase() : ConveyorEventStorage{} {} merge_conveyor_node_base::merge_conveyor_node_base()
: conveyor_event_storage{} {}
ErrorOr<Own<ConveyorNode>> error_or<own<conveyor_node>> queue_buffer_conveyor_node_base::swap_child(
QueueBufferConveyorNodeBase::swapChild(Own<ConveyorNode> &&swapee_) noexcept { own<conveyor_node> &&swapee_) noexcept {
return child_mixin.swapChild(std::move(swapee_)); return child_mixin_.swap_child(std::move(swapee_));
} }
void ConveyorSinkSet::destroySinkConveyorNode(ConveyorNode &node) { void conveyor_sink_set::destroy_sink_conveyor_node(conveyor_node &node) {
if (!isArmed()) { if (!is_armed()) {
armLast(); arm_last();
} }
delete_nodes.push(&node); delete_nodes_.push(&node);
} }
void ConveyorSinkSet::fail(Error &&error) { void conveyor_sink_set::fail(error &&error) {
/// @todo call error_handler /// @todo call error_handler
} }
ConveyorSinkSet::ConveyorSinkSet(EventLoop &event_loop) : Event{event_loop} {} conveyor_sink_set::conveyor_sink_set(event_loop &event_loop)
: event{event_loop} {}
void ConveyorSinkSet::add(Conveyor<void> &&sink) { void conveyor_sink_set::add(conveyor<void> &&sink) {
auto nas = Conveyor<void>::fromConveyor(std::move(sink)); auto nas = conveyor<void>::from_conveyor(std::move(sink));
SAW_ASSERT(nas) { return; } SAW_ASSERT(nas) { return; }
ConveyorStorage *storage = nas->nextStorage(); conveyor_storage *storage = nas->next_storage();
Own<SinkConveyorNode> sink_node = nullptr; own<sink_conveyor_node> sink_node = nullptr;
try { try {
sink_node = heap<SinkConveyorNode>(std::move(nas), *this); sink_node = heap<sink_conveyor_node>(std::move(nas), *this);
} catch (std::bad_alloc &) { } catch (std::bad_alloc &) {
return; return;
} }
if (storage) { if (storage) {
storage->setParent(sink_node.get()); storage->set_parent(sink_node.get());
} }
sink_nodes.emplace_back(std::move(sink_node)); sink_nodes_.emplace_back(std::move(sink_node));
} }
void ConveyorSinkSet::fire() { void conveyor_sink_set::fire() {
while (!delete_nodes.empty()) { while (!delete_nodes_.empty()) {
ConveyorNode *node = delete_nodes.front(); conveyor_node *node = delete_nodes_.front();
/*auto erased = */ std::remove_if(sink_nodes.begin(), sink_nodes.end(), /*auto erased = */ std::remove_if(sink_nodes_.begin(),
[node](Own<ConveyorNode> &element) { sink_nodes_.end(),
[node](own<conveyor_node> &element) {
return node == element.get(); return node == element.get();
}); });
delete_nodes.pop(); delete_nodes_.pop();
} }
} }
ConvertConveyorNodeBase::ConvertConveyorNodeBase(Own<ConveyorNode> &&dep) convert_conveyor_node_base::convert_conveyor_node_base(own<conveyor_node> &&dep)
: child_mixin{std::move(dep), *this} {} : child_mixin_{std::move(dep), *this} {}
void ConvertConveyorNodeBase::getResult(ErrorOrValue &err_or_val) { void convert_conveyor_node_base::get_result(error_or_value &err_or_val) {
getImpl(err_or_val); get_impl(err_or_val);
} }
void AttachConveyorNodeBase::getResult(ErrorOrValue &err_or_val) noexcept { void attach_conveyor_node_base::get_result(
if (child_mixin.child) { error_or_value &err_or_val) noexcept {
child_mixin.child->getResult(err_or_val); if (child_mixin_.child) {
child_mixin_.child->get_result(err_or_val);
} }
} }
ErrorOr<Own<ConveyorNode>> error_or<own<conveyor_node>>
AttachConveyorNodeBase::swapChild(Own<ConveyorNode> &&swapee_) noexcept { attach_conveyor_node_base::swap_child(own<conveyor_node> &&swapee_) noexcept {
return child_mixin.swapChild(std::move(swapee_)); return child_mixin_.swap_child(std::move(swapee_));
} }
ConveyorStorage *AttachConveyorNodeBase::nextStorage() noexcept { conveyor_storage *attach_conveyor_node_base::next_storage() noexcept {
if (!child_mixin.child) { if (!child_mixin_.child) {
return nullptr; return nullptr;
} }
return child_mixin.child->nextStorage(); return child_mixin_.child->next_storage();
} }
void detachConveyor(Conveyor<void> &&conveyor) { void detach_conveyor(conveyor<void> &&conveyor) {
EventLoop &loop = currentEventLoop(); event_loop &loop = current_event_loop();
ConveyorSinkSet &sink = loop.daemon(); conveyor_sink_set &sink = loop.daemon();
sink.add(std::move(conveyor)); sink.add(std::move(conveyor));
} }
} // namespace saw } // namespace saw

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,225 +7,225 @@
#include <sstream> #include <sstream>
namespace saw { namespace saw {
Error Buffer::push(const uint8_t &value) { error buffer::push(const uint8_t &value) {
size_t write_remain = writeCompositeLength(); size_t write_remain = write_composite_length();
if (write_remain > 0) { if (write_remain > 0) {
write() = value; write() = value;
writeAdvance(1); write_advance(1);
} else { } 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 buffer::push(const uint8_t &buffer, size_t size) {
Error error = writeRequireLength(size); error error = write_require_length(size);
if (error.failed()) { if (error.failed()) {
return error; return error;
} }
const uint8_t *buffer_ptr = &buffer; const uint8_t *buffer_ptr = &buffer;
while (size > 0) { while (size > 0) {
size_t segment = std::min(writeSegmentLength(), size); size_t segment = std::min(write_segment_length(), size);
memcpy(&write(), buffer_ptr, segment); memcpy(&write(), buffer_ptr, segment);
writeAdvance(segment); write_advance(segment);
size -= segment; size -= segment;
buffer_ptr += segment; buffer_ptr += segment;
} }
return noError(); return no_error();
} }
Error Buffer::pop(uint8_t &value) { error buffer::pop(uint8_t &value) {
if (readCompositeLength() > 0) { if (read_composite_length() > 0) {
value = read(); value = read();
readAdvance(1); read_advance(1);
} else { } 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) { error buffer::pop(uint8_t &buffer, size_t size) {
if (readCompositeLength() >= size) { if (read_composite_length() >= size) {
uint8_t *buffer_ptr = &buffer; uint8_t *buffer_ptr = &buffer;
while (size > 0) { while (size > 0) {
size_t segment = std::min(readSegmentLength(), size); size_t segment = std::min(read_segment_length(), size);
memcpy(buffer_ptr, &read(), segment); memcpy(buffer_ptr, &read(), segment);
readAdvance(segment); read_advance(segment);
size -= segment; size -= segment;
buffer_ptr += segment; buffer_ptr += segment;
} }
} else { } 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; std::ostringstream oss;
for (size_t i = 0; i < readCompositeLength(); ++i) { for (size_t i = 0; i < read_composite_length(); ++i) {
oss << read(i); oss << read(i);
} }
return oss.str(); return oss.str();
} }
std::string Buffer::toHex() const { std::string buffer::to_hex() const {
std::ostringstream oss; std::ostringstream oss;
oss << std::hex << std::setfill('0'); 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); oss << std::setw(2) << (uint16_t)read(i);
if ((i + 1) < readCompositeLength()) { if ((i + 1) < read_composite_length()) {
oss << ((i % 4 == 3) ? '\n' : ' '); oss << ((i % 4 == 3) ? '\n' : ' ');
} }
} }
return oss.str(); return oss.str();
} }
BufferView::BufferView(Buffer &buffer) buffer_view::buffer_view(buffer &buffer)
: buffer{buffer}, read_offset{0}, write_offset{0} {} : buffer_{buffer}, read_offset_{0}, write_offset_{0} {}
size_t BufferView::readPosition() const { size_t buffer_view::read_position() const {
return read_offset + buffer.readPosition(); return read_offset_ + buffer_.read_position();
} }
size_t BufferView::readCompositeLength() const { size_t buffer_view::read_composite_length() const {
assert(read_offset <= buffer.readCompositeLength()); assert(read_offset_ <= buffer_.read_composite_length());
if (read_offset > buffer.readCompositeLength()) { if (read_offset_ > buffer_.read_composite_length()) {
return 0; return 0;
} }
return buffer.readCompositeLength() - read_offset; return buffer_.read_composite_length() - read_offset_;
} }
size_t BufferView::readSegmentLength(size_t offset) const { size_t buffer_view::read_segment_length(size_t offset) const {
size_t off = offset + read_offset; size_t off = offset + read_offset_;
assert(off <= buffer.readCompositeLength()); assert(off <= buffer_.read_composite_length());
if (off > buffer.readCompositeLength()) { if (off > buffer_.read_composite_length()) {
return 0; return 0;
} }
return buffer.readSegmentLength(off); return buffer_.read_segment_length(off);
} }
void BufferView::readAdvance(size_t bytes) { void buffer_view::read_advance(size_t bytes) {
size_t offset = bytes + read_offset; size_t offset = bytes + read_offset_;
assert(offset <= buffer.readCompositeLength()); assert(offset <= buffer_.read_composite_length());
if (offset > buffer.readCompositeLength()) { if (offset > buffer_.read_composite_length()) {
read_offset += buffer.readCompositeLength(); read_offset_ += buffer_.read_composite_length();
return; return;
} }
read_offset += bytes; read_offset_ += bytes;
} }
uint8_t &BufferView::read(size_t i) { uint8_t &buffer_view::read(size_t i) {
size_t pos = i + read_offset; size_t pos = i + read_offset_;
assert(pos < buffer.readCompositeLength()); assert(pos < buffer_.read_composite_length());
return buffer.read(pos); return buffer_.read(pos);
} }
const uint8_t &BufferView::read(size_t i) const { const uint8_t &buffer_view::read(size_t i) const {
size_t pos = i + read_offset; size_t pos = i + read_offset_;
assert(pos < buffer.readCompositeLength()); assert(pos < buffer_.read_composite_length());
return buffer.read(pos); return buffer_.read(pos);
} }
size_t BufferView::writePosition() const { size_t buffer_view::write_position() const {
return write_offset + buffer.writePosition(); return write_offset_ + buffer_.write_position();
} }
size_t BufferView::writeCompositeLength() const { size_t buffer_view::write_composite_length() const {
assert(write_offset <= buffer.writeCompositeLength()); assert(write_offset_ <= buffer_.write_composite_length());
if (write_offset > buffer.writeCompositeLength()) { if (write_offset_ > buffer_.write_composite_length()) {
return 0; 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; size_t off = offset + write_offset_;
assert(off <= buffer.writeCompositeLength()); assert(off <= buffer_.write_composite_length());
if (off > buffer.writeCompositeLength()) { if (off > buffer_.write_composite_length()) {
return 0; 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; size_t offset = bytes + write_offset_;
assert(offset <= buffer.writeCompositeLength()); assert(offset <= buffer_.write_composite_length());
if (offset > buffer.writeCompositeLength()) { if (offset > buffer_.write_composite_length()) {
write_offset += buffer.writeCompositeLength(); write_offset_ += buffer_.write_composite_length();
return; return;
} }
write_offset += bytes; write_offset_ += bytes;
} }
uint8_t &BufferView::write(size_t i) { uint8_t &buffer_view::write(size_t i) {
size_t pos = i + write_offset; size_t pos = i + write_offset_;
assert(pos < buffer.writeCompositeLength()); assert(pos < buffer_.write_composite_length());
return buffer.write(pos); 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; size_t pos = i + write_offset_;
assert(pos < buffer.writeCompositeLength()); assert(pos < buffer_.write_composite_length());
return buffer.write(pos); return buffer_.write(pos);
} }
Error BufferView::writeRequireLength(size_t bytes) { error buffer_view::write_require_length(size_t bytes) {
return buffer.writeRequireLength(bytes + write_offset); 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} { ring_buffer::ring_buffer() : read_position_{0}, write_position_{0} {
buffer.resize(RING_BUFFER_MAX_SIZE); buffer_.resize(RING_BUFFER_MAX_SIZE);
} }
RingBuffer::RingBuffer(size_t size) : read_position{0}, write_position{0} { ring_buffer::ring_buffer(size_t size) : read_position_{0}, write_position_{0} {
buffer.resize(size); buffer_.resize(size);
} }
size_t RingBuffer::readPosition() const { return read_position; } size_t ring_buffer::read_position() const { return read_position_; }
/* /*
* If write is ahead of read it is a simple distance, but if read ist ahead of * If write is ahead of read it is a simple distance, but if read ist ahead of
* write then there are two segments * write then there are two segments
* *
*/ */
size_t RingBuffer::readCompositeLength() const { size_t ring_buffer::read_composite_length() const {
return writePosition() < readPosition() return write_position() < read_position()
? buffer.size() - (readPosition() - writePosition()) ? buffer_.size() - (read_position() - write_position())
: (write_reached_read ? buffer.size() : (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 * If write is ahead then it's the simple distance again. If read is ahead it's
* until the end of the buffer/segment * until the end of the buffer/segment
*/ */
size_t RingBuffer::readSegmentLength(size_t offset) const { size_t ring_buffer::read_segment_length(size_t offset) const {
size_t read_composite = readCompositeLength(); size_t read_composite = read_composite_length();
assert(offset <= read_composite); assert(offset <= read_composite);
offset = std::min(offset, read_composite); offset = std::min(offset, read_composite);
size_t remaining = read_composite - offset; 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 = read_offset >= buffer_.size() ? read_offset - buffer_.size()
: read_offset; : read_offset;
// case 1 write is located before read and reached read // case 1 write is located before read and reached read
// then offset can be used normally // then offset can be used normally
@ -233,98 +233,99 @@ size_t RingBuffer::readSegmentLength(size_t offset) const {
// then it is set to zero by readCompositeLength() // then it is set to zero by readCompositeLength()
// case 3 write is located after read // case 3 write is located after read
// since std::min you can use simple subtraction // since std::min you can use simple subtraction
if (writePosition() < read_offset) { if (write_position() < read_offset) {
return buffer.size() - read_offset; return buffer_.size() - read_offset;
} }
if (writePosition() == read_offset) { if (write_position() == read_offset) {
if (remaining > 0) { if (remaining > 0) {
return buffer.size() - read_offset; return buffer_.size() - read_offset;
} else { } else {
return 0; return 0;
} }
} }
return writePosition() - read_offset; return write_position() - read_offset;
} }
void RingBuffer::readAdvance(size_t bytes) { void ring_buffer::read_advance(size_t bytes) {
size_t read_composite = readCompositeLength(); size_t read_composite = read_composite_length();
assert(bytes <= read_composite); assert(bytes <= read_composite);
bytes = std::min(bytes, read_composite); bytes = std::min(bytes, read_composite);
size_t advanced = read_position + bytes; size_t advanced = read_position_ + bytes;
read_position = advanced >= buffer.size() ? advanced - buffer.size() read_position_ = advanced >= buffer_.size() ? advanced - buffer_.size()
: advanced; : advanced;
write_reached_read = bytes > 0 ? false : write_reached_read; write_reached_read_ = bytes > 0 ? false : write_reached_read_;
} }
uint8_t &RingBuffer::read(size_t i) { uint8_t &ring_buffer::read(size_t i) {
assert(i < readCompositeLength()); assert(i < read_composite_length());
size_t pos = read_position + i; size_t pos = read_position_ + i;
pos = pos >= buffer.size() ? pos - buffer.size() : pos; pos = pos >= buffer_.size() ? pos - buffer_.size() : pos;
return buffer[pos]; return buffer_[pos];
} }
const uint8_t &RingBuffer::read(size_t i) const { const uint8_t &ring_buffer::read(size_t i) const {
assert(i < readCompositeLength()); assert(i < read_composite_length());
size_t pos = read_position + i; size_t pos = read_position_ + i;
pos = pos >= buffer.size() ? pos - buffer.size() : pos; pos = pos >= buffer_.size() ? pos - buffer_.size() : pos;
return buffer[pos]; return buffer_[pos];
} }
size_t RingBuffer::writePosition() const { return write_position; } size_t ring_buffer::write_position() const { return write_position_; }
size_t RingBuffer::writeCompositeLength() const { size_t ring_buffer::write_composite_length() const {
return readPosition() > writePosition() return read_position() > write_position()
? (readPosition() - writePosition()) ? (read_position() - write_position())
: (write_reached_read : (write_reached_read_
? 0 ? 0
: buffer.size() - (writePosition() - readPosition())); : buffer_.size() - (write_position() - read_position()));
} }
size_t RingBuffer::writeSegmentLength(size_t offset) const { size_t ring_buffer::write_segment_length(size_t offset) const {
size_t write_composite = writeCompositeLength(); size_t write_composite = write_composite_length();
assert(offset <= write_composite); assert(offset <= write_composite);
offset = std::min(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 = write_offset >= buffer_.size()
: write_offset; ? write_offset - buffer_.size()
: write_offset;
if (read_position > write_offset) { if (read_position_ > write_offset) {
return read_position - write_offset; return read_position_ - write_offset;
} }
if (write_reached_read) { if (write_reached_read_) {
return 0; return 0;
} }
return buffer.size() - write_offset; return buffer_.size() - write_offset;
} }
void RingBuffer::writeAdvance(size_t bytes) { void ring_buffer::write_advance(size_t bytes) {
assert(bytes <= writeCompositeLength()); assert(bytes <= write_composite_length());
size_t advanced = write_position + bytes; size_t advanced = write_position_ + bytes;
write_position = advanced >= buffer.size() ? advanced - buffer.size() write_position_ = advanced >= buffer_.size() ? advanced - buffer_.size()
: advanced; : advanced;
write_reached_read = 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) { uint8_t &ring_buffer::write(size_t i) {
assert(i < writeCompositeLength()); assert(i < write_composite_length());
size_t pos = write_position + i; size_t pos = write_position_ + i;
pos = pos >= buffer.size() ? pos - buffer.size() : pos; pos = pos >= buffer_.size() ? pos - buffer_.size() : pos;
return buffer[pos]; return buffer_[pos];
} }
const uint8_t &RingBuffer::write(size_t i) const { const uint8_t &ring_buffer::write(size_t i) const {
assert(i < writeCompositeLength()); assert(i < write_composite_length());
size_t pos = write_position + i; size_t pos = write_position_ + i;
pos = pos >= buffer.size() ? pos - buffer.size() : pos; pos = pos >= buffer_.size() ? pos - buffer_.size() : pos;
return buffer[pos]; return buffer_[pos];
} }
/* /*
Error RingBuffer::increaseSize(size_t size){ Error RingBuffer::increaseSize(size_t size){
@ -344,89 +345,90 @@ const uint8_t &RingBuffer::write(size_t i) const {
return noError(); return noError();
} }
*/ */
Error RingBuffer::writeRequireLength(size_t bytes) { error ring_buffer::write_require_length(size_t bytes) {
size_t write_remain = writeCompositeLength(); size_t write_remain = write_composite_length();
if (bytes > write_remain) { 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)
buffer.resize(size); : read_position_{0}, 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 { size_t array_buffer::read_composite_length() const {
return write_position - read_position; return write_position_ - read_position_;
} }
size_t ArrayBuffer::readSegmentLength(size_t offset) const { size_t array_buffer::read_segment_length(size_t offset) const {
size_t read_composite = readCompositeLength(); size_t read_composite = read_composite_length();
assert(offset <= read_composite); assert(offset <= read_composite);
offset = std::min(read_composite, offset); 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) { void array_buffer::read_advance(size_t bytes) {
assert(bytes <= readCompositeLength()); assert(bytes <= read_composite_length());
read_position += bytes; read_position_ += bytes;
} }
uint8_t &ArrayBuffer::read(size_t i) { uint8_t &array_buffer::read(size_t i) {
assert(i < readCompositeLength()); assert(i < read_composite_length());
return buffer[i + read_position]; return buffer_[i + read_position_];
} }
const uint8_t &ArrayBuffer::read(size_t i) const { const uint8_t &array_buffer::read(size_t i) const {
assert(i + read_position < buffer.size()); 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 write_position_; }
size_t ArrayBuffer::writeCompositeLength() const { size_t array_buffer::write_composite_length() const {
assert(write_position <= buffer.size()); assert(write_position_ <= buffer_.size());
return buffer.size() - write_position; return buffer_.size() - write_position_;
} }
size_t ArrayBuffer::writeSegmentLength(size_t offset) const { size_t array_buffer::write_segment_length(size_t offset) const {
assert(write_position <= buffer.size()); assert(write_position_ <= buffer_.size());
size_t write_composite = writeCompositeLength(); size_t write_composite = write_composite_length();
assert(offset <= write_composite); assert(offset <= write_composite);
offset = std::min(write_composite, offset); 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; return buffer_.size() - write_offset;
} }
void ArrayBuffer::writeAdvance(size_t bytes) { void array_buffer::write_advance(size_t bytes) {
assert(bytes <= writeCompositeLength()); assert(bytes <= write_composite_length());
write_position += bytes; write_position_ += bytes;
} }
uint8_t &ArrayBuffer::write(size_t i) { uint8_t &array_buffer::write(size_t i) {
assert(i < writeCompositeLength()); assert(i < write_composite_length());
return buffer[i + write_position]; return buffer_[i + write_position_];
} }
const uint8_t &ArrayBuffer::write(size_t i) const { const uint8_t &array_buffer::write(size_t i) const {
assert(i < writeCompositeLength()); assert(i < write_composite_length());
return buffer[i + write_position]; return buffer_[i + write_position_];
} }
Error ArrayBuffer::writeRequireLength(size_t bytes) { error array_buffer::write_require_length(size_t bytes) {
size_t write_remain = writeCompositeLength(); size_t write_remain = write_composite_length();
if (bytes > write_remain) { if (bytes > write_remain) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
return noError(); return no_error();
} }
} // namespace saw } // namespace saw

View File

@ -13,23 +13,23 @@ namespace saw {
/* /*
* Access class to reduce templated BufferSegments bloat * Access class to reduce templated BufferSegments bloat
*/ */
class Buffer { class buffer {
protected: protected:
~Buffer() = default; ~buffer() = default;
public: public:
virtual size_t readPosition() const = 0; virtual size_t read_position() const = 0;
virtual size_t readCompositeLength() const = 0; virtual size_t read_composite_length() const = 0;
virtual size_t readSegmentLength(size_t offset = 0) const = 0; virtual size_t read_segment_length(size_t offset = 0) const = 0;
virtual void readAdvance(size_t bytes) = 0; virtual void read_advance(size_t bytes) = 0;
virtual uint8_t &read(size_t i = 0) = 0; virtual uint8_t &read(size_t i = 0) = 0;
virtual const uint8_t &read(size_t i = 0) const = 0; virtual const uint8_t &read(size_t i = 0) const = 0;
virtual size_t writePosition() const = 0; virtual size_t write_position() const = 0;
virtual size_t writeCompositeLength() const = 0; virtual size_t write_composite_length() const = 0;
virtual size_t writeSegmentLength(size_t offset = 0) const = 0; virtual size_t write_segment_length(size_t offset = 0) const = 0;
virtual void writeAdvance(size_t bytes) = 0; virtual void write_advance(size_t bytes) = 0;
virtual uint8_t &write(size_t i = 0) = 0; virtual uint8_t &write(size_t i = 0) = 0;
virtual const uint8_t &write(size_t i = 0) const = 0; virtual const uint8_t &write(size_t i = 0) const = 0;
@ -40,50 +40,53 @@ public:
* There is nothing you can do if read hasn't been filled, but at * There is nothing you can do if read hasn't been filled, but at
* least write can be increased if it is demanded. * 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 &value);
Error push(const uint8_t &buffer, size_t size); error push(const uint8_t &buffer, size_t size);
Error pop(uint8_t &value); error pop(uint8_t &value);
Error pop(uint8_t &buffer, size_t size); error pop(uint8_t &buffer, size_t size);
std::string toString() const; /*
std::string toHex() const; * Subject to change
*/
std::string to_string() const;
std::string to_hex() const;
}; };
/* /*
* A viewer class for buffers. * A viewer class for buffers.
* Working on the reference buffer invalidates the buffer view * Working on the reference buffer invalidates the buffer view
*/ */
class BufferView : public Buffer { class buffer_view : public buffer {
private: private:
Buffer &buffer; buffer &buffer_;
size_t read_offset; size_t read_offset_;
size_t write_offset; size_t write_offset_;
public: public:
BufferView(Buffer &); buffer_view(buffer &);
size_t readPosition() const override; size_t read_position() const override;
size_t readCompositeLength() const override; size_t read_composite_length() const override;
size_t readSegmentLength(size_t offset = 0) const override; size_t read_segment_length(size_t offset = 0) const override;
void readAdvance(size_t bytes) override; void read_advance(size_t bytes) override;
uint8_t &read(size_t i = 0) override; uint8_t &read(size_t i = 0) override;
const uint8_t &read(size_t i = 0) const override; const uint8_t &read(size_t i = 0) const override;
size_t writePosition() const override; size_t write_position() const override;
size_t writeCompositeLength() const override; size_t write_composite_length() const override;
size_t writeSegmentLength(size_t offset = 0) const override; size_t write_segment_length(size_t offset = 0) const override;
void writeAdvance(size_t bytes) override; void write_advance(size_t bytes) override;
uint8_t &write(size_t i = 0) override; uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const 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 read_offset() const;
size_t writeOffset() const; size_t write_offset() const;
}; };
/* /*
@ -94,99 +97,99 @@ constexpr size_t RING_BUFFER_MAX_SIZE = 4096;
/* /*
* Buffer wrapping around if read caught up * Buffer wrapping around if read caught up
*/ */
class RingBuffer final : public Buffer { class ring_buffer final : public buffer {
private: private:
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer_;
size_t read_position; size_t read_position_;
size_t write_position; size_t write_position_;
bool write_reached_read = false; bool write_reached_read_ = false;
public: public:
RingBuffer(); ring_buffer();
RingBuffer(size_t size); ring_buffer(size_t size);
inline size_t size() const { return buffer.size(); } inline size_t size() const { return buffer_.size(); }
inline uint8_t &operator[](size_t i) { return buffer[i]; } inline uint8_t &operator[](size_t i) { return buffer_[i]; }
inline const uint8_t &operator[](size_t i) const { return buffer[i]; } inline const uint8_t &operator[](size_t i) const { return buffer_[i]; }
size_t readPosition() const override; size_t read_position() const override;
size_t readCompositeLength() const override; size_t read_composite_length() const override;
size_t readSegmentLength(size_t offset = 0) const override; size_t read_segment_length(size_t offset = 0) const override;
void readAdvance(size_t bytes) override; void read_advance(size_t bytes) override;
uint8_t &read(size_t i = 0) override; uint8_t &read(size_t i = 0) override;
const uint8_t &read(size_t i = 0) const override; const uint8_t &read(size_t i = 0) const override;
size_t writePosition() const override; size_t write_position() const override;
size_t writeCompositeLength() const override; size_t write_composite_length() const override;
size_t writeSegmentLength(size_t offset = 0) const override; size_t write_segment_length(size_t offset = 0) const override;
void writeAdvance(size_t bytes) override; void write_advance(size_t bytes) override;
uint8_t &write(size_t i = 0) override; uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const 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 * One time buffer
*/ */
class ArrayBuffer : public Buffer { class array_buffer : public buffer {
private: private:
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer_;
size_t read_position; size_t read_position_;
size_t write_position; size_t write_position_;
public: public:
ArrayBuffer(size_t size); array_buffer(size_t size);
size_t readPosition() const override; size_t read_position() const override;
size_t readCompositeLength() const override; size_t read_composite_length() const override;
size_t readSegmentLength(size_t offset = 0) const override; size_t read_segment_length(size_t offset = 0) const override;
void readAdvance(size_t bytes) override; void read_advance(size_t bytes) override;
uint8_t &read(size_t i = 0) override; uint8_t &read(size_t i = 0) override;
const uint8_t &read(size_t i = 0) const override; const uint8_t &read(size_t i = 0) const override;
size_t writePosition() const override; size_t write_position() const override;
size_t writeCompositeLength() const override; size_t write_composite_length() const override;
size_t writeSegmentLength(size_t offset = 0) const override; size_t write_segment_length(size_t offset = 0) const override;
void writeAdvance(size_t bytes) override; void write_advance(size_t bytes) override;
uint8_t &write(size_t i = 0) override; uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const 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: private:
std::deque<ArrayBuffer> buffer; std::deque<array_buffer> buffer_;
size_t read_position; size_t read_position_;
size_t write_position; size_t write_position_;
public: public:
ChainArrayBuffer(); chain_array_buffer();
size_t readPosition() const override; size_t read_position() const override;
size_t readCompositeLength() const override; size_t read_composite_length() const override;
size_t readSegmentLength(size_t offset = 0) const override; size_t read_segment_length(size_t offset = 0) const override;
void readAdvance(size_t bytes) override; void read_advance(size_t bytes) override;
uint8_t &read(size_t i = 0) override; uint8_t &read(size_t i = 0) override;
const uint8_t &read(size_t i = 0) const override; const uint8_t &read(size_t i = 0) const override;
size_t writePosition() const override; size_t write_position() const override;
size_t writeCompositeLength() const override; size_t write_composite_length() const override;
size_t writeSegmentLength(size_t offset = 0) const override; size_t write_segment_length(size_t offset = 0) const override;
void writeAdvance(size_t bytes) override; void write_advance(size_t bytes) override;
uint8_t &write(size_t i = 0) override; uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const 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 } // namespace saw

View File

@ -32,43 +32,43 @@ namespace saw {
assert(expression); \ assert(expression); \
if (!(expression)) [[unlikely]] if (!(expression)) [[unlikely]]
template <typename T> using Maybe = std::optional<T>; template <typename T> using maybe = std::optional<T>;
template <typename T> using Own = std::unique_ptr<T>; template <typename T> using own = std::unique_ptr<T>;
template <typename T> using Our = std::shared_ptr<T>; template <typename T> using our = std::shared_ptr<T>;
template <typename T> using Lent = std::weak_ptr<T>; template <typename T> using lent = std::weak_ptr<T>;
template <typename T, class... Args> Own<T> heap(Args &&...args) { template <typename T, class... Args> own<T> heap(Args &&...args) {
return Own<T>(new T(std::forward<Args>(args)...)); return own<T>(new T(std::forward<Args>(args)...));
} }
template <typename T, class... Args> Our<T> share(Args &&...args) { template <typename T, class... Args> our<T> share(Args &&...args) {
return std::make_shared<T>(std::forward<Args>(args)...); return std::make_shared<T>(std::forward<Args>(args)...);
} }
template <typename T> T instance() noexcept; template <typename T> T instance() noexcept;
template <typename Func, typename T> struct ReturnTypeHelper { template <typename Func, typename T> struct return_type_helper {
typedef decltype(instance<Func>()(instance<T>())) Type; typedef decltype(instance<Func>()(instance<T>())) Type;
}; };
template <typename Func> struct ReturnTypeHelper<Func, void> { template <typename Func> struct return_type_helper<Func, void> {
typedef decltype(instance<Func>()()) Type; typedef decltype(instance<Func>()()) Type;
}; };
template <typename Func, typename T> template <typename Func, typename T>
using ReturnType = typename ReturnTypeHelper<Func, T>::Type; using return_type = typename return_type_helper<Func, T>::Type;
struct Void {}; struct void_t {};
template <typename T> struct VoidFix { typedef T Type; }; template <typename T> struct void_fix { typedef T Type; };
template <> struct VoidFix<void> { typedef Void Type; }; template <> struct void_fix<void> { typedef void_t Type; };
template <typename T> using FixVoid = typename VoidFix<T>::Type; template <typename T> using fix_void = typename void_fix<T>::Type;
template <typename T> struct VoidUnfix { typedef T Type; }; template <typename T> struct void_unfix { typedef T Type; };
template <> struct VoidUnfix<Void> { typedef void Type; }; template <> struct void_unfix<void_t> { typedef void Type; };
template <typename T> using UnfixVoid = typename VoidUnfix<T>::Type; template <typename T> using unfix_void = typename void_unfix<T>::Type;
template <typename... T> constexpr bool always_false = false; template <typename... T> constexpr bool always_false = false;

View File

@ -1,19 +1,19 @@
#include "error.h" #include "error.h"
namespace saw { 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::error(const std::string_view &msg, error::code code)
: error_message{msg}, error_{static_cast<Error::Code>(code)} {} : error_message_{msg}, error_{static_cast<error::code>(code)} {}
Error::Error(std::string &&msg, Error::Code code) error::error(std::string &&msg, error::code code)
: error_message{std::move(msg)}, error_{static_cast<Error::Code>(code)} {} : error_message_{std::move(msg)}, error_{static_cast<error::code>(code)} {}
Error::Error(Error &&error) error::error(error &&error)
: error_message{std::move(error.error_message)}, error_{std::move( : error_message_{std::move(error.error_message_)}, error_{std::move(
error.error_)} {} error.error_)} {}
const std::string_view Error::message() const { const std::string_view error::message() const {
return std::visit( return std::visit(
[this](auto &&arg) -> const std::string_view { [this](auto &&arg) -> const std::string_view {
@ -27,47 +27,47 @@ const std::string_view Error::message() const {
return "Error in class Error. Good luck :)"; return "Error in class Error. Good luck :)";
} }
}, },
error_message); error_message_);
} }
bool Error::failed() const { bool error::failed() const {
return static_cast<std::underlying_type_t<Error::Code>>(error_) != 0; return static_cast<std::underlying_type_t<error::code>>(error_) != 0;
} }
bool Error::isCritical() const { bool error::is_critical() const {
return static_cast<std::underlying_type_t<Error::Code>>(error_) < 0; return static_cast<std::underlying_type_t<error::code>>(error_) < 0;
} }
bool Error::isRecoverable() const { bool error::is_recoverable() const {
return static_cast<std::underlying_type_t<Error::Code>>(error_) > 0; return static_cast<std::underlying_type_t<error::code>>(error_) > 0;
} }
Error Error::copyError() const { error error::copy_error() const {
Error error; error error;
error.error_ = error_; error.error_ = error_;
try { try {
error.error_message = error_message; error.error_message_ = error_message_;
} catch (const std::bad_alloc &) { } catch (const std::bad_alloc &) {
error.error_message = error.error_message_ =
std::string_view{"Error while copying Error string. Out of memory"}; std::string_view{"Error while copying Error string. Out of memory"};
} }
return error; return error;
} }
Error::Code Error::code() const { return static_cast<Error::Code>(error_); } error::code error::id() const { return static_cast<error::code>(error_); }
Error makeError(const std::string_view &generic, Error::Code code) { error make_error(const std::string_view &generic, error::code code) {
return Error{generic, code}; return error{generic, code};
} }
Error criticalError(const std::string_view &generic, Error::Code c) { error critical_error(const std::string_view &generic, error::code c) {
return makeError(generic, c); return make_error(generic, c);
} }
Error recoverableError(const std::string_view &generic, Error::Code c) { error recoverable_error(const std::string_view &generic, error::code c) {
return makeError(generic, c); return make_error(generic, c);
} }
Error noError() { return Error{}; } error no_error() { return error{}; }
} // namespace saw } // namespace saw

View File

@ -14,9 +14,9 @@ namespace saw {
* critical and recoverable errors. Additional code ids can be provided to the * critical and recoverable errors. Additional code ids can be provided to the
* constructor if additional distinctions are necessary. * constructor if additional distinctions are necessary.
*/ */
class Error { class error {
public: public:
enum class Code : int16_t { enum class code : int16_t {
GenericCritical = -1, GenericCritical = -1,
GenericRecoverable = 1, GenericRecoverable = 1,
Disconnected = -99, Disconnected = -99,
@ -24,120 +24,126 @@ public:
}; };
private: private:
std::variant<std::string_view, std::string> error_message; std::variant<std::string_view, std::string> error_message_;
Code error_; code error_;
public: public:
Error(); error();
Error(const std::string_view &msg, Error::Code code); error(const std::string_view &msg, error::code id);
Error(std::string &&msg, Error::Code code); error(std::string &&msg, error::code id);
Error(Error &&error); 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; const std::string_view message() const;
bool failed() const; bool failed() const;
bool isCritical() const; bool is_critical() const;
bool isRecoverable() const; bool is_recoverable() const;
Error copyError() const; error copy_error() const;
Code code() const; code id() 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> template <typename Formatter>
Error makeError(const Formatter &formatter, Error::Code code, error make_error(const Formatter &formatter, error::code code,
const std::string_view &generic) { const std::string_view &generic) {
try { try {
std::string error_msg = formatter(); std::string error_msg = formatter();
return Error{std::move(error_msg), code}; return error{std::move(error_msg), code};
} catch (std::bad_alloc &) { } catch (std::bad_alloc &) {
return Error{generic, code}; return error{generic, code};
} }
} }
Error criticalError(const std::string_view &generic, error critical_error(const std::string_view &generic,
Error::Code c = Error::Code::GenericCritical); error::code c = error::code::GenericCritical);
template <typename Formatter> template <typename Formatter>
Error criticalError(const Formatter &formatter, const std::string_view &generic, error critical_error(const Formatter &formatter,
Error::Code c = Error::Code::GenericCritical) { const std::string_view &generic,
return makeError(formatter, c, generic); error::code c = error::code::GenericCritical) {
return make_error(formatter, c, generic);
} }
Error recoverableError(const std::string_view &generic, error recoverable_error(const std::string_view &generic,
Error::Code c = Error::Code::GenericRecoverable); error::code c = error::code::GenericRecoverable);
template <typename Formatter> template <typename Formatter>
Error recoverableError(const Formatter &formatter, error recoverable_error(const Formatter &formatter,
const std::string_view &generic, const std::string_view &generic,
Error::Code c = Error::Code::GenericRecoverable) { error::code c = error::code::GenericRecoverable) {
return makeError(formatter, c, generic); return make_error(formatter, c, generic);
} }
Error noError(); error no_error();
/** /**
* Exception alternative. Since I code without exceptions this class is * Exception alternative. Since I code without exceptions this class is
* essentially a kind of exception replacement. * essentially a kind of exception replacement.
*/ */
template <typename T> class ErrorOr; template <typename T> class error_or;
class ErrorOrValue { class error_or_value {
public: public:
virtual ~ErrorOrValue() = default; virtual ~error_or_value() = default;
template <typename T> ErrorOr<UnfixVoid<T>> &as() { template <typename T> error_or<unfix_void<T>> &as() {
return static_cast<ErrorOr<UnfixVoid<T>> &>(*this); return static_cast<error_or<unfix_void<T>> &>(*this);
} }
template <typename T> const ErrorOr<UnfixVoid<T>> &as() const { template <typename T> const error_or<unfix_void<T>> &as() const {
return static_cast<const ErrorOr<UnfixVoid<T>> &>(*this); return static_cast<const error_or<unfix_void<T>> &>(*this);
} }
}; };
template <typename T> class ErrorOr final : public ErrorOrValue { template <typename T> class error_or final : public error_or_value {
private: private:
std::variant<Error, FixVoid<T>> value_or_error; std::variant<error, fix_void<T>> value_or_error_;
static_assert(!std::is_same_v<T, Void>, "Don't use internal private types"); static_assert(!std::is_same_v<T, void_t>,
"Don't use internal private types");
public: public:
ErrorOr() = default; error_or() = default;
ErrorOr(const FixVoid<T> &value) : value_or_error{value} {} error_or(const fix_void<T> &value) : value_or_error_{value} {}
ErrorOr(FixVoid<T> &&value) : value_or_error{std::move(value)} {} error_or(fix_void<T> &&value) : value_or_error_{std::move(value)} {}
ErrorOr(const Error &error) : value_or_error{error} {} error_or(const error &error) : value_or_error_{error} {}
ErrorOr(Error &&error) : value_or_error{std::move(error)} {} error_or(error &&error) : value_or_error_{std::move(error)} {}
bool isValue() const { bool is_value() const {
return std::holds_alternative<FixVoid<T>>(value_or_error); return std::holds_alternative<fix_void<T>>(value_or_error_);
} }
bool isError() const { bool is_error() const {
return std::holds_alternative<Error>(value_or_error); return std::holds_alternative<class error>(value_or_error_);
} }
Error &error() { return std::get<Error>(value_or_error); } class error &error() {
return std::get<class error>(value_or_error_);
}
const Error &error() const { return std::get<Error>(value_or_error); } const class error &error() const {
return std::get<class error>(value_or_error_);
}
FixVoid<T> &value() { return std::get<FixVoid<T>>(value_or_error); } fix_void<T> &value() { return std::get<fix_void<T>>(value_or_error_); }
const FixVoid<T> &value() const { const fix_void<T> &value() const {
return std::get<FixVoid<T>>(value_or_error); return std::get<fix_void<T>>(value_or_error_);
} }
}; };
template <typename T> class ErrorOr<ErrorOr<T>> { template <typename T> class error_or<error_or<T>> {
private: private:
ErrorOr() = delete; error_or() = delete;
}; };
} // namespace saw } // namespace saw

View File

@ -4,68 +4,67 @@
namespace saw { namespace saw {
AsyncIoStream::AsyncIoStream(Own<IoStream> str) async_io_stream::async_io_stream(own<io_stream> str)
: stream{std::move(str)}, read_ready{stream->readReady() : stream_{std::move(str)},
.then([this]() { read_ready_{stream_->read_ready()
read_stepper.readStep(*stream); .then([this]() { read_stepper_.read_step(*stream_); })
})
.sink()},
write_ready{stream->writeReady()
.then([this]() { write_stepper.writeStep(*stream); })
.sink()}, .sink()},
read_disconnected{stream->onReadDisconnected() write_ready_{stream_->write_ready()
.then([this]() { .then([this]() { write_stepper_.write_step(*stream_); })
if (read_stepper.on_read_disconnect) { .sink()},
read_stepper.on_read_disconnect->feed(); read_disconnected_{stream_->on_read_disconnected()
} .then([this]() {
}) if (read_stepper_.on_read_disconnect) {
.sink()} {} read_stepper_.on_read_disconnect->feed();
}
})
.sink()} {}
void AsyncIoStream::read(void *buffer, size_t min_length, size_t max_length) { void async_io_stream::read(void *buffer, size_t min_length, size_t max_length) {
SAW_ASSERT(buffer && max_length >= min_length && min_length > 0) { return; } SAW_ASSERT(buffer && max_length >= min_length && min_length > 0) { return; }
SAW_ASSERT(!read_stepper.read_task.has_value()) { return; } SAW_ASSERT(!read_stepper_.read_task.has_value()) { return; }
read_stepper.read_task = read_stepper_.read_task = read_task_and_step_helper::read_io_task{
ReadTaskAndStepHelper::ReadIoTask{buffer, min_length, max_length, 0}; buffer, min_length, max_length, 0};
read_stepper.readStep(*stream); read_stepper_.read_step(*stream_);
} }
Conveyor<size_t> AsyncIoStream::readDone() { conveyor<size_t> async_io_stream::read_done() {
auto caf = newConveyorAndFeeder<size_t>(); auto caf = new_conveyor_and_feeder<size_t>();
read_stepper.read_done = std::move(caf.feeder); read_stepper_.read_done = std::move(caf.feeder);
return std::move(caf.conveyor); return std::move(caf.conveyor);
} }
Conveyor<void> AsyncIoStream::onReadDisconnected() { conveyor<void> async_io_stream::on_read_disconnected() {
auto caf = newConveyorAndFeeder<void>(); auto caf = new_conveyor_and_feeder<void>();
read_stepper.on_read_disconnect = std::move(caf.feeder); read_stepper_.on_read_disconnect = std::move(caf.feeder);
return std::move(caf.conveyor); return std::move(caf.conveyor);
} }
void AsyncIoStream::write(const void *buffer, size_t length) { void async_io_stream::write(const void *buffer, size_t length) {
SAW_ASSERT(buffer && length > 0) { return; } SAW_ASSERT(buffer && length > 0) { return; }
SAW_ASSERT(!write_stepper.write_task.has_value()) { return; } SAW_ASSERT(!write_stepper_.write_task.has_value()) { return; }
write_stepper.write_task = write_stepper_.write_task =
WriteTaskAndStepHelper::WriteIoTask{buffer, length, 0}; write_task_and_step_helper::write_io_task{buffer, length, 0};
write_stepper.writeStep(*stream); write_stepper_.write_step(*stream_);
} }
Conveyor<size_t> AsyncIoStream::writeDone() { conveyor<size_t> async_io_stream::write_done() {
auto caf = newConveyorAndFeeder<size_t>(); auto caf = new_conveyor_and_feeder<size_t>();
write_stepper.write_done = std::move(caf.feeder); write_stepper_.write_done = std::move(caf.feeder);
return std::move(caf.conveyor); return std::move(caf.conveyor);
} }
StringNetworkAddress::StringNetworkAddress(const std::string &address, string_network_address::string_network_address(const std::string &address,
uint16_t port) uint16_t port)
: address_value{address}, port_value{port} {} : address_value_{address}, port_value_{port} {}
const std::string &StringNetworkAddress::address() const { const std::string &string_network_address::address() const {
return address_value; return address_value_;
} }
uint16_t StringNetworkAddress::port() const { return port_value; } uint16_t string_network_address::port() const { return port_value_; }
} // namespace saw } // namespace saw

View File

@ -11,155 +11,156 @@ namespace saw {
/* /*
* Input stream * Input stream
*/ */
class InputStream { class input_stream {
public: public:
virtual ~InputStream() = default; virtual ~input_stream() = default;
virtual ErrorOr<size_t> read(void *buffer, size_t length) = 0; virtual error_or<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;
}; };
/* /*
* Output stream * Output stream
*/ */
class OutputStream { class output_stream {
public: public:
virtual ~OutputStream() = default; virtual ~output_stream() = default;
virtual ErrorOr<size_t> write(const void *buffer, size_t length) = 0; virtual error_or<size_t> write(const void *buffer, size_t length) = 0;
virtual Conveyor<void> writeReady() = 0; virtual conveyor<void> write_ready() = 0;
}; };
/* /*
* Io stream * Io stream
*/ */
class IoStream : public InputStream, public OutputStream { class io_stream : public input_stream, public output_stream {
public: public:
virtual ~IoStream() = default; virtual ~io_stream() = default;
}; };
class AsyncInputStream { class async_input_stream {
public: public:
virtual ~AsyncInputStream() = default; virtual ~async_input_stream() = default;
virtual void read(void *buffer, size_t min_length, size_t max_length) = 0; virtual void read(void *buffer, size_t min_length, size_t max_length) = 0;
virtual Conveyor<size_t> readDone() = 0; virtual conveyor<size_t> read_done() = 0;
virtual Conveyor<void> onReadDisconnected() = 0; virtual conveyor<void> on_read_disconnected() = 0;
}; };
class AsyncOutputStream { class async_output_stream {
public: public:
virtual ~AsyncOutputStream() = default; virtual ~async_output_stream() = default;
virtual void write(const void *buffer, size_t length) = 0; 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: private:
Own<IoStream> stream; own<io_stream> stream_;
ConveyorSink read_ready; conveyor_sink read_ready_;
ConveyorSink write_ready; conveyor_sink write_ready_;
ConveyorSink read_disconnected; conveyor_sink read_disconnected_;
ReadTaskAndStepHelper read_stepper; read_task_and_step_helper read_stepper_;
WriteTaskAndStepHelper write_stepper; write_task_and_step_helper write_stepper_;
public: public:
AsyncIoStream(Own<IoStream> str); async_io_stream(own<io_stream> str);
SAW_FORBID_COPY(AsyncIoStream); SAW_FORBID_COPY(async_io_stream);
SAW_FORBID_MOVE(AsyncIoStream); SAW_FORBID_MOVE(async_io_stream);
void read(void *buffer, size_t length, size_t max_length) override; 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; 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: public:
virtual ~Server() = default; virtual ~server() = default;
virtual Conveyor<Own<IoStream>> accept() = 0; virtual conveyor<own<io_stream>> accept() = 0;
}; };
class NetworkAddress; class network_address;
/** /**
* Datagram class. Bound to a local address it is able to receive inbound * Datagram class. Bound to a local address it is able to receive inbound
* datagram messages and send them as well as long as an address is provided as * datagram messages and send them as well as long as an address is provided as
* well * well
*/ */
class Datagram { class datagram {
public: public:
virtual ~Datagram() = default; virtual ~datagram() = default;
virtual ErrorOr<size_t> read(void *buffer, size_t length) = 0; virtual error_or<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, virtual error_or<size_t> write(const void *buffer, size_t length,
NetworkAddress &dest) = 0; network_address &dest) = 0;
virtual Conveyor<void> writeReady() = 0; virtual conveyor<void> write_ready() = 0;
}; };
class OsNetworkAddress; class os_network_address;
class StringNetworkAddress; class string_network_address;
class NetworkAddress { class network_address {
public: public:
using ChildVariant = using child_variant =
std::variant<OsNetworkAddress *, StringNetworkAddress *>; std::variant<os_network_address *, string_network_address *>;
virtual ~NetworkAddress() = default; virtual ~network_address() = default;
virtual NetworkAddress::ChildVariant representation() = 0; virtual network_address::child_variant representation() = 0;
virtual const std::string &address() const = 0; virtual const std::string &address() const = 0;
virtual uint16_t port() const = 0; virtual uint16_t port() const = 0;
}; };
class OsNetworkAddress : public NetworkAddress { class os_network_address : public network_address {
public: public:
virtual ~OsNetworkAddress() = default; virtual ~os_network_address() = default;
NetworkAddress::ChildVariant representation() override { return this; } network_address::child_variant representation() override { return this; }
}; };
class StringNetworkAddress final : public NetworkAddress { class string_network_address final : public network_address {
private: private:
std::string address_value; std::string address_value_;
uint16_t port_value; uint16_t port_value_;
public: public:
StringNetworkAddress(const std::string &address, uint16_t port); string_network_address(const std::string &address, uint16_t port);
const std::string &address() const override; const std::string &address() const override;
uint16_t port() const override; uint16_t port() const override;
NetworkAddress::ChildVariant representation() override { return this; } network_address::child_variant representation() override { return this; }
}; };
class Network { class network {
public: public:
virtual ~Network() = default; virtual ~network() = default;
/** /**
* Resolve the provided string and uint16 to the preferred storage method * Resolve the provided string and uint16 to the preferred storage method
*/ */
virtual Conveyor<Own<NetworkAddress>> virtual conveyor<own<network_address>>
resolveAddress(const std::string &addr, uint16_t port_hint = 0) = 0; resolve_address(const std::string &addr, uint16_t port_hint = 0) = 0;
/** /**
* Parse the provided string and uint16 to the preferred storage method * Parse the provided string and uint16 to the preferred storage method
@ -172,33 +173,33 @@ public:
/** /**
* Set up a listener on this address * Set up a listener on this address
*/ */
virtual Own<Server> listen(NetworkAddress &bind_addr) = 0; virtual own<server> listen(network_address &bind_addr) = 0;
/** /**
* Connect to a remote address * Connect to a remote address
*/ */
virtual Conveyor<Own<IoStream>> connect(NetworkAddress &address) = 0; virtual conveyor<own<io_stream>> connect(network_address &address) = 0;
/** /**
* Bind a datagram socket at this address. * Bind a datagram socket at this address.
*/ */
virtual Own<Datagram> datagram(NetworkAddress &address) = 0; virtual own<datagram> datagram(network_address &address) = 0;
}; };
class IoProvider { class io_provider {
public: public:
virtual ~IoProvider() = default; virtual ~io_provider() = default;
virtual Own<InputStream> wrapInputFd(int fd) = 0; virtual own<input_stream> wrap_input_fd(int fd) = 0;
virtual Network &network() = 0; virtual network &network() = 0;
}; };
struct AsyncIoContext { struct async_io_context {
Own<IoProvider> io; own<io_provider> io;
EventLoop &event_loop; event_loop &event_loop;
EventPort &event_port; event_port &event_port;
}; };
ErrorOr<AsyncIoContext> setupAsyncIo(); error_or<async_io_context> setup_async_io();
} // namespace saw } // namespace saw

View File

@ -1,8 +1,8 @@
#include "io_auth.h" #include "io_auth.h"
namespace saw { namespace saw {
Peer::Peer(const std::string &identity_) : identity_value{identity_} {} peer::peer(const std::string &identity_) : identity_value_{identity_} {}
Peer::Peer(std::string &&identity_) : identity_value{std::move(identity_)} {} peer::peer(std::string &&identity_) : identity_value_{std::move(identity_)} {}
const std::string &Peer::identity() const { return identity_value; } const std::string &peer::identity() const { return identity_value_; }
} // namespace saw } // namespace saw

View File

@ -3,51 +3,51 @@
#include "io.h" #include "io.h"
namespace saw { namespace saw {
class Peer { class peer {
public: public:
Peer(const std::string &ident); peer(const std::string &ident);
Peer(std::string &&ident); peer(std::string &&ident);
const std::string &identity() const; const std::string &identity() const;
private: private:
std::string identity_value; std::string identity_value_;
}; };
class AuthenticatedIoStream { class authenticated_io_stream {
public: public:
// This is the easiest way to implement Authenticated streams. // This is the easiest way to implement Authenticated streams.
// This is a simple pair of the stream and the peer. // This is a simple pair of the stream and the peer.
Own<IoStream> stream; own<io_stream> stream;
Maybe<Own<Peer>> peer; maybe<own<peer>> peer;
}; };
class AuthenticatedServer { class authenticated_server {
public: public:
virtual ~AuthenticatedServer() = default; virtual ~authenticated_server() = default;
virtual Conveyor<AuthenticatedIoStream> accept() = 0; virtual conveyor<authenticated_io_stream> accept() = 0;
}; };
/** /**
* Authenticated Network class which provides a peer identity when connecting * Authenticated Network class which provides a peer identity when connecting
*/ */
class AuthenticatedNetwork { class authenticated_network {
public: public:
virtual ~AuthenticatedNetwork() = default; virtual ~authenticated_network() = default;
/** /**
* Connects to the provided address. * Connects to the provided address.
* Returns as soon as it is authenticated or fails * Returns as soon as it is authenticated or fails
*/ */
virtual Conveyor<AuthenticatedIoStream> virtual conveyor<authenticated_io_stream>
connect(NetworkAddress &address) = 0; connect(network_address &address) = 0;
/** /**
* Creates a server listening for connections * Creates a server listening for connections
*/ */
virtual Own<AuthenticatedServer> listen() = 0; virtual own<authenticated_server> listen() = 0;
}; };
} // namespace saw } // namespace saw

View File

@ -1,26 +1,26 @@
#include "io_helpers.h" #include "io_helpers.h"
#include "io.h" #include "io.h"
#include <cassert> #include <cassert>
namespace saw { namespace saw {
void ReadTaskAndStepHelper::readStep(InputStream &reader) { void read_task_and_step_helper::read_step(input_stream &reader) {
while (read_task.has_value()) { while (read_task.has_value()) {
ReadIoTask &task = *read_task; read_io_task &task = *read_task;
ErrorOr<size_t> n_err = reader.read(task.buffer, task.max_length); error_or<size_t> n_err = reader.read(task.buffer, task.max_length);
if (n_err.isError()) { if (n_err.is_error()) {
const Error &error = n_err.error(); const error &error = n_err.error();
if (error.isCritical()) { if (error.is_critical()) {
if (read_done) { if (read_done) {
read_done->fail(error.copyError()); read_done->fail(error.copy_error());
} }
read_task = std::nullopt; read_task = std::nullopt;
} }
break; break;
} else if (n_err.isValue()) { } else if (n_err.is_value()) {
size_t n = n_err.value(); size_t n = n_err.value();
if (static_cast<size_t>(n) >= task.min_length && if (static_cast<size_t>(n) >= task.min_length &&
static_cast<size_t>(n) <= task.max_length) { static_cast<size_t>(n) <= task.max_length) {
@ -37,20 +37,20 @@ void ReadTaskAndStepHelper::readStep(InputStream &reader) {
} else { } else {
if (read_done) { if (read_done) {
read_done->fail(criticalError("Read failed")); read_done->fail(critical_error("Read failed"));
} }
read_task = std::nullopt; read_task = std::nullopt;
} }
} }
} }
void WriteTaskAndStepHelper::writeStep(OutputStream &writer) { void write_task_and_step_helper::write_step(output_stream &writer) {
while (write_task.has_value()) { while (write_task.has_value()) {
WriteIoTask &task = *write_task; write_io_task &task = *write_task;
ErrorOr<size_t> n_err = writer.write(task.buffer, task.length); error_or<size_t> n_err = writer.write(task.buffer, task.length);
if (n_err.isValue()) { if (n_err.is_value()) {
size_t n = n_err.value(); size_t n = n_err.value();
assert(n <= task.length); assert(n <= task.length);
@ -64,22 +64,22 @@ void WriteTaskAndStepHelper::writeStep(OutputStream &writer) {
task.length -= n; task.length -= n;
task.already_written += n; task.already_written += n;
} }
} else if (n_err.isError()) { } else if (n_err.is_error()) {
const Error &error = n_err.error(); const error &error = n_err.error();
if (error.isCritical()) { if (error.is_critical()) {
if (write_done) { if (write_done) {
write_done->fail(error.copyError()); write_done->fail(error.copy_error());
} }
write_task = std::nullopt; write_task = std::nullopt;
} }
break; break;
} else { } else {
if (write_done) { if (write_done) {
write_done->fail(criticalError("Write failed")); write_done->fail(critical_error("Write failed"));
} }
write_task = std::nullopt; write_task = std::nullopt;
} }
} }
} }
} // namespace saw } // namespace saw

View File

@ -16,38 +16,38 @@ namespace saw {
* and gnutls doesn't let me write or read into buffers I have to have this kind * and gnutls doesn't let me write or read into buffers I have to have this kind
* of strange abstraction. This may also be reusable for windows/macOS though. * of strange abstraction. This may also be reusable for windows/macOS though.
*/ */
class InputStream; class input_stream;
class ReadTaskAndStepHelper { class read_task_and_step_helper {
public: public:
struct ReadIoTask { struct read_io_task {
void *buffer; void *buffer;
size_t min_length; size_t min_length;
size_t max_length; size_t max_length;
size_t already_read = 0; size_t already_read = 0;
}; };
std::optional<ReadIoTask> read_task; std::optional<read_io_task> read_task;
Own<ConveyorFeeder<size_t>> read_done = nullptr; own<conveyor_feeder<size_t>> read_done = nullptr;
Own<ConveyorFeeder<void>> on_read_disconnect = nullptr; own<conveyor_feeder<void>> on_read_disconnect = nullptr;
public: public:
void readStep(InputStream &reader); void read_step(input_stream &reader);
}; };
class OutputStream; class output_stream;
class WriteTaskAndStepHelper { class write_task_and_step_helper {
public: public:
struct WriteIoTask { struct write_io_task {
const void *buffer; const void *buffer;
size_t length; size_t length;
size_t already_written = 0; size_t already_written = 0;
}; };
std::optional<WriteIoTask> write_task; std::optional<write_io_task> write_task;
Own<ConveyorFeeder<size_t>> write_done = nullptr; own<conveyor_feeder<size_t>> write_done = nullptr;
public: public:
void writeStep(OutputStream &writer); void write_step(output_stream &writer);
}; };
} // namespace saw } // namespace saw

View File

@ -1,87 +1,89 @@
#pragma once #pragma once
#include "async.h" #include "async.h"
#include "buffer.h"
#include "io.h" #include "io.h"
#include "message.h" #include "message.h"
#include "buffer.h"
namespace saw { namespace saw {
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer = MessageContainer<Incoming>, typename InContainer = message_container<Incoming>,
typename OutContainer = MessageContainer<Outgoing>, typename OutContainer = message_container<Outgoing>,
typename BufferT = RingBuffer> typename BufferT = ring_buffer>
class StreamingIoPeer { class streaming_io_peer {
public: public:
/** /**
* *
*/ */
StreamingIoPeer( streaming_io_peer(
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, own<conveyor_feeder<heap_message_root<Incoming, InContainer>>> feed,
Own<AsyncIoStream> stream, Codec codec, BufferT in, BufferT out); own<async_io_stream> stream, Codec codec, BufferT in, BufferT out);
/** /**
* *
*/ */
StreamingIoPeer( streaming_io_peer(
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, own<conveyor_feeder<heap_message_root<Incoming, InContainer>>> feed,
Own<AsyncIoStream> stream); own<async_io_stream> stream);
/** /**
* Deleted copy and move constructors * Deleted copy and move constructors
*/ */
SAW_FORBID_COPY(StreamingIoPeer); SAW_FORBID_COPY(streaming_io_peer);
SAW_FORBID_MOVE(StreamingIoPeer); SAW_FORBID_MOVE(streaming_io_peer);
/** /**
* Send a message to the remote peer * Send a message to the remote peer
*/ */
Error send(HeapMessageRoot<Outgoing, OutContainer> builder); error send(heap_message_root<Outgoing, OutContainer> builder);
/** /**
* A phantom conveyor feeder. Meant for interfacing with other components * A phantom conveyor feeder. Meant for interfacing with other components
*/ */
ConveyorFeeder<HeapMessageRoot<Outgoing, OutContainer>> &feeder(); conveyor_feeder<heap_message_root<Outgoing, OutContainer>> &feeder();
Conveyor<void> onReadDisconnected(); conveyor<void> on_read_disconnected();
private: private:
/// @unimplemented /// @unimplemented
class PeerConveyorFeeder final class peer_conveyor_feeder final
: public ConveyorFeeder<HeapMessageRoot<Outgoing, OutContainer>> { : public conveyor_feeder<heap_message_root<Outgoing, OutContainer>> {
public: public:
PeerConveyorFeeder( peer_conveyor_feeder(
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT> &peer_) OutContainer, BufferT> &peer_)
: peer{peer_} {} : peer_{peer_} {}
void feed(HeapMessageRoot<Outgoing, OutContainer> &&data) override { (void)data; } void feed(heap_message_root<Outgoing, OutContainer> &&data) override {
(void)data;
}
void fail(Error &&error) override { (void)error; } void fail(error &&error) override { (void)error; }
size_t space() const override { return 0; } size_t space() const override { return 0; }
size_t queued() const override { return 0; } size_t queued() const override { return 0; }
private: private:
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
BufferT> &peer; BufferT> &peer_;
}; };
private: private:
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> own<conveyor_feeder<heap_message_root<Incoming, InContainer>>>
incoming_feeder = nullptr; incoming_feeder_ = nullptr;
Own<AsyncIoStream> io_stream; own<async_io_stream> io_stream_;
Codec codec; Codec codec_;
BufferT in_buffer; BufferT in_buffer_;
BufferT out_buffer; BufferT out_buffer_;
ConveyorSink sink_read; conveyor_sink sink_read_;
ConveyorSink sink_write; conveyor_sink sink_write_;
PeerConveyorFeeder conveyor_feeder; peer_conveyor_feeder conveyor_feeder_;
}; };
/** /**
@ -89,13 +91,13 @@ private:
* This is a convenience wrapper intended for a faster setup of this class * This is a convenience wrapper intended for a faster setup of this class
*/ */
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer = MessageContainer<Incoming>, typename InContainer = message_container<Incoming>,
typename OutContainer = MessageContainer<Outgoing>, typename OutContainer = message_container<Outgoing>,
typename BufferT = RingBuffer> typename BufferT = ring_buffer>
std::pair<Own<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, std::pair<own<streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>>, OutContainer, BufferT>>,
Conveyor<HeapMessageRoot<Incoming, InContainer>>> conveyor<heap_message_root<Incoming, InContainer>>>
newStreamingIoPeer(Own<AsyncIoStream> stream); new_streaming_io_peer(own<async_io_stream> stream);
} // namespace saw } // namespace saw

View File

@ -2,110 +2,115 @@ namespace saw {
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT> typename InContainer, typename OutContainer, typename BufferT>
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>:: streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
StreamingIoPeer( BufferT>::
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, streaming_io_peer(
Own<AsyncIoStream> str) own<conveyor_feeder<heap_message_root<Incoming, InContainer>>> feed,
: StreamingIoPeer{std::move(feed), std::move(str), {}, {}, {}} {} own<async_io_stream> str)
: streaming_io_peer{std::move(feed), std::move(str), {}, {}, {}} {}
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT> typename InContainer, typename OutContainer, typename BufferT>
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>:: streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
StreamingIoPeer( BufferT>::
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed_, streaming_io_peer(
Own<AsyncIoStream> stream_, Codec codec_, BufferT in_, BufferT out_) own<conveyor_feeder<heap_message_root<Incoming, InContainer>>> feed,
: incoming_feeder{std::move(feed_)}, io_stream{std::move(stream_)}, own<async_io_stream> stream, Codec codec, BufferT in, BufferT out)
codec{std::move(codec_)}, in_buffer{std::move(in_)}, out_buffer{std::move( : incoming_feeder_{std::move(feed)},
out_)}, io_stream_{std::move(stream)}, codec_{std::move(codec)},
sink_read{io_stream->readDone() in_buffer_{std::move(in)}, out_buffer_{std::move(out)},
.then([this](size_t bytes) -> ErrorOr<void> { sink_read_{
in_buffer.writeAdvance(bytes); io_stream_->read_done()
.then([this](size_t bytes) -> error_or<void> {
in_buffer_.write_advance(bytes);
if (in_buffer.writeSegmentLength() == 0) { if (in_buffer_.write_segment_length() == 0) {
return criticalError("Message too long"); return critical_error("Message too long");
} }
io_stream->read(&in_buffer.write(), 1, io_stream_->read(&in_buffer_.write(), 1,
in_buffer.writeSegmentLength()); in_buffer_.write_segment_length());
while (true) { while (true) {
auto root = auto root = heap_message_root<Incoming, InContainer>();
heapMessageRoot<Incoming, InContainer>(); auto builder = root.build();
auto builder = root.build();
Error error = error err = codec_.template decode<Incoming, InContainer>(
codec.template decode<Incoming, InContainer>( builder, in_buffer_);
builder, in_buffer); if (err.is_critical()) {
if (error.isCritical()) { return err;
return error; }
}
if (!error.failed()) { if (!err.failed()) {
incoming_feeder->feed(std::move(root)); incoming_feeder_->feed(std::move(root));
} else { } else {
break; break;
} }
} }
return Void{}; return void_t{};
}) })
.sink([this](Error error) { .sink([this](error err) {
incoming_feeder->fail(error.copyError()); incoming_feeder_->fail(err.copy_error());
return error; return err;
})}, })},
sink_write{io_stream->writeDone() sink_write_{io_stream_->write_done()
.then([this](size_t bytes) -> ErrorOr<void> { .then([this](size_t bytes) -> error_or<void> {
out_buffer.readAdvance(bytes); out_buffer_.read_advance(bytes);
if (out_buffer.readCompositeLength() > 0) { if (out_buffer_.readCompositeLength() > 0) {
io_stream->write(&out_buffer.read(), io_stream_->write(
out_buffer.readSegmentLength()); &out_buffer_.read(),
} out_buffer_.read_segment_length());
}
return Void{}; return void_t{};
}) })
.sink()} { .sink()} {
io_stream->read(&in_buffer.write(), 1, in_buffer.writeSegmentLength()); io_stream_->read(&in_buffer_.write(), 1, in_buffer_.write_segment_length());
} }
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT> typename InContainer, typename OutContainer, typename BufferT>
Error StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, error streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
BufferT>::send(HeapMessageRoot<Outgoing, OutContainer> BufferT>::send(heap_message_root<Outgoing, OutContainer>
msg) { msg) {
bool restart_write = out_buffer.readSegmentLength() == 0; bool restart_write = out_buffer_.read_segment_length() == 0;
Error error = error err =
codec.template encode<Outgoing, OutContainer>(msg.read(), out_buffer); codec_.template encode<Outgoing, OutContainer>(msg.read(), out_buffer_);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
if (restart_write) { if (restart_write) {
io_stream->write(&out_buffer.read(), out_buffer.readSegmentLength()); io_stream_->write(&out_buffer_.read(),
out_buffer_.read_segment_length());
} }
return noError(); return no_error();
} }
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT> typename InContainer, typename OutContainer, typename BufferT>
Conveyor<void> StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, conveyor<void>
OutContainer, BufferT>::onReadDisconnected() { streaming_io_peer<Codec, Incoming, Outgoing, InContainer, OutContainer,
return io_stream->onReadDisconnected(); BufferT>::on_read_disconnected() {
return io_stream_->on_read_disconnected();
} }
template <typename Codec, typename Incoming, typename Outgoing, template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT> typename InContainer, typename OutContainer, typename BufferT>
std::pair<Own<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, std::pair<own<streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>>, OutContainer, BufferT>>,
Conveyor<HeapMessageRoot<Incoming, InContainer>>> conveyor<heap_message_root<Incoming, InContainer>>>
newStreamingIoPeer(Own<AsyncIoStream> stream) { newstreaming_io_peer(own<async_io_stream> stream) {
auto caf = newConveyorAndFeeder<HeapMessageRoot<Incoming, InContainer>>(); auto caf =
new_conveyor_and_feeder<heap_message_root<Incoming, InContainer>>();
return {heap<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, return {heap<streaming_io_peer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>>(std::move(caf.feeder), OutContainer, BufferT>>(
std::move(stream)), std::move(caf.feeder), std::move(stream)),
std::move(caf.conveyor)}; std::move(caf.conveyor)};
} }

View File

@ -1,7 +1,7 @@
#include "log.h" #include "log.h"
namespace saw { namespace saw {
LogIo::LogIo(EventLoop &loop) : loop{loop} {} log_io::log_io(event_loop &loop) : loop_{loop} {}
Log::Log(LogIo &central, EventLoop &loop) : central{central}, loop{loop} {} log::log(log_io &central, event_loop &loop) : central_{central}, loop_{loop} {}
} // namespace saw } // namespace saw

View File

@ -3,24 +3,24 @@
#include "common.h" #include "common.h"
namespace saw { namespace saw {
class EventLoop; class event_loop;
class LogIo; class log_io;
class Log { class log {
public: public:
enum class Type : uint8_t { Info, Warning, Error, Debug }; enum class Type : uint8_t { Info, Warning, Error, Debug };
private: private:
LogIo &central; log_io &central_;
EventLoop &loop; event_loop &loop_;
public: public:
Log(LogIo &central, EventLoop &loop); log(log_io &central, event_loop &loop);
}; };
class LogIo { class log_io {
private: private:
EventLoop &loop; event_loop &loop_;
public: public:
LogIo(EventLoop &loop); log_io(event_loop &loop);
}; };
} // namespace saw } // namespace saw

View File

@ -15,18 +15,18 @@
#include "string_literal.h" #include "string_literal.h"
namespace saw { namespace saw {
class MessageBase { class message_base {
protected: protected:
bool set_explicitly = false; bool set_explicitly_ = false;
public: public:
template <class T> T &as() { 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); return dynamic_cast<T &>(*this);
} }
template <class T> const T &as() const { 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); return dynamic_cast<const T &>(*this);
} }
}; };
@ -44,184 +44,184 @@ public:
/* /*
* Struct Message * Struct Message
*/ */
template <class... V, StringLiteral... Keys, class Container> template <class... V, string_literal... Keys, class Container>
class Message<schema::Struct<schema::NamedMember<V, Keys>...>, Container> final class message<schema::Struct<schema::NamedMember<V, Keys>...>, Container> final
: public MessageBase { : public message_base {
private: private:
using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>; using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>;
using MessageType = Message<SchemaType, Container>; using MessageType = message<SchemaType, Container>;
Container container; Container container_;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>, static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message"); "Container should have same the schema as Message");
friend class Builder; friend class builder;
friend class Reader; friend class reader;
public: public:
class Reader; class reader;
class Builder { class builder {
private: private:
MessageType &message; MessageType &message_;
public: public:
Builder(MessageType &msg) : message{msg} {} builder(MessageType &msg) : message_{msg} {}
Reader asReader() { return Reader{message}; } reader as_reader() { return reader{message_}; }
/* /*
* Initialize a member by index * Initialize a member by index
*/ */
template <size_t i> template <size_t i>
typename std::enable_if< typename std::enable_if<
!SchemaIsArray< !schema_is_array<
typename MessageParameterPackType<i, V...>::Type>::Value, typename message_parameter_pack_type<i, V...>::Type>::Value,
typename Container::template ElementType<i>::Builder>::type typename Container::template ElementType<i>::builder>::type
init() { init() {
return typename Container::template ElementType<i>::Builder{ return typename Container::template ElementType<i>::builder{
message.container.template get<i>()}; message_.container_.template get<i>()};
} }
/* /*
* Initialize a member by their name * Initialize a member by their name
* This is the preferred method for schema::Struct messages * This is the preferred method for schema::Struct messages
*/ */
template <StringLiteral Literal> template <string_literal Literal>
typename std::enable_if< typename std::enable_if<
!SchemaIsArray<typename MessageParameterPackType< !schema_is_array<typename message_parameter_pack_type<
MessageParameterKeyPackIndex<Literal, Keys...>::Value, message_parameter_key_pack_index<Literal, Keys...>::Value,
V...>::Type>::Value, V...>::Type>::Value,
typename Container::template ElementType< typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, message_parameter_key_pack_index<Literal, Keys...>::Value>::
Keys...>::Value>::Builder>::type builder>::type
init() { init() {
constexpr size_t i = constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value; message_parameter_key_pack_index<Literal, Keys...>::Value;
return init<i>(); return init<i>();
} }
template <size_t i> template <size_t i>
typename std::enable_if< typename std::enable_if<
SchemaIsArray< schema_is_array<
typename MessageParameterPackType<i, V...>::Type>::Value, typename message_parameter_pack_type<i, V...>::Type>::Value,
typename Container::template ElementType<i>::Builder>::type typename Container::template ElementType<i>::builder>::type
init(size_t size = 0) { init(size_t size = 0) {
auto array_builder = auto array_builder =
typename Container::template ElementType<i>::Builder{ typename Container::template ElementType<i>::builder{
message.container.template get<i>(), size}; message_.container_.template get<i>(), size};
return array_builder; return array_builder;
} }
/* /*
* Version for array schema type * Version for array schema type
*/ */
template <StringLiteral Literal> template <string_literal Literal>
typename std::enable_if< typename std::enable_if<
SchemaIsArray<typename MessageParameterPackType< schema_is_array<typename message_parameter_pack_type<
MessageParameterKeyPackIndex<Literal, Keys...>::Value, message_parameter_key_pack_index<Literal, Keys...>::Value,
V...>::Type>::Value, V...>::Type>::Value,
typename Container::template ElementType< typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, message_parameter_key_pack_index<Literal, Keys...>::Value>::
Keys...>::Value>::Builder>::type builder>::type
init(size_t size) { init(size_t size) {
constexpr size_t i = constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value; message_parameter_key_pack_index<Literal, Keys...>::Value;
return init<i>(size); return init<i>(size);
} }
}; };
class Reader { class reader {
private: private:
MessageType &message; MessageType &message_;
public: public:
Reader(MessageType &msg) : message{msg} {} reader(MessageType &msg) : message_{msg} {}
Builder asBuilder() { return Builder{message}; } builder as_builder() { return builder{message_}; }
/* /*
* Get member by index * Get member by index
*/ */
template <size_t i> template <size_t i>
typename Container::template ElementType<i>::Reader get() { typename Container::template ElementType<i>::reader get() {
return typename Container::template ElementType<i>::Reader{ return typename Container::template ElementType<i>::reader{
message.container.template get<i>()}; message_.container_.template get<i>()};
} }
/* /*
* Get member by name * Get member by name
* This is the preferred method for schema::Struct messages * This is the preferred method for schema::Struct messages
*/ */
template <StringLiteral Literal> template <string_literal Literal>
typename Container::template ElementType< typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Reader message_parameter_key_pack_index<Literal, Keys...>::Value>::reader
get() { get() {
// The index of the first match // The index of the first match
constexpr size_t i = constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value; message_parameter_key_pack_index<Literal, Keys...>::Value;
return get<i>(); return get<i>();
} }
}; };
Builder build() { return Builder{*this}; } builder build() { return builder{*this}; }
Reader read() { return Reader{*this}; } reader read() { return reader{*this}; }
}; };
/* /*
* Union message class. Wrapper object * Union message class. Wrapper object
*/ */
template <class... V, StringLiteral... Keys, class Container> template <class... V, string_literal... Keys, class Container>
class Message<schema::Union<schema::NamedMember<V, Keys>...>, Container> final class message<schema::Union<schema::NamedMember<V, Keys>...>, Container> final
: public MessageBase { : public message_base {
private: private:
using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>; using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>;
using MessageType = Message<SchemaType, Container>; using MessageType = message<SchemaType, Container>;
Container container; Container container_;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>, static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message"); "Container should have same the schema as Message");
friend class Builder; friend class builder;
friend class Reader; friend class reader;
public: public:
class Reader; class reader;
class Builder { class builder {
private: private:
MessageType &message; MessageType &message_;
public: public:
Builder(MessageType &msg) : message{msg} {} builder(MessageType &msg) : message_{msg} {}
Reader asReader() { return Reader{message}; } reader as_reader() { return reader{message_}; }
template <size_t i> template <size_t i>
typename std::enable_if< typename std::enable_if<
!SchemaIsArray< !schema_is_array<
typename MessageParameterPackType<i, V...>::Type>::Value, typename message_parameter_pack_type<i, V...>::Type>::Value,
typename Container::template ElementType<i>::Builder>::type typename Container::template ElementType<i>::builder>::type
init() { init() {
return typename Container::template ElementType<i>::Builder{ return typename Container::template ElementType<i>::builder{
message.container.template get<i>()}; message_.container_.template get<i>()};
} }
template <StringLiteral Literal> template <string_literal Literal>
typename std::enable_if< typename std::enable_if<
!SchemaIsArray<typename MessageParameterPackType< !schema_is_array<typename message_parameter_pack_type<
MessageParameterKeyPackIndex<Literal, Keys...>::Value, message_parameter_key_pack_index<Literal, Keys...>::Value,
V...>::Type>::Value, V...>::Type>::Value,
typename Container::template ElementType< typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, message_parameter_key_pack_index<Literal, Keys...>::Value>::
Keys...>::Value>::Builder>::type builder>::type
init() { init() {
constexpr size_t i = constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value; message_parameter_key_pack_index<Literal, Keys...>::Value;
return init<i>(); return init<i>();
} }
@ -231,65 +231,65 @@ public:
*/ */
template <size_t i> template <size_t i>
typename std::enable_if< typename std::enable_if<
SchemaIsArray< schema_is_array<
typename MessageParameterPackType<i, V...>::Type>::Value, typename message_parameter_pack_type<i, V...>::Type>::Value,
typename Container::template ElementType<i>::Builder>::type typename Container::template ElementType<i>::builder>::type
init(size_t size = 0) { init(size_t size = 0) {
return typename Container::template ElementType<i>::Builder{ return typename Container::template ElementType<i>::builder{
message.container.template get<i>(), size}; message_.container_.template get<i>(), size};
} }
template <StringLiteral Literal> template <string_literal Literal>
typename std::enable_if< typename std::enable_if<
SchemaIsArray<typename MessageParameterPackType< schema_is_array<typename message_parameter_pack_type<
MessageParameterKeyPackIndex<Literal, Keys...>::Value, message_parameter_key_pack_index<Literal, Keys...>::Value,
V...>::Type>::Value, V...>::Type>::Value,
typename Container::template ElementType< typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, message_parameter_key_pack_index<Literal, Keys...>::Value>::
Keys...>::Value>::Builder>::type builder>::type
init(size_t size) { init(size_t size) {
constexpr size_t i = constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value; message_parameter_key_pack_index<Literal, Keys...>::Value;
return init<i>(size); return init<i>(size);
} }
}; };
class Reader { class reader {
private: private:
MessageType &message; MessageType &message_;
public: public:
Reader(MessageType &msg) : message{msg} {} reader(MessageType &msg) : message_{msg} {}
Builder asBuilder() { return Builder{message}; } builder as_builder() { return builder{message_}; }
template <size_t i> template <size_t i>
typename Container::template ElementType<i>::Reader get() { typename Container::template ElementType<i>::reader get() {
return typename Container::template ElementType<i>::Reader{ return typename Container::template ElementType<i>::reader{
message.container.template get<i>()}; message_.container_.template get<i>()};
} }
template <StringLiteral Literal> template <string_literal Literal>
typename Container::template ElementType< typename Container::template ElementType<
MessageParameterKeyPackIndex<Literal, Keys...>::Value>::Reader message_parameter_key_pack_index<Literal, Keys...>::Value>::reader
get() { get() {
// The index of the first match // The index of the first match
constexpr size_t i = constexpr size_t i =
MessageParameterKeyPackIndex<Literal, Keys...>::Value; message_parameter_key_pack_index<Literal, Keys...>::Value;
return get<i>(); return get<i>();
} }
template <StringLiteral Literal> template <string_literal Literal>
static constexpr size_t toIndex() noexcept { static constexpr size_t to_index() noexcept {
return MessageParameterKeyPackIndex<Literal, Keys...>::Value; return message_parameter_key_pack_index<Literal, Keys...>::Value;
} }
size_t index() const noexcept { return message.container.index(); } size_t index() const noexcept { return message_.container_.index(); }
template <StringLiteral Literal> bool hasAlternative() const { template <string_literal Literal> bool has_alternative() const {
return index() == toIndex<Literal>(); return index() == to_index<Literal>();
} }
}; };
}; };
@ -298,59 +298,59 @@ public:
* Array message class. Wrapper around an array schema element * Array message class. Wrapper around an array schema element
*/ */
template <class T, class Container> 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: private:
using SchemaType = schema::Array<T>; using SchemaType = schema::Array<T>;
using MessageType = Message<SchemaType, Container>; using MessageType = message<SchemaType, Container>;
Container container; Container container_;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>, static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same Schema as Message"); "Container should have same Schema as Message");
friend class Builder; friend class builder;
friend class Reader; friend class reader;
public: public:
class Reader; class reader;
class Builder { class builder {
private: private:
MessageType &message; MessageType &message_;
public: public:
Builder(MessageType &msg, size_t size) : message{msg} { builder(MessageType &msg, size_t size) : message_{msg} {
if (size > 0) { if (size > 0) {
message.container.resize(size); message_.container_.resize(size);
} }
} }
Reader asReader() { return Reader{message}; } reader as_reader() { return reader{message_}; }
typename Container::ElementType::Builder init(size_t i) { typename Container::ElementType::builder init(size_t i) {
return typename Container::ElementType::Builder{ return typename Container::ElementType::builder{
message.container.get(i)}; message_.container_.get(i)};
} }
size_t size() const { return message.container.size(); } size_t size() const { return message_.container_.size(); }
void resize(size_t size) { message.container.resize(size); } void resize(size_t size) { message_.container_.resize(size); }
}; };
class Reader { class reader {
private: private:
MessageType &message; MessageType &message_;
public: public:
Reader(MessageType &msg) : message{msg} {} reader(MessageType &msg) : message_{msg} {}
Builder asBuilder() { return Builder{message, 0}; } builder as_builder() { return builder{message_, 0}; }
typename Container::ElementType::Reader get(size_t i) { typename Container::ElementType::reader get(size_t i) {
return typename Container::ElementType::Reader{ return typename Container::ElementType::reader{
message.container.get(i)}; message_.container_.get(i)};
} }
size_t size() const { return message.container.size(); } size_t size() const { return message_.container_.size(); }
}; };
}; };
@ -358,62 +358,62 @@ public:
* Tuple message class. Wrapper around a tuple schema * Tuple message class. Wrapper around a tuple schema
*/ */
template <class... T, class Container> 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: private:
using SchemaType = schema::Tuple<T...>; using SchemaType = schema::Tuple<T...>;
using MessageType = Message<SchemaType, Container>; using MessageType = message<SchemaType, Container>;
Container container; Container container_;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>, static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message"); "Container should have same the schema as Message");
friend class Builder; friend class builder;
friend class Reader; friend class reader;
public: public:
class Reader; class reader;
class Builder { class builder {
MessageType &message; MessageType &message_;
public: public:
Builder(MessageType &msg) : message{msg} {} builder(MessageType &msg) : message_{msg} {}
Reader asReader() { return Reader{message}; } reader as_reader() { return reader{message_}; }
template <size_t i> template <size_t i>
typename std::enable_if< typename std::enable_if<
!SchemaIsArray< !schema_is_array<
typename MessageParameterPackType<i, T...>::Type>::Value, typename message_parameter_pack_type<i, T...>::Type>::Value,
typename Container::template ElementType<i>::Builder>::type typename Container::template ElementType<i>::builder>::type
init() { init() {
return typename Container::template ElementType<i>::Builder{ return typename Container::template ElementType<i>::builder{
message.container.template get<i>()}; message_.container_.template get<i>()};
} }
template <size_t i> template <size_t i>
typename std::enable_if< typename std::enable_if<
SchemaIsArray< schema_is_array<
typename MessageParameterPackType<i, T...>::Type>::Value, typename message_parameter_pack_type<i, T...>::Type>::Value,
typename Container::template ElementType<i>::Builder>::type typename Container::template ElementType<i>::builder>::type
init(size_t size = 0) { init(size_t size = 0) {
return typename Container::template ElementType<i>::Builder{ return typename Container::template ElementType<i>::builder{
message.container.template get<i>(), size}; message_.container_.template get<i>(), size};
} }
}; };
class Reader { class reader {
private: private:
MessageType &message; MessageType &message_;
public: public:
Reader(MessageType &msg) : message{msg} {} reader(MessageType &msg) : message_{msg} {}
Builder asBuilder() { return Builder{message}; } builder as_builder() { return builder{message_}; }
template <size_t i> template <size_t i>
typename Container::template ElementType<i>::Reader get() { typename Container::template ElementType<i>::reader get() {
return typename Container::template ElementType<i>::Reader{ return typename Container::template ElementType<i>::reader{
message.container.template get<i>()}; message_.container_.template get<i>()};
} }
}; };
}; };
@ -423,140 +423,142 @@ public:
* int16_t, int32_t, int64_t) message class * int16_t, int32_t, int64_t) message class
*/ */
template <class T, size_t N, class Container> 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: private:
using SchemaType = schema::Primitive<T, N>; using SchemaType = schema::Primitive<T, N>;
using MessageType = Message<SchemaType, Container>; using MessageType = message<SchemaType, Container>;
Container container; Container container_;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>, static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message"); "Container should have same the schema as Message");
friend class Builder; friend class builder;
friend class Reader; friend class reader;
public: public:
class Reader; class reader;
class Builder { class builder {
private: private:
MessageType &message; MessageType &message_;
public: public:
Builder(MessageType &msg) : message{msg} {} builder(MessageType &msg) : message_{msg} {}
Reader asReader() { return Reader{message}; } reader as_reader() { return reader{message_}; }
void set(const typename Container::ValueType &value) { void set(const typename Container::ValueType &value) {
message.container.set(value); message_.container_.set(value);
} }
}; };
class Reader { class reader {
private: private:
MessageType &message; MessageType &message_;
public: public:
Reader(Message &msg) : message{msg} {} reader(message &msg) : message_{msg} {}
Builder asBuilder() { return Builder{message}; } builder as_builder() { return builder{message_}; }
const typename Container::ValueType &get() const { const typename Container::ValueType &get() const {
return message.container.get(); return message_.container_.get();
} }
}; };
}; };
template <class Container> template <class Container>
class Message<schema::String, Container> final : public MessageBase { class message<schema::String, Container> final : public message_base {
private: private:
using SchemaType = schema::String; using SchemaType = schema::String;
using MessageType = Message<SchemaType, Container>; using MessageType = message<SchemaType, Container>;
Container container; Container container_;
static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>, static_assert(std::is_same_v<SchemaType, typename Container::SchemaType>,
"Container should have same the schema as Message"); "Container should have same the schema as Message");
friend class Builder; friend class builder;
friend class Reader; friend class reader;
public: public:
class Reader; class reader;
class Builder { class builder {
private: private:
MessageType &message; MessageType &message_;
public: public:
Builder(MessageType &msg) : message{msg} {} builder(MessageType &msg) : message_{msg} {}
Reader asReader() { return Reader{message}; } reader as_reader() { return reader{message_}; }
void set(std::string &&str) { message.container.set(std::move(str)); } void set(std::string &&str) { message_.container_.set(std::move(str)); }
void set(const std::string_view str) { message.container.set(str); } void set(const std::string_view str) { message_.container_.set(str); }
void set(const char *str) { set(std::string_view{str}); } void set(const char *str) { set(std::string_view{str}); }
}; };
class Reader { class reader {
private: private:
MessageType &message; MessageType &message_;
public: public:
Reader(MessageType &msg) : message{msg} {} reader(MessageType &msg) : message_{msg} {}
Builder asBuilder() { return Builder{message}; } builder as_builder() { return builder{message_}; }
const std::string_view get() const { return message.container.get(); } const std::string_view get() const { return message_.container_.get(); }
}; };
}; };
template <class Schema, class Container = MessageContainer<Schema>> template <class Schema, class Container = message_container<Schema>>
class HeapMessageRoot { class heap_message_root {
private: private:
Own<Message<Schema, Container>> root; own<message<Schema, Container>> root_;
public: 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() { typename message<Schema, Container>::builder build() {
assert(root); assert(root_);
return typename Message<Schema, Container>::Builder{*root}; return typename message<Schema, Container>::builder{*root_};
} }
typename Message<Schema, Container>::Reader read() { typename message<Schema, Container>::reader read() {
assert(root); assert(root_);
return typename Message<Schema, Container>::Reader{*root}; return typename message<Schema, Container>::reader{*root_};
} }
}; };
template <class T, class Container> template <class T, class Container>
class HeapMessageRoot<schema::Array<T>, Container> { class heap_message_root<schema::Array<T>, Container> {
public: public:
using Schema = schema::Array<T>; using Schema = schema::Array<T>;
private: private:
Own<Message<Schema, Container>> root; own<message<Schema, Container>> root_;
public: 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) { typename message<Schema, Container>::builder build(size_t size) {
assert(root); assert(root_);
return typename Message<Schema, Container>::Builder{*root, size}; return typename message<Schema, Container>::builder{*root_, size};
} }
typename Message<Schema, Container>::Reader read() { typename message<Schema, Container>::reader read() {
assert(root); assert(root_);
return typename Message<Schema, Container>::Reader{*root}; return typename message<Schema, Container>::reader{*root_};
} }
}; };
/* /*
* Minor helper for creating a message root * Minor helper for creating a message root
*/ */
template <class Schema, class Container = MessageContainer<Schema>> template <class Schema, class Container = message_container<Schema>>
inline HeapMessageRoot<Schema, Container> heapMessageRoot() { inline heap_message_root<Schema, Container> new_heap_message_root() {
Own<Message<Schema, Container>> root = heap<Message<Schema, Container>>(); 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 } // namespace saw

View File

@ -2,21 +2,25 @@
#include "schema.h" #include "schema.h"
#include <variant>
#include <vector>
namespace saw { namespace saw {
template <class T> class MessageContainer; template <class T> class message_container;
template <class T, class Container = MessageContainer<T>> class Message; template <class T, class Container = message_container<T>> class message;
template <size_t N, class... T> struct MessageParameterPackType; template <size_t N, class... T> struct message_parameter_pack_type;
template <class TN, class... T> struct MessageParameterPackType<0, TN, T...> { template <class TN, class... T>
struct message_parameter_pack_type<0, TN, T...> {
using Type = TN; using Type = TN;
}; };
template <size_t N, class TN, class... T> template <size_t N, class TN, class... T>
struct MessageParameterPackType<N, TN, T...> { struct message_parameter_pack_type<N, TN, T...> {
static_assert(sizeof...(T) > 0, "Exhausted parameters"); static_assert(sizeof...(T) > 0, "Exhausted parameters");
using Type = typename MessageParameterPackType<N - 1, T...>::Type; using Type = typename message_parameter_pack_type<N - 1, T...>::Type;
}; };
template <class T, class... TL> struct MessageParameterPackIndex; template <class T, class... TL> struct MessageParameterPackIndex;
@ -36,117 +40,118 @@ struct MessageParameterPackIndex<T, TL0, TL...> {
* StringLiterals cannot be resolved as non-type primitive template values can. * StringLiterals cannot be resolved as non-type primitive template values can.
* This is the workaround * This is the workaround
*/ */
template <StringLiteral V, StringLiteral Key0, StringLiteral... Keys> template <string_literal V, string_literal Key0, string_literal... Keys>
struct MessageParameterKeyPackIndexHelper { struct message_parameter_key_pack_index_helper {
static constexpr size_t Value = static constexpr size_t Value =
(V == Key0) (V == Key0)
? (0u) ? (0u)
: (1u + MessageParameterKeyPackIndexHelper<V, Keys...>::Value); : (1u + message_parameter_key_pack_index_helper<V, Keys...>::Value);
}; };
template <StringLiteral V, StringLiteral Key0> template <string_literal V, string_literal Key0>
struct MessageParameterKeyPackIndexHelper<V, Key0> { struct message_parameter_key_pack_index_helper<V, Key0> {
static constexpr size_t Value = (V == Key0) ? (0u) : (1u); static constexpr size_t Value = (V == Key0) ? (0u) : (1u);
}; };
template <StringLiteral V, StringLiteral... Keys> template <string_literal V, string_literal... Keys>
struct MessageParameterKeyPackIndex { struct message_parameter_key_pack_index {
static constexpr size_t Value = static constexpr size_t Value =
MessageParameterKeyPackIndexHelper<V, Keys...>::Value; message_parameter_key_pack_index_helper<V, Keys...>::Value;
static_assert(Value < sizeof...(Keys), static_assert(Value < sizeof...(Keys),
"Provided StringLiteral doesn't exist in searched list"); "Provided StringLiteral doesn't exist in searched list");
}; };
template <class T> struct SchemaIsArray { template <class T> struct schema_is_array {
constexpr static bool Value = false; constexpr static bool Value = false;
}; };
template <class T> struct SchemaIsArray<schema::Array<T>> { template <class T> struct schema_is_array<schema::Array<T>> {
constexpr static bool Value = true; constexpr static bool Value = true;
}; };
template <class... V, StringLiteral... Keys> template <class... V, string_literal... Keys>
class MessageContainer<schema::Struct<schema::NamedMember<V, Keys>...>> { class message_container<schema::Struct<schema::NamedMember<V, Keys>...>> {
private: private:
using ValueType = std::tuple<Message<V, MessageContainer<V>>...>; using ValueType = std::tuple<message<V, message_container<V>>...>;
ValueType values; ValueType values_;
public: public:
using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>; using SchemaType = schema::Struct<schema::NamedMember<V, Keys>...>;
template <size_t i> template <size_t i>
using ElementType = typename MessageParameterPackType< using ElementType = typename message_parameter_pack_type<
i, Message<V, MessageContainer<V>>...>::Type; i, message<V, message_container<V>>...>::Type;
template <size_t i> ElementType<i> &get() { return std::get<i>(values); } template <size_t i> ElementType<i> &get() { return std::get<i>(values_); }
}; };
/* /*
* Union storage * Union storage
*/ */
template <class... V, StringLiteral... Keys> template <class... V, string_literal... Keys>
class MessageContainer<schema::Union<schema::NamedMember<V, Keys>...>> { class message_container<schema::Union<schema::NamedMember<V, Keys>...>> {
private: private:
using ValueType = std::variant<Message<V, MessageContainer<V>>...>; using ValueType = std::variant<message<V, message_container<V>>...>;
ValueType value; ValueType value_;
public: public:
using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>; using SchemaType = schema::Union<schema::NamedMember<V, Keys>...>;
template <size_t i> template <size_t i>
using ElementType = typename MessageParameterPackType< using ElementType = typename message_parameter_pack_type<
i, Message<V, MessageContainer<V>>...>::Type; i, message<V, message_container<V>>...>::Type;
template <size_t i> ElementType<i> &get() { template <size_t i> ElementType<i> &get() {
if (i != value.index()) { if (i != value_.index()) {
using MessageIV = typename MessageParameterPackType<i, V...>::Type; using MessageIV =
value = Message<MessageIV, MessageContainer<MessageIV>>{}; typename message_parameter_pack_type<i, V...>::Type;
value_ = message<MessageIV, message_container<MessageIV>>{};
} }
return std::get<i>(value); return std::get<i>(value_);
} }
size_t index() const noexcept { return value.index(); } size_t index() const noexcept { return value_.index(); }
}; };
/* /*
* Array storage * Array storage
*/ */
template <class T> class MessageContainer<schema::Array<T>> { template <class T> class message_container<schema::Array<T>> {
private: private:
using ValueType = std::vector<Message<T, MessageContainer<T>>>; using ValueType = std::vector<message<T, message_container<T>>>;
ValueType values; ValueType values_;
public: public:
using SchemaType = schema::Array<T>; using SchemaType = schema::Array<T>;
using ElementType = Message<T, MessageContainer<T>>; using ElementType = message<T, message_container<T>>;
Message<T, MessageContainer<T>> &get(size_t index) { message<T, message_container<T>> &get(size_t index) {
return values.at(index); return values_.at(index);
} }
void resize(size_t size) { values.resize(size); } void resize(size_t size) { values_.resize(size); }
size_t size() const { return values.size(); } size_t size() const { return values_.size(); }
}; };
/* /*
* Tuple storage * Tuple storage
*/ */
template <class... T> class MessageContainer<schema::Tuple<T...>> { template <class... T> class message_container<schema::Tuple<T...>> {
private: private:
using ValueType = std::tuple<Message<T, MessageContainer<T>>...>; using ValueType = std::tuple<message<T, message_container<T>>...>;
ValueType values; ValueType values_;
public: public:
using SchemaType = schema::Tuple<T...>; using SchemaType = schema::Tuple<T...>;
template <size_t i> template <size_t i>
using ElementType = typename MessageParameterPackType< using ElementType = typename message_parameter_pack_type<
i, Message<T, MessageContainer<T>>...>::Type; i, message<T, message_container<T>>...>::Type;
template <size_t i> ElementType<i> &get() { return std::get<i>(values); } template <size_t i> ElementType<i> &get() { return std::get<i>(values_); }
}; };
/* /*
@ -205,37 +210,37 @@ struct PrimitiveTypeHelper<schema::Primitive<schema::FloatingPoint, 8>> {
using Type = double; using Type = double;
}; };
template <class T, size_t N> class MessageContainer<schema::Primitive<T, N>> { template <class T, size_t N> class message_container<schema::Primitive<T, N>> {
public: public:
using SchemaType = schema::Primitive<T, N>; using SchemaType = schema::Primitive<T, N>;
using ValueType = using ValueType =
typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type; typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type;
private: private:
ValueType value; ValueType value_;
public: public:
MessageContainer() : value{0} {} message_container() : value_{0} {}
void set(const ValueType &v) { value = v; } void set(const ValueType &v) { value_ = v; }
const ValueType &get() const { return value; } const ValueType &get() const { return value_; }
}; };
template <> class MessageContainer<schema::String> { template <> class message_container<schema::String> {
public: public:
using SchemaType = schema::String; using SchemaType = schema::String;
using ValueType = std::string; using ValueType = std::string;
using ValueViewType = std::string_view; using ValueViewType = std::string_view;
private: private:
ValueType value; ValueType value_;
public: public:
void set(ValueType &&v) { value = std::move(v); } void set(ValueType &&v) { value_ = std::move(v); }
void set(const ValueType &v) { value = v; } void set(const ValueType &v) { value_ = v; }
void set(const ValueViewType v) { value = std::string{v}; } void set(const ValueViewType v) { value_ = std::string{v}; }
const ValueType &get() const { return value; } const ValueType &get() const { return value_; }
}; };
} // namespace saw } // namespace saw

View File

@ -5,303 +5,307 @@
#include "stream_endian.h" #include "stream_endian.h"
namespace saw { namespace saw {
class ProtoKelCodec { class proto_kel_codec {
public: public:
using UnionIdT = uint32_t; using UnionIdT = uint32_t;
using ArrayLengthT = uint64_t; using ArrayLengthT = uint64_t;
using PacketLengthT = uint64_t; using PacketLengthT = uint64_t;
private: private:
struct ReadContext { struct read_context {
Buffer &buffer; buffer &buffer;
size_t offset = 0; size_t offset = 0;
}; };
template <typename T> friend struct ProtoKelEncodeImpl; template <typename T> friend struct proto_kel_encode_impl;
template <typename T> friend struct ProtoKelDecodeImpl; template <typename T> friend struct proto_kel_decode_impl;
public: public:
struct Limits { struct limits {
ProtoKelCodec::PacketLengthT packet_size; proto_kel_codec::PacketLengthT packet_size;
Limits() : packet_size{4096} {} limits() : packet_size{4096} {}
Limits(ProtoKelCodec::PacketLengthT ps) : packet_size{ps} {} limits(proto_kel_codec::PacketLengthT ps) : packet_size{ps} {}
}; };
struct Version { struct version {
size_t major; size_t major;
size_t minor; size_t minor;
size_t security; size_t security;
}; };
const Version version() const { return Version{0, 0, 0}; } const version get_version() const { return version{0, 0, 0}; }
template <class Schema, class Container = MessageContainer<Schema>> template <class Schema, class Container = message_container<Schema>>
Error encode(typename Message<Schema, Container>::Reader reader, error encode(typename message<Schema, Container>::reader reader,
Buffer &buffer); buffer &buffer);
template <class Schema, class Container = MessageContainer<Schema>> template <class Schema, class Container = message_container<Schema>>
Error decode(typename Message<Schema, Container>::Builder builder, error decode(typename message<Schema, Container>::builder builder,
Buffer &buffer, const Limits &limits = Limits{}); buffer &buffer, const limits &lim = limits{});
}; };
template <class T> struct ProtoKelEncodeImpl; template <class T> struct proto_kel_encode_impl;
template <class T, size_t N, class Container> template <class T, size_t N, class Container>
struct ProtoKelEncodeImpl<Message<schema::Primitive<T, N>, Container>> { struct proto_kel_encode_impl<message<schema::Primitive<T, N>, Container>> {
static Error static error
encode(typename Message<schema::Primitive<T, N>, Container>::Reader data, encode(typename message<schema::Primitive<T, N>, Container>::reader data,
Buffer &buffer) { buffer &buffer) {
Error error = StreamValue<typename PrimitiveTypeHelper< error err = stream_value<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::encode(data.get(), buffer); schema::Primitive<T, N>>::Type>::encode(data.get(), buffer);
return error; return err;
} }
static size_t static size_t
size(typename Message<schema::Primitive<T, N>, Container>::Reader) { size(typename message<schema::Primitive<T, N>, Container>::reader) {
return StreamValue<typename PrimitiveTypeHelper< return stream_value<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::size(); schema::Primitive<T, N>>::Type>::size();
} }
}; };
template <class Container> template <class Container>
struct ProtoKelEncodeImpl<Message<schema::String, Container>> { struct proto_kel_encode_impl<message<schema::String, Container>> {
static Error static error
encode(typename Message<schema::String, Container>::Reader data, encode(typename message<schema::String, Container>::reader data,
Buffer &buffer) { buffer &buffer) {
std::string_view view = data.get(); std::string_view view = data.get();
size_t size = view.size(); size_t size = view.size();
Error error = buffer.writeRequireLength(sizeof(size) + size); error err = buffer.write_require_length(sizeof(size) + size);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
error = StreamValue<size_t>::encode(size, buffer); err = stream_value<size_t>::encode(size, buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
for (size_t i = 0; i < view.size(); ++i) { for (size_t i = 0; i < view.size(); ++i) {
buffer.write(i) = view[i]; buffer.write(i) = view[i];
} }
buffer.writeAdvance(view.size()); buffer.write_advance(view.size());
return noError(); return no_error();
} }
static size_t static size_t
size(typename Message<schema::String, Container>::Reader reader) { size(typename message<schema::String, Container>::reader reader) {
return sizeof(size_t) + reader.get().size(); return sizeof(size_t) + reader.get().size();
} }
}; };
template <class... T, class Container> template <class... T, class Container>
struct ProtoKelEncodeImpl<Message<schema::Tuple<T...>, Container>> { struct proto_kel_encode_impl<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 static typename std::enable_if<i == sizeof...(T), error>::type
encodeMembers(typename Message<schema::Tuple<T...>, Container>::Reader, encode_members(typename message<schema::Tuple<T...>, Container>::reader,
Buffer &) { buffer &) {
return noError(); return no_error();
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if<(i < sizeof...(T)), Error>::type static typename std::enable_if<(i < sizeof...(T)), error>::type
encodeMembers(typename Message<schema::Tuple<T...>, Container>::Reader data, encode_members(
Buffer &buffer) { typename message<schema::Tuple<T...>, Container>::reader data,
Error error = buffer &buffer) {
ProtoKelEncodeImpl<typename Container::template ElementType<i>>:: error err =
proto_kel_encode_impl<typename Container::template ElementType<i>>::
encode(data.template get<i>(), buffer); encode(data.template get<i>(), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
return encodeMembers<i + 1>(data, buffer); return encode_members<i + 1>(data, buffer);
} }
static Error static error
encode(typename Message<schema::Tuple<T...>, Container>::Reader data, encode(typename message<schema::Tuple<T...>, Container>::reader data,
Buffer &buffer) { buffer &buffer) {
return encodeMembers<0>(data, buffer); return encode_members<0>(data, buffer);
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if<i == sizeof...(T), size_t>::type static typename std::enable_if<i == sizeof...(T), size_t>::type
sizeMembers(typename Message<schema::Tuple<T...>, Container>::Reader) { size_members(typename message<schema::Tuple<T...>, Container>::reader) {
return 0; return 0;
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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) { typename message<schema::Tuple<T...>, Container>::reader reader) {
return ProtoKelEncodeImpl<typename Container::template ElementType<i>>:: return proto_kel_encode_impl<typename Container::template ElementType<
size(reader.template get<i>()) + i>>::size(reader.template get<i>()) +
sizeMembers<i + 1>(reader); size_members<i + 1>(reader);
} }
static size_t static size_t
size(typename Message<schema::Tuple<T...>, Container>::Reader reader) { size(typename message<schema::Tuple<T...>, Container>::reader reader) {
return sizeMembers<0>(reader); return size_members<0>(reader);
} }
}; };
template <typename... V, StringLiteral... K, class Container> template <typename... V, string_literal... K, class Container>
struct ProtoKelEncodeImpl< struct proto_kel_encode_impl<
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> { 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 static typename std::enable_if<i == sizeof...(V), error>::type
encodeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>, encode_members(
Container>::Reader, typename message<schema::Struct<schema::NamedMember<V, K>...>,
Buffer &) { Container>::reader,
return noError(); buffer &) {
return no_error();
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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>...>, typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader data, Container>::reader data,
Buffer &buffer) { buffer &buffer) {
Error error = error err =
ProtoKelEncodeImpl<typename Container::template ElementType<i>>:: proto_kel_encode_impl<typename Container::template ElementType<i>>::
encode(data.template get<i>(), buffer); encode(data.template get<i>(), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
return encodeMembers<i + 1>(data, buffer); return encode_members<i + 1>(data, buffer);
} }
static Error static error
encode(typename Message<schema::Struct<schema::NamedMember<V, K>...>, encode(typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader data, Container>::reader data,
Buffer &buffer) { buffer &buffer) {
return encodeMembers<0>(data, buffer); return encode_members<0>(data, buffer);
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), size_t>::type static typename std::enable_if<i == sizeof...(V), size_t>::type
sizeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>, size_members(typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader) { Container>::reader) {
return 0; return 0;
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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>...>, typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader reader) { Container>::reader reader) {
return ProtoKelEncodeImpl<typename Container::template ElementType<i>>:: return proto_kel_encode_impl<typename Container::template ElementType<
size(reader.template get<i>()) + i>>::size(reader.template get<i>()) +
sizeMembers<i + 1>(reader); size_members<i + 1>(reader);
} }
static size_t static size_t
size(typename Message<schema::Struct<schema::NamedMember<V, K>...>, size(typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader reader) { Container>::reader reader) {
return sizeMembers<0>(reader); return size_members<0>(reader);
} }
}; };
template <typename... V, StringLiteral... K, class Container> template <typename... V, string_literal... K, class Container>
struct ProtoKelEncodeImpl< struct proto_kel_encode_impl<
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> { 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 static typename std::enable_if<i == sizeof...(V), error>::type
encodeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>, encode_members(typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader, Container>::reader,
Buffer &) { buffer &) {
return noError(); return no_error();
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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>...>, typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader, Container>::reader reader,
Buffer &buffer) { buffer &buffer) {
if (reader.index() == i) { if (reader.index() == i) {
Error error = error err =
StreamValue<ProtoKelCodec::UnionIdT>::encode(i, buffer); stream_value<proto_kel_codec::UnionIdT>::encode(i, buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
return ProtoKelEncodeImpl<typename Container::template ElementType< return proto_kel_encode_impl<
i>>::encode(reader.template get<i>(), buffer); typename Container::template ElementType<i>>::
encode(reader.template get<i>(), buffer);
} }
return encodeMembers<i + 1>(reader, buffer); return encode_members<i + 1>(reader, buffer);
} }
static Error static error
encode(typename Message<schema::Union<schema::NamedMember<V, K>...>, encode(typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader, Container>::reader reader,
Buffer &buffer) { buffer &buffer) {
return encodeMembers<0>(reader, buffer); return encode_members<0>(reader, buffer);
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if<i == sizeof...(V), size_t>::type static typename std::enable_if<i == sizeof...(V), size_t>::type
sizeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>, size_members(typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader) { Container>::reader) {
return 0; return 0;
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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>...>, typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader) { Container>::reader reader) {
if (reader.index() == i) { if (reader.index() == i) {
return ProtoKelEncodeImpl<typename Container::template ElementType< return proto_kel_encode_impl<
i>>::size(reader.template get<i>()); typename Container::template ElementType<i>>::
size(reader.template get<i>());
} }
return sizeMembers<i + 1>(reader); return size_members<i + 1>(reader);
} }
/* /*
* Size of union id + member size * Size of union id + member size
*/ */
static size_t static size_t
size(typename Message<schema::Union<schema::NamedMember<V, K>...>, size(typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader) { Container>::reader reader) {
return sizeof(ProtoKelCodec::UnionIdT) + sizeMembers<0>(reader); return sizeof(proto_kel_codec::UnionIdT) + size_members<0>(reader);
} }
}; };
template <class T, class Container> template <class T, class Container>
struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> { struct proto_kel_encode_impl<message<schema::Array<T>, Container>> {
static Error static error
encode(typename Message<schema::Array<T>, Container>::Reader data, encode(typename message<schema::Array<T>, Container>::reader data,
Buffer &buffer) { buffer &buffer) {
ProtoKelCodec::ArrayLengthT array_length = data.size(); proto_kel_codec::ArrayLengthT array_length = data.size();
{ {
Error error = StreamValue<ProtoKelCodec::ArrayLengthT>::encode( error err = stream_value<proto_kel_codec::ArrayLengthT>::encode(
array_length, buffer); array_length, buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
for (size_t i = 0; i < array_length; ++i) { for (size_t i = 0; i < array_length; ++i) {
Error error = error err =
ProtoKelEncodeImpl<typename Container::ElementType>::encode( proto_kel_encode_impl<typename Container::ElementType>::encode(
data.get(i), buffer); data.get(i), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
return noError(); return no_error();
} }
/* /*
* *
*/ */
static size_t static size_t
size(typename Message<schema::Array<T>, Container>::Reader data) { size(typename message<schema::Array<T>, Container>::reader data) {
size_t members = sizeof(ProtoKelCodec::ArrayLengthT); size_t members = sizeof(proto_kel_codec::ArrayLengthT);
for (size_t i = 0; i < data.size(); ++i) { for (size_t i = 0; i < data.size(); ++i) {
members += members +=
ProtoKelEncodeImpl<typename Container::ElementType>::size( proto_kel_encode_impl<typename Container::ElementType>::size(
data.get(i)); data.get(i));
} }
@ -312,248 +316,249 @@ struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> {
/* /*
* Decode Implementations * Decode Implementations
*/ */
template <typename T> struct ProtoKelDecodeImpl; template <typename T> struct proto_kel_decode_impl;
template <class T, size_t N, class Container> template <class T, size_t N, class Container>
struct ProtoKelDecodeImpl<Message<schema::Primitive<T, N>, Container>> { struct proto_kel_decode_impl<message<schema::Primitive<T, N>, Container>> {
static Error static error
decode(typename Message<schema::Primitive<T, N>, Container>::Builder data, decode(typename message<schema::Primitive<T, N>, Container>::builder data,
Buffer &buffer) { buffer &buffer) {
typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type val = 0; typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type val = 0;
Error error = StreamValue<typename PrimitiveTypeHelper< error err = stream_value<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::decode(val, buffer); schema::Primitive<T, N>>::Type>::decode(val, buffer);
data.set(val); data.set(val);
return error; return err;
} }
}; };
template <class Container> template <class Container>
struct ProtoKelDecodeImpl<Message<schema::String, Container>> { struct proto_kel_decode_impl<message<schema::String, Container>> {
static Error static error
decode(typename Message<schema::String, Container>::Builder data, decode(typename message<schema::String, Container>::builder data,
Buffer &buffer) { buffer &buffer) {
size_t size = 0; size_t size = 0;
if (sizeof(size) > buffer.readCompositeLength()) { if (sizeof(size) > buffer.read_composite_length()) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
Error error = StreamValue<size_t>::decode(size, buffer); error err = stream_value<size_t>::decode(size, buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
if (size > buffer.readCompositeLength()) { if (size > buffer.read_composite_length()) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
std::string value; std::string value;
value.resize(size); value.resize(size);
if (size > buffer.readCompositeLength()) { if (size > buffer.read_composite_length()) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
for (size_t i = 0; i < value.size(); ++i) { for (size_t i = 0; i < value.size(); ++i) {
value[i] = buffer.read(i); value[i] = buffer.read(i);
} }
buffer.readAdvance(value.size()); buffer.read_advance(value.size());
data.set(std::move(value)); data.set(std::move(value));
return noError(); return no_error();
} }
}; };
template <class... T, class Container> template <class... T, class Container>
struct ProtoKelDecodeImpl<Message<schema::Tuple<T...>, Container>> { struct proto_kel_decode_impl<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 static typename std::enable_if<i == sizeof...(T), error>::type
decodeMembers(typename Message<schema::Tuple<T...>, Container>::Builder, decode_members(typename message<schema::Tuple<T...>, Container>::builder,
Buffer &) { buffer &) {
return noError(); return no_error();
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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, typename message<schema::Tuple<T...>, Container>::builder builder,
Buffer &buffer) { buffer &buffer) {
Error error = error err =
ProtoKelDecodeImpl<typename Container::template ElementType<i>>:: proto_kel_decode_impl<typename Container::template ElementType<i>>::
decode(builder.template init<i>(), buffer); decode(builder.template init<i>(), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
return decodeMembers<i + 1>(builder, buffer); return decode_members<i + 1>(builder, buffer);
} }
static Error static error
decode(typename Message<schema::Tuple<T...>, Container>::Builder builder, decode(typename message<schema::Tuple<T...>, Container>::builder builder,
Buffer &buffer) { buffer &buffer) {
return decodeMembers<0>(builder, buffer); return decode_members<0>(builder, buffer);
} }
}; };
template <class... V, StringLiteral... K, class Container> template <class... V, string_literal... K, class Container>
struct ProtoKelDecodeImpl< struct proto_kel_decode_impl<
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> { 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 static typename std::enable_if<i == sizeof...(V), error>::type
decodeMembers(typename Message<schema::Struct<schema::NamedMember<V, K>...>, decode_members(
Container>::Builder, typename message<schema::Struct<schema::NamedMember<V, K>...>,
Buffer &) { Container>::builder,
return noError(); buffer &) {
return no_error();
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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>...>, typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder builder, Container>::builder builder,
Buffer &buffer) { buffer &buffer) {
Error error = error err =
ProtoKelDecodeImpl<typename Container::template ElementType<i>>:: proto_kel_decode_impl<typename Container::template ElementType<i>>::
decode(builder.template init<i>(), buffer); decode(builder.template init<i>(), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
return decodeMembers<i + 1>(builder, buffer); return decode_members<i + 1>(builder, buffer);
} }
static Error static error
decode(typename Message<schema::Struct<schema::NamedMember<V, K>...>, decode(typename message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder builder, Container>::builder builder,
Buffer &buffer) { buffer &buffer) {
return decodeMembers<0>(builder, buffer); return decode_members<0>(builder, buffer);
} }
}; };
template <class... V, StringLiteral... K, class Container> template <class... V, string_literal... K, class Container>
struct ProtoKelDecodeImpl< struct proto_kel_decode_impl<
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> { 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 static typename std::enable_if<i == sizeof...(V), error>::type
decodeMembers(typename Message<schema::Union<schema::NamedMember<V, K>...>, decode_members(typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder, Container>::builder,
Buffer &, ProtoKelCodec::UnionIdT) { buffer &, proto_kel_codec::UnionIdT) {
return noError(); return no_error();
} }
template <size_t i = 0> template <size_t i = 0>
static typename std::enable_if < 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>...>, typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder builder, Container>::builder builder,
Buffer &buffer, ProtoKelCodec::UnionIdT id) { buffer &buffer, proto_kel_codec::UnionIdT id) {
if (id == i) { if (id == i) {
Error error = error err =
ProtoKelDecodeImpl<typename Container::template ElementType< proto_kel_decode_impl<typename Container::template ElementType<
i>>::decode(builder.template init<i>(), buffer); i>>::decode(builder.template init<i>(), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
return decodeMembers<i + 1>(builder, buffer, id); return decode_members<i + 1>(builder, buffer, id);
} }
static Error static error
decode(typename Message<schema::Union<schema::NamedMember<V, K>...>, decode(typename message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder builder, Container>::builder builder,
Buffer &buffer) { buffer &buffer) {
ProtoKelCodec::UnionIdT id = 0; proto_kel_codec::UnionIdT id = 0;
Error error = StreamValue<ProtoKelCodec::UnionIdT>::decode(id, buffer); error err = stream_value<proto_kel_codec::UnionIdT>::decode(id, buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
if (id >= sizeof...(V)) { if (id >= sizeof...(V)) {
return criticalError("Union doesn't have this many id's"); return critical_error("Union doesn't have this many id's");
} }
return decodeMembers<0>(builder, buffer, id); return decode_members<0>(builder, buffer, id);
} }
}; };
template <class T, class Container> template <class T, class Container>
struct ProtoKelDecodeImpl<Message<schema::Array<T>, Container>> { struct proto_kel_decode_impl<message<schema::Array<T>, Container>> {
static Error static error
decode(typename Message<schema::Array<T>, Container>::Builder data, decode(typename message<schema::Array<T>, Container>::builder data,
Buffer &buffer) { buffer &buffer) {
ProtoKelCodec::ArrayLengthT array_length = 0; proto_kel_codec::ArrayLengthT array_length = 0;
{ {
Error error = StreamValue<ProtoKelCodec::ArrayLengthT>::decode( error err = stream_value<proto_kel_codec::ArrayLengthT>::decode(
array_length, buffer); array_length, buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
data.resize(array_length); data.resize(array_length);
for (size_t i = 0; i < array_length; ++i) { for (size_t i = 0; i < array_length; ++i) {
Error error = error err =
ProtoKelDecodeImpl<typename Container::ElementType>::decode( proto_kel_decode_impl<typename Container::ElementType>::decode(
data.init(i), buffer); data.init(i), buffer);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
return noError(); return no_error();
} }
}; };
template <class Schema, class Container> template <class Schema, class Container>
Error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader, error proto_kel_codec::encode(
Buffer &buffer) { typename message<Schema, Container>::reader reader, buffer &buffer) {
BufferView view{buffer}; buffer_view view{buffer};
ProtoKelCodec::PacketLengthT packet_length = proto_kel_codec::PacketLengthT packet_length =
ProtoKelEncodeImpl<Message<Schema, Container>>::size(reader); proto_kel_encode_impl<message<Schema, Container>>::size(reader);
// Check the size of the packet for the first // Check the size of the packet for the first
// message length description // message length description
Error error = view.writeRequireLength(packet_length + error err = view.write_require_length(
sizeof(ProtoKelCodec::PacketLengthT)); packet_length + sizeof(proto_kel_codec::PacketLengthT));
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
{ {
Error error = StreamValue<ProtoKelCodec::PacketLengthT>::encode( error err = stream_value<proto_kel_codec::PacketLengthT>::encode(
packet_length, view); packet_length, view);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
{ {
Error error = ProtoKelEncodeImpl<Message<Schema, Container>>::encode( error err = proto_kel_encode_impl<message<Schema, Container>>::encode(
reader, view); reader, view);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
buffer.writeAdvance(view.writeOffset()); buffer.write_advance(view.write_offset());
return noError(); return no_error();
} }
template <class Schema, class Container> template <class Schema, class Container>
Error ProtoKelCodec::decode( error proto_kel_codec::decode(
typename Message<Schema, Container>::Builder builder, Buffer &buffer, typename message<Schema, Container>::builder builder, buffer &buffer,
const Limits &limits) { const limits &limits) {
BufferView view{buffer}; buffer_view view{buffer};
ProtoKelCodec::PacketLengthT packet_length = 0; proto_kel_codec::PacketLengthT packet_length = 0;
{ {
Error error = StreamValue<ProtoKelCodec::PacketLengthT>::decode( error err = stream_value<proto_kel_codec::PacketLengthT>::decode(
packet_length, view); packet_length, view);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
if (packet_length > limits.packet_size) { if (packet_length > limits.packet_size) {
return criticalError( return critical_error(
[packet_length]() { [packet_length]() {
return std::string{"Packet size too big: "} + return std::string{"Packet size too big: "} +
std::to_string(packet_length); std::to_string(packet_length);
@ -562,21 +567,21 @@ Error ProtoKelCodec::decode(
} }
{ {
Error error = ProtoKelDecodeImpl<Message<Schema, Container>>::decode( error err = proto_kel_decode_impl<message<Schema, Container>>::decode(
builder, view); builder, view);
if (error.failed()) { if (err.failed()) {
return error; return err;
} }
} }
{ {
if (ProtoKelEncodeImpl<Message<Schema, Container>>::size( if (proto_kel_encode_impl<message<Schema, Container>>::size(
builder.asReader()) != packet_length) { builder.as_reader()) != packet_length) {
return criticalError("Bad packet format"); return critical_error("Bad packet format");
} }
} }
buffer.readAdvance(view.readOffset()); buffer.read_advance(view.read_offset());
return noError(); return no_error();
} }
} // namespace saw } // namespace saw

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include "string_literal.h"
#include "common.h" #include "common.h"
#include "string_literal.h"
namespace saw { namespace saw {
namespace schema { namespace schema {
// NOLINTBEGIN
template <typename T, StringLiteral Literal> struct NamedMember {}; template <typename T, string_literal Literal> struct NamedMember {};
template <typename... T> struct Struct { template <typename... T> struct Struct {
static_assert( static_assert(
@ -14,7 +14,7 @@ template <typename... T> struct Struct {
"This schema template doesn't support this type of template argument"); "This schema template doesn't support this type of template argument");
}; };
template <typename... V, StringLiteral... K> template <typename... V, string_literal... K>
struct Struct<NamedMember<V, K>...> {}; struct Struct<NamedMember<V, K>...> {};
template <typename... T> struct Union { template <typename... T> struct Union {
@ -23,7 +23,7 @@ template <typename... T> struct Union {
"This schema template doesn't support this type of template argument"); "This schema template doesn't support this type of template argument");
}; };
template <typename... V, StringLiteral... K> template <typename... V, string_literal... K>
struct Union<NamedMember<V, K>...> {}; struct Union<NamedMember<V, K>...> {};
template <typename T> struct Array {}; template <typename T> struct Array {};
@ -60,7 +60,7 @@ using Float64 = Primitive<FloatingPoint, 8>;
/** /**
* Classes enabling Rpc calls * Classes enabling Rpc calls
*/ */
template <class Request, class Response, StringLiteral Literal> template <class Request, class Response, string_literal Literal>
struct Function {}; struct Function {};
template <class... T> struct Interface { template <class... T> struct Interface {
@ -69,8 +69,9 @@ template <class... T> struct Interface {
"This schema template doesn't support this type of template argument"); "This schema template doesn't support this type of template argument");
}; };
template <class... Request, class... Response, StringLiteral... Literal> template <class... Request, class... Response, string_literal... Literal>
struct Interface<Function<Request, Response, Literal>...> {}; struct Interface<Function<Request, Response, Literal>...> {};
// NOLINTEND
} // namespace schema } // namespace schema
} // namespace saw } // namespace saw

View File

@ -15,16 +15,16 @@ namespace saw {
* platform independent. So it does not matter if the memory layout is * platform independent. So it does not matter if the memory layout is
* little endian or big endian * little endian or big endian
*/ */
template <typename T, size_t size = sizeof(T)> class ShiftStreamValue; template <typename T, size_t size = sizeof(T)> class shift_stream_value;
template <typename T> class ShiftStreamValue<T, 1> { template <typename T> class shift_stream_value<T, 1> {
public: 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); uint8_t &raw = reinterpret_cast<uint8_t &>(val);
return buffer.pop(raw, sizeof(T)); 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); const uint8_t &raw = reinterpret_cast<const uint8_t &>(val);
return buffer.push(raw, sizeof(T)); return buffer.push(raw, sizeof(T));
} }
@ -32,11 +32,11 @@ public:
inline static size_t size() { return sizeof(T); } inline static size_t size() { return sizeof(T); }
}; };
template <typename T> class ShiftStreamValue<T, 2> { template <typename T> class shift_stream_value<T, 2> {
public: public:
inline static Error decode(T &val, Buffer &buffer) { inline static error decode(T &val, buffer &buffer) {
if (buffer.readCompositeLength() < sizeof(T)) { if (buffer.read_composite_length() < sizeof(T)) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
uint16_t raw = 0; uint16_t raw = 0;
@ -45,13 +45,13 @@ public:
raw |= (static_cast<uint16_t>(buffer.read(i)) << (i * 8)); raw |= (static_cast<uint16_t>(buffer.read(i)) << (i * 8));
} }
memcpy(&val, &raw, sizeof(T)); 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) { inline static error encode(const T &val, buffer &buffer) {
Error error = buffer.writeRequireLength(sizeof(T)); error error = buffer.write_require_length(sizeof(T));
if (error.failed()) { if (error.failed()) {
return error; return error;
} }
@ -63,18 +63,18 @@ public:
buffer.write(i) = raw >> (i * 8); buffer.write(i) = raw >> (i * 8);
} }
buffer.writeAdvance(sizeof(T)); buffer.write_advance(sizeof(T));
return noError(); return no_error();
} }
inline static size_t size() { return sizeof(T); } inline static size_t size() { return sizeof(T); }
}; };
template <typename T> class ShiftStreamValue<T, 4> { template <typename T> class shift_stream_value<T, 4> {
public: public:
inline static Error decode(T &val, Buffer &buffer) { inline static error decode(T &val, buffer &buffer) {
if (buffer.readCompositeLength() < sizeof(T)) { if (buffer.read_composite_length() < sizeof(T)) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
uint32_t raw = 0; uint32_t raw = 0;
@ -83,13 +83,13 @@ public:
raw |= (static_cast<uint32_t>(buffer.read(i)) << (i * 8)); raw |= (static_cast<uint32_t>(buffer.read(i)) << (i * 8));
} }
memcpy(&val, &raw, sizeof(T)); 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) { inline static error encode(const T &val, buffer &buffer) {
Error error = buffer.writeRequireLength(sizeof(T)); error error = buffer.write_require_length(sizeof(T));
if (error.failed()) { if (error.failed()) {
return error; return error;
} }
@ -101,18 +101,18 @@ public:
buffer.write(i) = raw >> (i * 8); buffer.write(i) = raw >> (i * 8);
} }
buffer.writeAdvance(sizeof(T)); buffer.write_advance(sizeof(T));
return noError(); return no_error();
} }
inline static size_t size() { return sizeof(T); } inline static size_t size() { return sizeof(T); }
}; };
template <typename T> class ShiftStreamValue<T, 8> { template <typename T> class shift_stream_value<T, 8> {
public: public:
inline static Error decode(T &val, Buffer &buffer) { inline static error decode(T &val, buffer &buffer) {
if (buffer.readCompositeLength() < sizeof(T)) { if (buffer.read_composite_length() < sizeof(T)) {
return recoverableError("Buffer too small"); return recoverable_error("Buffer too small");
} }
uint64_t raw = 0; uint64_t raw = 0;
@ -122,13 +122,13 @@ public:
} }
memcpy(&val, &raw, sizeof(T)); 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) { inline static error encode(const T &val, buffer &buffer) {
Error error = buffer.writeRequireLength(sizeof(T)); error error = buffer.write_require_length(sizeof(T));
if (error.failed()) { if (error.failed()) {
return error; return error;
} }
@ -140,13 +140,13 @@ public:
buffer.write(i) = raw >> (i * 8); buffer.write(i) = raw >> (i * 8);
} }
buffer.writeAdvance(sizeof(T)); buffer.write_advance(sizeof(T));
return noError(); return no_error();
} }
inline static size_t size() { return sizeof(T); } inline static size_t size() { return sizeof(T); }
}; };
template <typename T> using StreamValue = ShiftStreamValue<T>; template <typename T> using stream_value = shift_stream_value<T>;
} // namespace saw } // namespace saw

View File

@ -9,9 +9,9 @@ namespace saw {
* literal. It guarantees compile time uniqueness and thus allows using strings * literal. It guarantees compile time uniqueness and thus allows using strings
* in template parameters. * in template parameters.
*/ */
template <class CharT, size_t N> class StringLiteral { template <class CharT, size_t N> class string_literal {
public: public:
constexpr StringLiteral(const CharT (&input)[N]) noexcept { constexpr string_literal(const CharT (&input)[N]) noexcept {
for (size_t i = 0; i < N; ++i) { for (size_t i = 0; i < N; ++i) {
data[i] = input[i]; data[i] = input[i];
} }
@ -24,17 +24,17 @@ public:
} }
constexpr bool constexpr bool
operator==(const StringLiteral<CharT, N> &) const noexcept = default; operator==(const string_literal<CharT, N> &) const noexcept = default;
template <class CharTR, size_t NR> template <class CharTR, size_t NR>
constexpr bool constexpr bool
operator==(const StringLiteral<CharTR, NR> &) const noexcept { operator==(const string_literal<CharTR, NR> &) const noexcept {
return false; return false;
} }
}; };
template <typename T, T... Chars> template <typename T, T... Chars>
constexpr StringLiteral<T, sizeof...(Chars)> operator""_key() { constexpr string_literal<T, sizeof...(Chars)> operator""_key() {
return StringLiteral<T, sizeof...(Chars) + 1u>{Chars..., '\0'}; return string_literal<T, sizeof...(Chars) + 1u>{Chars..., '\0'};
} }
} // namespace saw } // namespace saw

View File

@ -38,60 +38,60 @@ Tls::~Tls() {}
Tls::Impl &Tls::getImpl() { return *impl; } Tls::Impl &Tls::getImpl() { return *impl; }
class TlsIoStream final : public IoStream { class TlsIoStream final : public io_stream {
private: private:
Own<IoStream> internal; own<io_stream> internal;
gnutls_session_t session_handle; gnutls_session_t session_handle;
public: public:
TlsIoStream(Own<IoStream> internal_) : internal{std::move(internal_)} {} TlsIoStream(own<io_stream> internal_) : internal{std::move(internal_)} {}
~TlsIoStream() { gnutls_bye(session_handle, GNUTLS_SHUT_RDWR); } ~TlsIoStream() { gnutls_bye(session_handle, GNUTLS_SHUT_RDWR); }
ErrorOr<size_t> read(void *buffer, size_t length) override { error_or<size_t> read(void *buffer, size_t length) override {
ssize_t size = gnutls_record_recv(session_handle, buffer, length); ssize_t size = gnutls_record_recv(session_handle, buffer, length);
if (size < 0) { if (size < 0) {
if(gnutls_error_is_fatal(size) == 0){ if(gnutls_error_is_fatal(size) == 0){
return recoverableError([size](){return std::string{"Read recoverable Error "}+std::string{gnutls_strerror(size)};}, "Error read r"); return recoverable_error([size](){return std::string{"Read recoverable Error "}+std::string{gnutls_strerror(size)};}, "Error read r");
}else{ }else{
return criticalError([size](){return std::string{"Read critical Error "}+std::string{gnutls_strerror(size)};}, "Error read c"); return critical_error([size](){return std::string{"Read critical Error "}+std::string{gnutls_strerror(size)};}, "Error read c");
} }
}else if(size == 0){ }else if(size == 0){
return criticalError("Disconnected"); return critical_error("Disconnected");
} }
return static_cast<size_t>(length); return static_cast<size_t>(length);
} }
Conveyor<void> readReady() override { return internal->readReady(); } conveyor<void> read_ready() override { return internal->read_ready(); }
Conveyor<void> onReadDisconnected() override { conveyor<void> on_read_disconnected() override {
return internal->onReadDisconnected(); return internal->on_read_disconnected();
} }
ErrorOr<size_t> write(const void *buffer, size_t length) override { error_or<size_t> write(const void *buffer, size_t length) override {
ssize_t size = gnutls_record_send(session_handle, buffer, length); ssize_t size = gnutls_record_send(session_handle, buffer, length);
if(size < 0){ if(size < 0){
if(gnutls_error_is_fatal(size) == 0){ if(gnutls_error_is_fatal(size) == 0){
return recoverableError([size](){return std::string{"Write recoverable Error "}+std::string{gnutls_strerror(size)} + " " + std::to_string(size);}, "Error write r"); return recoverable_error([size](){return std::string{"Write recoverable Error "}+std::string{gnutls_strerror(size)} + " " + std::to_string(size);}, "Error write r");
}else{ }else{
return criticalError([size](){return std::string{"Write critical Error "}+std::string{gnutls_strerror(size)} + " " + std::to_string(size);}, "Error write c"); return critical_error([size](){return std::string{"Write critical Error "}+std::string{gnutls_strerror(size)} + " " + std::to_string(size);}, "Error write c");
} }
} }
return static_cast<size_t>(size); return static_cast<size_t>(size);
} }
Conveyor<void> writeReady() override { return internal->writeReady(); } conveyor<void> write_ready() override { return internal->write_ready(); }
gnutls_session_t &session() { return session_handle; } gnutls_session_t &session() { return session_handle; }
}; };
TlsServer::TlsServer(Own<Server> srv) : internal{std::move(srv)} {} TlsServer::TlsServer(own<server> srv) : internal{std::move(srv)} {}
Conveyor<Own<IoStream>> TlsServer::accept() { conveyor<own<io_stream>> TlsServer::accept() {
SAW_ASSERT(internal) { return Conveyor<Own<IoStream>>{FixVoid<Own<IoStream>>{nullptr}}; } SAW_ASSERT(internal) { return conveyor<own<io_stream>>{fix_void<own<io_stream>>{nullptr}}; }
return internal->accept().then([](Own<IoStream> stream) -> Own<IoStream> { return internal->accept().then([](own<io_stream> stream) -> own<io_stream> {
/// @todo handshake /// @todo handshake
@ -105,14 +105,14 @@ namespace {
*/ */
struct TlsClientStreamHelper { struct TlsClientStreamHelper {
public: public:
Own<ConveyorFeeder<Own<IoStream>>> feeder; own<conveyor_feeder<own<io_stream>>> feeder;
ConveyorSink connection_sink; conveyor_sink connection_sink;
ConveyorSink stream_reader; conveyor_sink stream_reader;
ConveyorSink stream_writer; conveyor_sink stream_writer;
Own<TlsIoStream> stream = nullptr; own<TlsIoStream> stream = nullptr;
public: public:
TlsClientStreamHelper(Own<ConveyorFeeder<Own<IoStream>>> f): TlsClientStreamHelper(own<conveyor_feeder<own<io_stream>>> f):
feeder{std::move(f)} feeder{std::move(f)}
{} {}
@ -121,11 +121,11 @@ public:
return; return;
} }
stream_reader = stream->readReady().then([this](){ stream_reader = stream->read_ready().then([this](){
turn(); turn();
}).sink(); }).sink();
stream_writer = stream->writeReady().then([this](){ stream_writer = stream->write_ready().then([this](){
turn(); turn();
}).sink(); }).sink();
} }
@ -145,7 +145,7 @@ public:
} while ( (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) && gnutls_error_is_fatal(ret) == 0); } while ( (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) && gnutls_error_is_fatal(ret) == 0);
if(gnutls_error_is_fatal(ret)){ if(gnutls_error_is_fatal(ret)){
feeder->fail(criticalError("Couldn't create Tls connection")); feeder->fail(critical_error("Couldn't create Tls connection"));
stream = nullptr; stream = nullptr;
}else if(ret == GNUTLS_E_SUCCESS){ }else if(ret == GNUTLS_E_SUCCESS){
feeder->feed(std::move(stream)); feeder->feed(std::move(stream));
@ -155,20 +155,20 @@ public:
}; };
} }
Own<Server> TlsNetwork::listen(NetworkAddress& address) { own<server> TlsNetwork::listen(network_address& address) {
return heap<TlsServer>(internal.listen(address)); return heap<TlsServer>(internal.listen(address));
} }
Conveyor<Own<IoStream>> TlsNetwork::connect(NetworkAddress& address) { conveyor<own<io_stream>> TlsNetwork::connect(network_address& address) {
// Helper setups // Helper setups
auto caf = newConveyorAndFeeder<Own<IoStream>>(); auto caf = new_conveyor_and_feeder<own<io_stream>>();
Own<TlsClientStreamHelper> helper = heap<TlsClientStreamHelper>(std::move(caf.feeder)); own<TlsClientStreamHelper> helper = heap<TlsClientStreamHelper>(std::move(caf.feeder));
TlsClientStreamHelper* hlp_ptr = helper.get(); TlsClientStreamHelper* hlp_ptr = helper.get();
// Conveyor entangled structure // Conveyor entangled structure
auto prim_conv = internal.connect(address).then([this, hlp_ptr, addr = address.address()]( auto prim_conv = internal.connect(address).then([this, hlp_ptr, addr = address.address()](
Own<IoStream> stream) -> ErrorOr<void> { own<io_stream> stream) -> error_or<void> {
IoStream* inner_stream = stream.get(); io_stream* inner_stream = stream.get();
auto tls_stream = heap<TlsIoStream>(std::move(stream)); auto tls_stream = heap<TlsIoStream>(std::move(stream));
auto &session = tls_stream->session(); auto &session = tls_stream->session();
@ -193,7 +193,7 @@ Conveyor<Own<IoStream>> TlsNetwork::connect(NetworkAddress& address) {
hlp_ptr->setupTurn(); hlp_ptr->setupTurn();
hlp_ptr->turn(); hlp_ptr->turn();
return Void{}; return void_t{};
}); });
helper->connection_sink = prim_conv.sink(); helper->connection_sink = prim_conv.sink();
@ -201,20 +201,20 @@ Conveyor<Own<IoStream>> TlsNetwork::connect(NetworkAddress& address) {
return caf.conveyor.attach(std::move(helper)); return caf.conveyor.attach(std::move(helper));
} }
Own<Datagram> TlsNetwork::datagram(NetworkAddress& address){ own<datagram> TlsNetwork::datagram(network_address& address){
///@unimplemented ///@unimplemented
return nullptr; return nullptr;
} }
static ssize_t forst_tls_push_func(gnutls_transport_ptr_t p, const void *data, static ssize_t forst_tls_push_func(gnutls_transport_ptr_t p, const void *data,
size_t size) { size_t size) {
IoStream *stream = reinterpret_cast<IoStream *>(p); io_stream *stream = reinterpret_cast<io_stream *>(p);
if (!stream) { if (!stream) {
return -1; return -1;
} }
ErrorOr<size_t> length = stream->write(data, size); error_or<size_t> length = stream->write(data, size);
if (length.isError() || !length.isValue()) { if (length.is_error() || !length.is_value()) {
return -1; return -1;
} }
@ -222,29 +222,29 @@ static ssize_t forst_tls_push_func(gnutls_transport_ptr_t p, const void *data,
} }
static ssize_t forst_tls_pull_func(gnutls_transport_ptr_t p, void *data, size_t size) { static ssize_t forst_tls_pull_func(gnutls_transport_ptr_t p, void *data, size_t size) {
IoStream *stream = reinterpret_cast<IoStream *>(p); io_stream *stream = reinterpret_cast<io_stream *>(p);
if (!stream) { if (!stream) {
return -1; return -1;
} }
ErrorOr<size_t> length = stream->read(data, size); error_or<size_t> length = stream->read(data, size);
if (length.isError() || !length.isValue()) { if (length.is_error() || !length.is_value()) {
return -1; return -1;
} }
return static_cast<ssize_t>(length.value()); return static_cast<ssize_t>(length.value());
} }
TlsNetwork::TlsNetwork(Tls& tls_, Network &network) : tls{tls_},internal{network} {} TlsNetwork::TlsNetwork(Tls& tls_, network &network) : tls{tls_},internal{network} {}
Conveyor<Own<NetworkAddress>> TlsNetwork::resolveAddress(const std::string &addr, conveyor<own<network_address>> TlsNetwork::resolve_address(const std::string &addr,
uint16_t port) { uint16_t port) {
/// @todo tls server name needed. Check validity. Won't matter later on, because gnutls should fail anyway. But /// @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 /// it's better to find the error source sooner rather than later
return internal.resolveAddress(addr, port); return internal.resolve_address(addr, port);
} }
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network) { std::optional<own<TlsNetwork>> setupTlsNetwork(network &network) {
return std::nullopt; return std::nullopt;
} }
} // namespace saw } // namespace saw

View File

@ -9,30 +9,30 @@
namespace saw { namespace saw {
class Tls; class Tls;
class TlsServer final : public Server { class TlsServer final : public server {
private: private:
Own<Server> internal; own<server> internal;
public: public:
TlsServer(Own<Server> srv); TlsServer(own<server> srv);
Conveyor<Own<IoStream>> accept() override; conveyor<own<io_stream>> accept() override;
}; };
class TlsNetwork final : public Network { class TlsNetwork final : public network {
private: private:
Tls& tls; Tls& tls;
Network &internal; network &internal;
public: public:
TlsNetwork(Tls& tls_, Network &network_); TlsNetwork(Tls& tls_, network &network_);
Conveyor<Own<NetworkAddress>> resolveAddress(const std::string &addr, uint16_t port = 0) override; conveyor<own<network_address>> resolve_address(const std::string &addr, uint16_t port = 0) override;
Own<Server> listen(NetworkAddress& address) override; own<server> listen(network_address& address) override;
Conveyor<Own<IoStream>> connect(NetworkAddress& address) override; conveyor<own<io_stream>> connect(network_address& address) override;
Own<Datagram> datagram(NetworkAddress& address) override; own<class datagram> datagram(network_address& address) override;
}; };
/** /**
@ -42,7 +42,7 @@ public:
class Tls { class Tls {
private: private:
class Impl; class Impl;
Own<Impl> impl; own<Impl> impl;
public: public:
Tls(); Tls();
~Tls(); ~Tls();
@ -58,13 +58,13 @@ public:
Version version; Version version;
}; };
Network& tlsNetwork(); network& tlsNetwork();
Impl &getImpl(); Impl &getImpl();
private: private:
Options options; Options options;
}; };
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network); std::optional<own<TlsNetwork>> setupTlsNetwork(network &network);
} // namespace saw } // namespace saw

View File

@ -6,38 +6,38 @@ namespace {
SAW_TEST("Async Immediate"){ SAW_TEST("Async Immediate"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
Conveyor<size_t> number{5}; conveyor<size_t> number{5};
Conveyor<bool> is_number = number.then([](size_t val){ conveyor<bool> is_number = number.then([](size_t val){
return val == 5; return val == 5;
}); });
wait_scope.poll(); wait_scope.poll();
ErrorOr<bool> error_or_number = is_number.take(); error_or<bool> error_or_number = is_number.take();
SAW_EXPECT(!error_or_number.isError(), error_or_number.error().message()); SAW_EXPECT(!error_or_number.is_error(), error_or_number.error().message());
SAW_EXPECT(error_or_number.isValue(), "Return is not a value"); SAW_EXPECT(error_or_number.is_value(), "Return is not a value");
SAW_EXPECT(error_or_number.value(), "Value is not 5"); SAW_EXPECT(error_or_number.value(), "Value is not 5");
} }
SAW_TEST("Async Adapt"){ SAW_TEST("Async Adapt"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto feeder_conveyor = newConveyorAndFeeder<size_t>(); auto feeder_conveyor = new_conveyor_and_feeder<size_t>();
feeder_conveyor.feeder->feed(5); feeder_conveyor.feeder->feed(5);
ErrorOr<size_t> foo = feeder_conveyor.conveyor.take(); error_or<size_t> foo = feeder_conveyor.conveyor.take();
SAW_EXPECT(!foo.isError(), foo.error().message()); SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.isValue(), "Return is not a value"); SAW_EXPECT(foo.is_value(), "Return is not a value");
SAW_EXPECT(foo.value() == 5, "Values not 5, but " + std::to_string(foo.value())); SAW_EXPECT(foo.value() == 5, "Values not 5, but " + std::to_string(foo.value()));
} }
@ -45,72 +45,72 @@ SAW_TEST("Async Adapt"){
SAW_TEST("Async Adapt Multiple"){ SAW_TEST("Async Adapt Multiple"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto feeder_conveyor = newConveyorAndFeeder<size_t>(); auto feeder_conveyor = new_conveyor_and_feeder<size_t>();
feeder_conveyor.feeder->feed(5); feeder_conveyor.feeder->feed(5);
ErrorOr<size_t> foo = feeder_conveyor.conveyor.take(); error_or<size_t> foo = feeder_conveyor.conveyor.take();
SAW_EXPECT(!foo.isError(), foo.error().message()); SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.isValue(), "Return is not a value"); SAW_EXPECT(foo.is_value(), "Return is not a value");
SAW_EXPECT(foo.value() == 5, "Values not 5, but " + std::to_string(foo.value())); SAW_EXPECT(foo.value() == 5, "Values not 5, but " + std::to_string(foo.value()));
feeder_conveyor.feeder->feed(10); feeder_conveyor.feeder->feed(10);
ErrorOr<size_t> bar = feeder_conveyor.conveyor.take(); error_or<size_t> bar = feeder_conveyor.conveyor.take();
SAW_EXPECT(!foo.isError(), bar.error().message()); SAW_EXPECT(!foo.is_error(), bar.error().message());
SAW_EXPECT(bar.isValue(), "Return is not a value"); SAW_EXPECT(bar.is_value(), "Return is not a value");
SAW_EXPECT(bar.value() == 10, "Values not 10, but " + std::to_string(bar.value())); SAW_EXPECT(bar.value() == 10, "Values not 10, but " + std::to_string(bar.value()));
feeder_conveyor.feeder->feed(2); feeder_conveyor.feeder->feed(2);
feeder_conveyor.feeder->feed(4234); feeder_conveyor.feeder->feed(4234);
ErrorOr<size_t> a = feeder_conveyor.conveyor.take(); error_or<size_t> a = feeder_conveyor.conveyor.take();
ErrorOr<size_t> b = feeder_conveyor.conveyor.take(); error_or<size_t> b = feeder_conveyor.conveyor.take();
SAW_EXPECT(!foo.isError(), a.error().message()); SAW_EXPECT(!foo.is_error(), a.error().message());
SAW_EXPECT(a.isValue(), "Return is not a value"); SAW_EXPECT(a.is_value(), "Return is not a value");
SAW_EXPECT(a.value() == 2, "Values not 2, but " + std::to_string(a.value())); SAW_EXPECT(a.value() == 2, "Values not 2, but " + std::to_string(a.value()));
SAW_EXPECT(!foo.isError(), b.error().message()); SAW_EXPECT(!foo.is_error(), b.error().message());
SAW_EXPECT(b.isValue(), "Return is not a value"); SAW_EXPECT(b.is_value(), "Return is not a value");
SAW_EXPECT(b.value() == 4234, "Values not 4234, but " + std::to_string(b.value())); SAW_EXPECT(b.value() == 4234, "Values not 4234, but " + std::to_string(b.value()));
} }
SAW_TEST("Async Conversion"){ SAW_TEST("Async Conversion"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto feeder_conveyor = newConveyorAndFeeder<size_t>(); auto feeder_conveyor = new_conveyor_and_feeder<size_t>();
Conveyor<std::string> string_conveyor = feeder_conveyor.conveyor.then([](size_t foo){ conveyor<std::string> string_conveyor = feeder_conveyor.conveyor.then([](size_t foo){
return std::to_string(foo); return std::to_string(foo);
}); });
feeder_conveyor.feeder->feed(10); feeder_conveyor.feeder->feed(10);
ErrorOr<std::string> foo = string_conveyor.take(); error_or<std::string> foo = string_conveyor.take();
SAW_EXPECT(!foo.isError(), foo.error().message()); SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.isValue(), "Return is not a value"); SAW_EXPECT(foo.is_value(), "Return is not a value");
SAW_EXPECT(foo.value() == std::to_string(10), "Values is not 10, but " + foo.value()); SAW_EXPECT(foo.value() == std::to_string(10), "Values is not 10, but " + foo.value());
} }
SAW_TEST("Async Conversion Multistep"){ SAW_TEST("Async Conversion Multistep"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto feeder_conveyor = newConveyorAndFeeder<size_t>(); auto feeder_conveyor = new_conveyor_and_feeder<size_t>();
Conveyor<bool> conveyor = feeder_conveyor.conveyor.then([](size_t foo){ conveyor<bool> conveyor = feeder_conveyor.conveyor.then([](size_t foo){
return std::to_string(foo); return std::to_string(foo);
}).then([](const std::string& value){ }).then([](const std::string& value){
return value != "10"; return value != "10";
@ -120,29 +120,29 @@ SAW_TEST("Async Conversion Multistep"){
feeder_conveyor.feeder->feed(10); feeder_conveyor.feeder->feed(10);
ErrorOr<bool> foo = conveyor.take(); error_or<bool> foo = conveyor.take();
SAW_EXPECT(!foo.isError(), foo.error().message()); SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.isValue(), "Return is not a value"); SAW_EXPECT(foo.is_value(), "Return is not a value");
SAW_EXPECT(foo.value(), "Values is not true"); SAW_EXPECT(foo.value(), "Values is not true");
} }
SAW_TEST("Async Scheduling"){ SAW_TEST("Async Scheduling"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto feeder_conveyor = newConveyorAndFeeder<size_t>(); auto feeder_conveyor = new_conveyor_and_feeder<size_t>();
/* /*
* Attach node test data * Attach node test data
*/ */
Own<size_t> counter = heap<size_t>(); own<size_t> counter = heap<size_t>();
size_t* ctr_ptr = counter.get(); size_t* ctr_ptr = counter.get();
*ctr_ptr = 0; *ctr_ptr = 0;
Conveyor<std::string> string_conveyor = feeder_conveyor.conveyor conveyor<std::string> string_conveyor = feeder_conveyor.conveyor
.then([ctr_ptr](size_t foo){ .then([ctr_ptr](size_t foo){
return std::to_string(foo + ++(*ctr_ptr)); return std::to_string(foo + ++(*ctr_ptr));
}) })
@ -163,34 +163,34 @@ SAW_TEST("Async Scheduling"){
wait_scope.poll(); wait_scope.poll();
ErrorOr<std::string> foo_10 = string_conveyor.take(); error_or<std::string> foo_10 = string_conveyor.take();
SAW_EXPECT(!foo_10.isError(), foo_10.error().message()); SAW_EXPECT(!foo_10.is_error(), foo_10.error().message());
SAW_EXPECT(foo_10.isValue(), "Return is not a value"); SAW_EXPECT(foo_10.is_value(), "Return is not a value");
SAW_EXPECT(foo_10.value() == (std::string{"pre"} + std::to_string(11) + std::string{"post"}), "Values is not pre11post, but " + foo_10.value()); SAW_EXPECT(foo_10.value() == (std::string{"pre"} + std::to_string(11) + std::string{"post"}), "Values is not pre11post, but " + foo_10.value());
ErrorOr<std::string> foo_20 = string_conveyor.take(); error_or<std::string> foo_20 = string_conveyor.take();
SAW_EXPECT(!foo_20.isError(), foo_20.error().message()); SAW_EXPECT(!foo_20.is_error(), foo_20.error().message());
SAW_EXPECT(foo_20.isValue(), "Return is not a value"); SAW_EXPECT(foo_20.is_value(), "Return is not a value");
SAW_EXPECT(foo_20.value() == (std::string{"pre"} + std::to_string(22) + std::string{"post"}), "Values is not pre22post, but " + foo_20.value()); SAW_EXPECT(foo_20.value() == (std::string{"pre"} + std::to_string(22) + std::string{"post"}), "Values is not pre22post, but " + foo_20.value());
ErrorOr<std::string> foo_30 = string_conveyor.take(); error_or<std::string> foo_30 = string_conveyor.take();
SAW_EXPECT(!foo_30.isError(), foo_30.error().message()); SAW_EXPECT(!foo_30.is_error(), foo_30.error().message());
SAW_EXPECT(foo_30.isValue(), "Return is not a value"); SAW_EXPECT(foo_30.is_value(), "Return is not a value");
SAW_EXPECT(foo_30.value() == (std::string{"pre"} + std::to_string(33) + std::string{"post"}), "Values is not pre33post, but " + foo_30.value()); SAW_EXPECT(foo_30.value() == (std::string{"pre"} + std::to_string(33) + std::string{"post"}), "Values is not pre33post, but " + foo_30.value());
} }
SAW_TEST("Async Detach"){ SAW_TEST("Async Detach"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
int num = 0; int num = 0;
Conveyor<int>{10}.then([&num](int bar){ conveyor<int>{10}.then([&num](int bar){
num = bar; num = bar;
}).detach(); }).detach();
@ -202,14 +202,14 @@ SAW_TEST("Async Detach"){
SAW_TEST("Async Merge"){ SAW_TEST("Async Merge"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto cam = Conveyor<int>{10}.merge(); auto cam = conveyor<int>{10}.merge();
cam.second.attach(Conveyor<int>{11}); cam.second.attach(conveyor<int>{11});
cam.second.attach(Conveyor<int>{14}); cam.second.attach(conveyor<int>{14});
size_t elements_passed = 0; size_t elements_passed = 0;
bool wrong_value = false; bool wrong_value = false;
@ -231,12 +231,12 @@ SAW_TEST("Async Merge"){
SAW_TEST("Async Connect"){ SAW_TEST("Async Connect"){
using namespace saw; using namespace saw;
EventLoop event_loop; event_loop event_loop;
WaitScope wait_scope{event_loop}; wait_scope wait_scope{event_loop};
auto caf1 = newConveyorAndFeeder<int>(); auto caf1 = new_conveyor_and_feeder<int>();
auto caf2 = newConveyorAndFeeder<float>(); auto caf2 = new_conveyor_and_feeder<float>();
bool val_passed = false; bool val_passed = false;
auto conveyor1 = caf1.conveyor.then([&val_passed](int val) -> float{ auto conveyor1 = caf1.conveyor.then([&val_passed](int val) -> float{

View File

@ -16,7 +16,7 @@ using TestTuple = schema::Tuple<schema::UInt32, schema::String>;
SAW_TEST("Message Tuple"){ SAW_TEST("Message Tuple"){
std::string test_string_1 = "banana"; std::string test_string_1 = "banana";
auto root = saw::heapMessageRoot<TestTuple>(); auto root = saw::new_heap_message_root<TestTuple>();
auto builder = root.build(); auto builder = root.build();
auto uint = builder.init<0>(); auto uint = builder.init<0>();
uint.set(10); uint.set(10);
@ -36,7 +36,7 @@ SAW_TEST("Message Tuple nested"){
std::string test_string_1 = "banana"; std::string test_string_1 = "banana";
std::string test_string_2 = "bat"; std::string test_string_2 = "bat";
auto root = saw::heapMessageRoot<NestedTestTuple>(); auto root = saw::new_heap_message_root<NestedTestTuple>();
auto builder = root.build(); auto builder = root.build();
auto inner_list = builder.init<0>(); auto inner_list = builder.init<0>();
auto uint = inner_list.init<0>(); auto uint = inner_list.init<0>();
@ -64,7 +64,7 @@ using TestStruct = schema::Struct<
SAW_TEST("Message Struct"){ SAW_TEST("Message Struct"){
std::string test_string = "foo"; std::string test_string = "foo";
auto root = saw::heapMessageRoot<TestStruct>(); auto root = saw::new_heap_message_root<TestStruct>();
auto builder = root.build(); auto builder = root.build();
auto uint = builder.init<"test_uint">(); auto uint = builder.init<"test_uint">();
uint.set(23); uint.set(23);
@ -88,7 +88,7 @@ SAW_TEST("Message Struct"){
using TestArray = schema::Array<schema::UInt32>; using TestArray = schema::Array<schema::UInt32>;
void arrayCheck(saw::Message<TestArray>::Builder builder){ void arrayCheck(saw::message<TestArray>::builder builder){
auto one = builder.init(0); auto one = builder.init(0);
auto two = builder.init(1); auto two = builder.init(1);
auto three = builder.init(2); auto three = builder.init(2);
@ -97,13 +97,13 @@ void arrayCheck(saw::Message<TestArray>::Builder builder){
two.set(45); two.set(45);
three.set(1230); three.set(1230);
auto reader = builder.asReader(); auto reader = builder.as_reader();
SAW_EXPECT(reader.get(0).get() == 24 && reader.get(1).get() == 45 && reader.get(2).get(), "Wrong values"); SAW_EXPECT(reader.get(0).get() == 24 && reader.get(1).get() == 45 && reader.get(2).get(), "Wrong values");
} }
SAW_TEST("Message Array"){ SAW_TEST("Message Array"){
auto root = saw::heapMessageRoot<TestArray>(); auto root = saw::new_heap_message_root<TestArray>();
auto builder = root.build(3); auto builder = root.build(3);
@ -115,7 +115,7 @@ using TestArrayStruct = schema::Struct<
>; >;
SAW_TEST("Message Array in Struct"){ SAW_TEST("Message Array in Struct"){
auto root = saw::heapMessageRoot<TestArrayStruct>(); auto root = saw::new_heap_message_root<TestArrayStruct>();
auto builder = root.build(); auto builder = root.build();

View File

@ -27,26 +27,26 @@ SAW_TEST("Primitive Encoding"){
using namespace saw; using namespace saw;
uint32_t value = 5; uint32_t value = 5;
auto root = heapMessageRoot<TestSize>(); auto root = new_heap_message_root<TestSize>();
auto builder = root.build(); auto builder = root.build();
builder.set(value); builder.set(value);
RingBuffer temp_buffer; ring_buffer temp_buffer;
ProtoKelCodec codec; proto_kel_codec codec;
Error error = codec.encode<TestSize>(root.read(), temp_buffer); error err = codec.encode<TestSize>(root.read(), temp_buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(temp_buffer.readCompositeLength() == (sizeof(value)+sizeof(ProtoKelCodec::PacketLengthT)), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength())); SAW_EXPECT(temp_buffer.read_composite_length() == (sizeof(value)+sizeof(proto_kel_codec::PacketLengthT)), "Bad Size: " + std::to_string(temp_buffer.read_composite_length()));
constexpr size_t pkt_shift = sizeof(ProtoKelCodec::PacketLengthT); constexpr size_t pkt_shift = sizeof(proto_kel_codec::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"); 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");
} }
SAW_TEST("List Encoding"){ SAW_TEST("List Encoding"){
using namespace saw; using namespace saw;
auto root = heapMessageRoot<TestTuple>(); auto root = new_heap_message_root<TestTuple>();
auto builder = root.build(); auto builder = root.build();
auto first = builder.init<0>(); auto first = builder.init<0>();
@ -54,20 +54,20 @@ SAW_TEST("List Encoding"){
auto second = builder.init<1>(); auto second = builder.init<1>();
second.set(43871); second.set(43871);
RingBuffer buffer; ring_buffer buffer;
ProtoKelCodec codec; proto_kel_codec codec;
Error error = codec.encode<TestTuple>(root.read(), buffer); error err = codec.encode<TestTuple>(root.read(), buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(buffer.readCompositeLength() == 14, "Bad Size: " + std::to_string(buffer.readCompositeLength())); SAW_EXPECT(buffer.read_composite_length() == 14, "Bad Size: " + std::to_string(buffer.read_composite_length()));
SAW_EXPECT("06 00 00 00\n00 00 00 00\nbf 94 20 00\n5f ab" == buffer.toHex(), "Not equal encoding\n"+buffer.toHex()); SAW_EXPECT("06 00 00 00\n00 00 00 00\nbf 94 20 00\n5f ab" == buffer.to_hex(), "Not equal encoding\n"+buffer.to_hex());
} }
SAW_TEST("Struct Encoding"){ SAW_TEST("Struct Encoding"){
using namespace saw; using namespace saw;
auto root = heapMessageRoot<TestStruct>(); auto root = new_heap_message_root<TestStruct>();
auto builder = root.build(); auto builder = root.build();
auto test_uint = builder.init<"test_uint">(); auto test_uint = builder.init<"test_uint">();
@ -80,52 +80,52 @@ SAW_TEST("Struct Encoding"){
auto string_name = builder.init<"test_name">(); auto string_name = builder.init<"test_name">();
string_name.set("test_name"); string_name.set("test_name");
RingBuffer buffer; ring_buffer buffer;
ProtoKelCodec codec; proto_kel_codec codec;
Error error = codec.encode<TestStruct>(builder.asReader(), buffer); error err = codec.encode<TestStruct>(builder.as_reader(), buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(buffer.readCompositeLength() == 40, "Bad Size: " + std::to_string(buffer.readCompositeLength())); SAW_EXPECT(buffer.read_composite_length() == 40, "Bad Size: " + std::to_string(buffer.read_composite_length()));
SAW_EXPECT("20 00 00 00\n00 00 00 00\n17 00 00 00\n03 00 00 00\n00 00 00 00\n66 6f 6f 09\n00 00 00 00\n00 00 00 74\n65 73 74 5f\n6e 61 6d 65" SAW_EXPECT("20 00 00 00\n00 00 00 00\n17 00 00 00\n03 00 00 00\n00 00 00 00\n66 6f 6f 09\n00 00 00 00\n00 00 00 74\n65 73 74 5f\n6e 61 6d 65"
== buffer.toHex(), "Not equal encoding:\n"+buffer.toHex()); == buffer.to_hex(), "Not equal encoding:\n"+buffer.to_hex());
} }
SAW_TEST("Union Encoding"){ SAW_TEST("Union Encoding"){
using namespace saw; using namespace saw;
{ {
auto root = heapMessageRoot<TestUnion>(); auto root = new_heap_message_root<TestUnion>();
auto builder = root.build(); auto builder = root.build();
auto test_uint = builder.init<"test_uint">(); auto test_uint = builder.init<"test_uint">();
test_uint.set(23); test_uint.set(23);
RingBuffer buffer; ring_buffer buffer;
ProtoKelCodec codec; proto_kel_codec codec;
Error error = codec.encode<TestUnion>(builder.asReader(), buffer); error err = codec.encode<TestUnion>(builder.as_reader(), buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(buffer.readCompositeLength() == 16, "Bad Size: " + std::to_string(buffer.readCompositeLength())); SAW_EXPECT(buffer.read_composite_length() == 16, "Bad Size: " + std::to_string(buffer.read_composite_length()));
SAW_EXPECT("08 00 00 00\n00 00 00 00\n00 00 00 00\n17 00 00 00" SAW_EXPECT("08 00 00 00\n00 00 00 00\n00 00 00 00\n17 00 00 00"
== buffer.toHex(), "Not equal encoding:\n"+buffer.toHex()); == buffer.to_hex(), "Not equal encoding:\n"+buffer.to_hex());
} }
{ {
auto root = heapMessageRoot<TestUnion>(); auto root = new_heap_message_root<TestUnion>();
auto builder = root.build(); auto builder = root.build();
auto test_string = builder.init<"test_string">(); auto test_string = builder.init<"test_string">();
test_string.set("foo"); test_string.set("foo");
RingBuffer buffer; ring_buffer buffer;
ProtoKelCodec codec; proto_kel_codec codec;
Error error = codec.encode<TestUnion>(builder.asReader(), buffer); error err = codec.encode<TestUnion>(builder.as_reader(), buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(buffer.readCompositeLength() == 23, "Bad Size: " + std::to_string(buffer.readCompositeLength())); SAW_EXPECT(buffer.read_composite_length() == 23, "Bad Size: " + std::to_string(buffer.read_composite_length()));
SAW_EXPECT("0f 00 00 00\n00 00 00 00\n01 00 00 00\n03 00 00 00\n00 00 00 00\n66 6f 6f" SAW_EXPECT("0f 00 00 00\n00 00 00 00\n01 00 00 00\n03 00 00 00\n00 00 00 00\n66 6f 6f"
== buffer.toHex(), "Not equal encoding:\n"+buffer.toHex()); == buffer.to_hex(), "Not equal encoding:\n"+buffer.to_hex());
} }
} }
@ -133,18 +133,18 @@ SAW_TEST("Tuple Decoding"){
using namespace saw; using namespace saw;
const uint8_t buffer_raw[] = {0x06, 0, 0, 0, 0, 0, 0, 0, 0xbf, 0x94, 0x20, 0x00, 0x5f, 0xab}; const uint8_t buffer_raw[] = {0x06, 0, 0, 0, 0, 0, 0, 0, 0xbf, 0x94, 0x20, 0x00, 0x5f, 0xab};
RingBuffer buffer; ring_buffer buffer;
buffer.push(*buffer_raw, sizeof(buffer_raw)); buffer.push(*buffer_raw, sizeof(buffer_raw));
ProtoKelCodec codec; proto_kel_codec codec;
auto root = heapMessageRoot<TestTuple>(); auto root = new_heap_message_root<TestTuple>();
auto builder = root.build(); auto builder = root.build();
Error error = codec.decode<TestTuple>(builder, buffer); error err = codec.decode<TestTuple>(builder, buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
auto reader = builder.asReader(); auto reader = builder.as_reader();
auto first = reader.get<0>(); auto first = reader.get<0>();
auto second = reader.get<1>(); auto second = reader.get<1>();
@ -156,22 +156,22 @@ SAW_TEST("Struct Decoding"){
using namespace saw; using namespace saw;
const uint8_t buffer_raw[] = {0x20,0,0,0,0,0,0,0,0x17,0,0,0,0x03,0,0,0,0,0,0,0,0x66,0x6f,0x6f,0x09,0,0,0,0,0,0,0,0x74,0x65,0x73,0x74,0x5f,0x6e,0x61,0x6d,0x65}; const uint8_t buffer_raw[] = {0x20,0,0,0,0,0,0,0,0x17,0,0,0,0x03,0,0,0,0,0,0,0,0x66,0x6f,0x6f,0x09,0,0,0,0,0,0,0,0x74,0x65,0x73,0x74,0x5f,0x6e,0x61,0x6d,0x65};
RingBuffer buffer; ring_buffer buffer;
buffer.push(*buffer_raw, sizeof(buffer_raw)); buffer.push(*buffer_raw, sizeof(buffer_raw));
ProtoKelCodec codec; proto_kel_codec codec;
auto root = heapMessageRoot<TestStruct>(); auto root = new_heap_message_root<TestStruct>();
auto builder = root.build(); auto builder = root.build();
Error error = codec.decode<TestStruct>(builder, buffer); error err = codec.decode<TestStruct>(builder, buffer);
auto reader = builder.asReader(); auto reader = builder.as_reader();
auto foo_string = reader.get<"test_string">(); auto foo_string = reader.get<"test_string">();
auto test_uint = reader.get<"test_uint">(); auto test_uint = reader.get<"test_uint">();
auto test_name = reader.get<"test_name">(); auto test_name = reader.get<"test_name">();
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(foo_string.get() == "foo" && test_uint.get() == 23 && test_name.get() == "test_name", "Values not correctly decoded"); SAW_EXPECT(foo_string.get() == "foo" && test_uint.get() == 23 && test_name.get() == "test_name", "Values not correctly decoded");
} }
@ -179,19 +179,19 @@ SAW_TEST("Union Decoding"){
using namespace saw; using namespace saw;
const uint8_t buffer_raw[] = {0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x6f,0x6f}; const uint8_t buffer_raw[] = {0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x66,0x6f,0x6f};
RingBuffer buffer; ring_buffer buffer;
buffer.push(*buffer_raw, sizeof(buffer_raw)); buffer.push(*buffer_raw, sizeof(buffer_raw));
ProtoKelCodec codec; proto_kel_codec codec;
auto root = heapMessageRoot<TestUnion>(); auto root = new_heap_message_root<TestUnion>();
auto builder = root.build(); auto builder = root.build();
auto reader = builder.asReader(); auto reader = builder.as_reader();
Error error = codec.decode<TestUnion>(builder, buffer); error err = codec.decode<TestUnion>(builder, buffer);
SAW_EXPECT(!error.failed(), error.message()); SAW_EXPECT(!err.failed(), err.message());
SAW_EXPECT(reader.hasAlternative<"test_string">(), "Wrong union value"); SAW_EXPECT(reader.has_alternative<"test_string">(), "Wrong union value");
auto str_rd = reader.get<"test_string">(); auto str_rd = reader.get<"test_string">();
SAW_EXPECT(str_rd.get() == "foo", "Wrong value: " + std::string{str_rd.get()}); SAW_EXPECT(str_rd.get() == "foo", "Wrong value: " + std::string{str_rd.get()});
} }
@ -203,8 +203,8 @@ using TestArrayStruct = schema::Array<
SAW_TEST("Array Encoding"){ SAW_TEST("Array Encoding"){
using namespace saw; using namespace saw;
ProtoKelCodec codec; proto_kel_codec codec;
auto root = heapMessageRoot<TestArrayStruct>(); auto root = new_heap_message_root<TestArrayStruct>();
auto builder = root.build(2); auto builder = root.build(2);
auto one = builder.init(0); auto one = builder.init(0);
@ -218,10 +218,10 @@ SAW_TEST("Array Encoding"){
two.init<"test_string">().set("bar"); two.init<"test_string">().set("bar");
two.init<"test_name">().set("Bravo"); two.init<"test_name">().set("Bravo");
RingBuffer buffer; ring_buffer buffer;
Error error = codec.encode<TestArrayStruct>(root.read(), buffer); error err = codec.encode<TestArrayStruct>(root.read(), buffer);
SAW_EXPECT(!error.failed(), "Error occured"); SAW_EXPECT(!err.failed(), "Error occured");
} }
} }