Compare commits

...

72 Commits

Author SHA1 Message Date
Claudius Holeksa 16298130c3 updated io_peer errors 2022-12-08 10:23:18 +01:00
Claudius Holeksa 92f874b3f2 Own changed to own 2022-12-06 19:24:20 +01:00
Claudius Holeksa 833169a47f prepare for linting 2022-12-06 19:21:20 +01:00
Claudius Holeksa 8f4614b264 renaming things 2022-12-05 17:17:49 +01:00
Claudius Holeksa fc12627f54 worked through async.cpp errors 2022-12-05 02:04:19 +01:00
Claudius Holeksa 947004fd65 in process Camel to snake case 2022-12-05 01:49:38 +01:00
Claudius Holeksa a1a718967d fixed missing connection notification 2022-12-03 17:39:21 +01:00
Claudius Holeksa 6968a80518 Problem: assert was being thrown due to invalid state after setting up parents incorrectly in merge 2022-12-02 15:11:32 +01:00
Claudius Holeksa 55a6d4dd9b parent connection is added 2022-12-01 19:21:48 +01:00
Claudius Holeksa 4384f8acfa Problem: referenced node after move 2022-12-01 19:16:16 +01:00
Claudius Holeksa 77acd00720 flipped bool check 2022-12-01 19:12:42 +01:00
Claudius Holeksa 3004dec554 compilable state 2022-12-01 19:06:46 +01:00
Claudius Holeksa 9330d1ee74 working progress for the child storage querying 2022-12-01 18:54:09 +01:00
Claudius Holeksa c51bb63e9b removing old storage use 2022-11-30 00:49:54 +01:00
Claudius Holeksa 389d23bd28 rename virtual function 2022-11-25 00:27:44 +01:00
Claudius Holeksa 30937d98c5 adding replacement calls for previously removed variable 2022-11-21 02:05:45 +01:00
Claudius Holeksa 4fa6ed0d59 helper removal to see which parts fail. Needs to be removed due to the swapChild calls 2022-11-21 02:03:15 +01:00
Claudius Holeksa 33188f213e removing notify. only necessary for adapt and it can handle the case itself 2022-11-21 00:41:20 +01:00
Claudius Holeksa 7aacdc357c parent notification implemented. calls to it missing. Tests needed 2022-11-19 20:09:24 +01:00
Claudius Holeksa 21a1bde479 adding parent child swap support. missing the parent notification part for now. 2022-11-19 19:19:42 +01:00
Claudius Holeksa a963bdff6c add compilation data generation 2022-11-19 16:29:45 +01:00
Claudius Holeksa d845848449 cleaned up shell file 2022-11-19 16:29:07 +01:00
Claudius Holeksa 37ed2ebc8e moving towards rpc with better conveyor comm and adding minor hint for custom assert 2022-11-03 20:33:40 +01:00
Claudius Holeksa e4b6204edd appendage declared functiong 2022-10-19 22:29:56 +02:00
Claudius Holeksa 536aa05298 Merge branch 'fb-rpc' of ssh://git.keldu.de/forstio/forstio into fb-rpc 2022-10-17 23:15:08 +02:00
Claudius Holeksa 74663daeef appendage has to be a node now 2022-10-17 23:15:02 +02:00
keldu 91a8f680b2 merge 2022-10-04 00:48:56 +02:00
Claudius Holeksa 2e9d96a1d0 fixed dangling renames 2022-10-02 22:53:08 +02:00
Claudius Holeksa 3651aea384 changed to no default CC env 2022-09-28 17:56:55 +02:00
keldu 7fecac92c0 Merge branch 'fb-rpc' of git.keldu.de:forstio/forstio into fb-rpc 2022-09-27 00:38:43 +02:00
keldu cdb096a44f dangling lines 2022-09-27 00:34:12 +02:00
Claudius Holeksa 5d3796c751 Merge branch 'dev' into fb-rpc 2022-09-26 20:49:36 +02:00
Claudius Holeksa fb9312acb1 removed unnecessary nix files 2022-09-20 00:56:45 +02:00
keldu f695b047e9 Merge pull request 'added nix dev files' (#1) from fb-shell-at-different-pos into dev
Reviewed-on: #1
2022-09-19 21:41:29 +02:00
Claudius Holeksa 7518dd7ed4 added nix dev files 2022-09-19 17:58:06 +02:00
Claudius Holeksa afbe54c795 Merge branch 'fb-rpc' of ssh://git.keldu.de/forstio/forstio into fb-rpc 2022-09-19 17:31:01 +02:00
Claudius Holeksa 9e4260cc04 remove default library 2022-09-19 17:25:37 +02:00
Claudius Holeksa f0f1c8f2e8 dangling stuff 2022-09-17 17:05:19 +02:00
keldu 5ce093cb6a since parents could change now, we need to recheck the storage interaction 2022-06-07 23:23:00 +02:00
Claudius Holeksa b8b461a4c6 reworking async for swapping out nodes 2022-06-07 23:03:54 +02:00
keldu f92ebab88a moving to swap feature of conveyor nodes 2022-06-06 01:22:36 +02:00
keldu 01ebd991ae static lib for tls 2022-05-27 17:46:13 +02:00
keldu f38a122efa seperated tls from base lib 2022-05-27 17:26:37 +02:00
keldu 80c5fd6bfb restructure of scons build 2022-05-27 16:02:58 +02:00
Claudius Holeksa c0241fe666 changing compile structure 2022-05-27 15:46:32 +02:00
keldu b25b28a560 Update 'source/forstio/rpc/rpc.h' 2022-05-15 15:06:02 +02:00
keldu 54608ac410 Add 'source/forstio/rpc/rpc.h' 2022-05-14 19:18:55 +02:00
keldu 9136e902f1 Changed schema names and added some clarified compiler errors. 2022-05-13 15:14:19 +02:00
Claudius Holeksa 2ea95b8b3e added name to rpc 2022-05-05 20:53:47 +02:00
Claudius Holeksa dc5ad0e62a format 2022-05-05 19:08:09 +02:00
Claudius Holeksa 883cfc32a5 Merge branch 'dev' into fb-rpc 2022-05-01 16:46:58 +02:00
Claudius Holeksa 2af95c3664 adding nix files 2022-05-01 16:43:49 +02:00
Claudius Holeksa c82d717c2d scoped variables for ProtoKelCodec to that class 2022-04-03 15:51:32 +02:00
Claudius Holeksa 0d06a58798 smallish fix. cassert had to be include manually previously. Which caused some annoyance with SAW_ASSERT 2022-03-30 22:26:07 +02:00
Claudius Holeksa d172f458a3 removed white space 2022-03-29 22:25:46 +02:00
Claudius Holeksa e571a7ce90 Merge branch 'dev' of ssh://git.keldu.de:64730/forstio/forstio into dev 2022-03-29 22:24:01 +02:00
Claudius Holeksa a5cfca7a12 commenting some things 2022-03-29 22:23:36 +02:00
Claudius Holeksa ffed345df1 Tls now the main object. Network is retrieved from the TLS class 2022-03-29 22:09:12 +02:00
keldu 0808db94ee format 2022-03-28 01:19:00 +02:00
Claudius Holeksa f44b6a1dc8 declaring a future template. it is not clean coding/vcs, but i am collecting features i want to freeze for later 2022-03-20 22:25:17 +01:00
Claudius Holeksa b0991ce29b added some todos 2022-03-20 22:23:35 +01:00
Claudius Holeksa 60d710cab7 forgot to remove const qualifier 2022-03-20 19:02:57 +01:00
Claudius Holeksa 28ea7d6708 fixed tls call of resolveAddress and made one Reader function static 2022-03-20 18:55:09 +01:00
Claudius Holeksa 3ff512bfca renamed from parse to resolve 2022-03-16 01:46:41 +01:00
Claudius Holeksa 2d8889983a error copy has to be called explicitly 2022-03-15 18:54:47 +01:00
Claudius Holeksa 5a6f63eadb called wrong func 2022-03-15 18:40:44 +01:00
Claudius Holeksa 911db65409 changed streaming peer to return in heaped env 2022-03-13 21:15:21 +01:00
Claudius Holeksa f29d1c6512 io peering fix 2022-03-13 20:17:06 +01:00
Claudius Holeksa 3cb0434e49 io peering. forgot to drop default template assignement when defining the functions 2022-03-13 17:13:20 +01:00
Claudius Holeksa 7117f23fcd io peering. forgot to drop default template assignement when defining the functions 2022-03-13 17:09:46 +01:00
Claudius Holeksa 6624960f86 io peering. forgot to drop default template assignement when defining the functions 2022-03-13 17:00:43 +01:00
Claudius Holeksa 12c61f46dc schema design 2022-01-12 22:01:59 +01:00
36 changed files with 2107 additions and 1392 deletions

7
.clang-tidy Normal file
View File

@ -0,0 +1,7 @@
Checks: '-*,readability-identifier-naming'
CheckOptions:
- { key: readability-identifier-naming.NamespaceCase, value: lower_case }
- { key: readability-identifier-naming.ClassCase, value: lower_case }
- { key: readability-identifier-naming.StructCase, value: CamelCase }
- { key: readability-identifier-naming.FunctionCase, value: lower_case }
- { key: readability-identifier-naming.VariableCase, value: lower_case }

4
.gitignore vendored
View File

@ -71,3 +71,7 @@ thoughts
*.swp
vgcore.*
*.pdf
# cache file for ale
.cache
async.plist

10
.nix/shell.nix Normal file
View File

@ -0,0 +1,10 @@
with import <nixpkgs> {};
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
name = "forstio";
nativeBuildInputs = [ scons gnutls clang_12 clang-tools];
buildPhase = ''
'';
}

View File

@ -32,22 +32,27 @@ def add_kel_source_files(self, sources, filetype, lib_env=None, shared=False, ta
def isAbsolutePath(key, dirname, env):
assert os.path.isabs(dirname), "%r must have absolute path syntax" % (key,)
## Environment variables
env_vars = Variables(
args=ARGUMENTS
)
env_vars.Add('prefix',
help='Installation target location of build results and headers',
default='/usr/local/',
validator=isAbsolutePath
)
## Environment setup
env=Environment(ENV=os.environ, variables=env_vars, CPPPATH=['#source/forstio','#source','#','#driver'],
CXX='clang++',
CPPDEFINES=['SAW_UNIX'],
CXXFLAGS=['-std=c++20','-g','-Wall','-Wextra'],
LIBS=['gnutls'])
LIBS=[])
env.__class__.add_source_files = add_kel_source_files
env.Tool('compilation_db');
env.cdb = env.CompilationDatabase('compile_commands.json');
env.objects = []
env.sources = []
@ -60,26 +65,8 @@ env.driver_sources = []
env.driver_headers = []
Export('env')
SConscript('source/forstio/SConscript')
SConscript('driver/SConscript')
# Library build
env_library = env.Clone()
env.objects_shared = []
env_library.add_source_files(env.objects_shared, env.sources + env.driver_sources + env.tls_sources, shared=True)
env.library_shared = env_library.SharedLibrary('#build/forstio', [env.objects_shared])
env.objects_static = []
env_library.add_source_files(env.objects_static, env.sources + env.driver_sources + env.tls_sources)
env.library_static = env_library.StaticLibrary('#build/forstio', [env.objects_static])
env.Alias('library', [env.library_shared, env.library_static])
env.Alias('library_shared', env.library_shared)
env.Alias('library_static', env.library_static)
env.Default('library')
SConscript('source/forstio/SConscript')
# Tests
SConscript('test/SConscript')
@ -88,17 +75,32 @@ env.Alias('test', env.test_program)
# Clang format part
env.Append(BUILDERS={'ClangFormat' : Builder(action = 'clang-format --style=file -i $SOURCE')})
env.Append(BUILDERS={'ClangTidyFix' : Builder(action = 'clang-tidy -extra-arg-before=-xc++ --fix $SOURCE -- -std=c++17 -DSAW_UNIX -Isource')})
env.format_actions = []
def format_iter(env,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
env.tidy_actions = []
def tidy_iter(env,files):
string_of_files = "";
for f in files:
if(f != "/home/keldu/workspace/forstio/source/forstio/async.tmpl.h" ):
string_of_files = string_of_files + " " + f;
# env.tidy_actions.append(env.AlwaysBuild(env.ClangTidyFix(target=f+"-clang-tidy-fix",source=f)));
print(string_of_files);
pass
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('all', ['format', 'library_shared', 'library_static', 'test'])
env.Alias('cdb', env.cdb);
env.Alias('all', ['format', 'library', 'test'])
env.Default('all')
env.Install('$prefix/lib/', [env.library_shared, env.library_static])
env.Install('$prefix/include/forstio/', [env.headers])

View File

@ -1,19 +1,19 @@
#include "driver/io-unix.h"
#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},
i_fd_owner::i_fd_owner(UnixEventPort &event_port, int file_descriptor,
int fd_flags, uint32_t event_mask)
: m_event_port{event_port}, file_descriptor{file_descriptor},
fd_flags{fd_flags}, event_mask{event_mask} {
event_port.subscribe(*this, file_descriptor, event_mask);
m_event_port.subscribe(*this, file_descriptor, event_mask);
}
IFdOwner::~IFdOwner() {
i_fd_owner::~i_fd_owner() {
if (file_descriptor >= 0) {
event_port.unsubscribe(file_descriptor);
m_event_port.unsubscribe(file_descriptor);
::close(file_descriptor);
}
}
@ -28,33 +28,33 @@ ssize_t unixWrite(int fd, const void *buffer, size_t length) {
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} {
}
: i_fd_owner{event_port, file_descriptor, fd_flags,
event_mask | EPOLLRDHUP} {}
ErrorOr<size_t> UnixIoStream::read(void *buffer, size_t length) {
error_or<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 critical_error("Disconnected", error::code::disconnected);
}
return recoverableError("Currently busy");
return recoverable_error("Currently busy");
}
Conveyor<void> UnixIoStream::readReady() {
auto caf = newConveyorAndFeeder<void>();
conveyor<void> UnixIoStream::readReady() {
auto caf = new_conveyor_and_feeder<void>();
read_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
Conveyor<void> UnixIoStream::onReadDisconnected() {
auto caf = newConveyorAndFeeder<void>();
conveyor<void> UnixIoStream::onReadDisconnected() {
auto caf = new_conveyor_and_feeder<void>();
on_read_disconnect = std::move(caf.feeder);
return std::move(caf.conveyor);
}
ErrorOr<size_t> UnixIoStream::write(const void *buffer, size_t length) {
error_or<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);
@ -63,14 +63,14 @@ ErrorOr<size_t> UnixIoStream::write(const void *buffer, size_t length) {
int error = errno;
if (error == EAGAIN || error == EWOULDBLOCK) {
return recoverableError("Currently busy");
return recoverable_error("Currently busy");
}
return criticalError("Disconnected", Error::Code::Disconnected);
return critical_error("Disconnected", error::code::disconnected);
}
Conveyor<void> UnixIoStream::writeReady() {
auto caf = newConveyorAndFeeder<void>();
conveyor<void> UnixIoStream::writeReady() {
auto caf = new_conveyor_and_feeder<void>();
write_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
@ -97,10 +97,10 @@ void UnixIoStream::notify(uint32_t mask) {
UnixServer::UnixServer(UnixEventPort &event_port, int file_descriptor,
int fd_flags)
: IFdOwner{event_port, file_descriptor, fd_flags, EPOLLIN} {}
: i_fd_owner{event_port, file_descriptor, fd_flags, EPOLLIN} {}
Conveyor<Own<IoStream>> UnixServer::accept() {
auto caf = newConveyorAndFeeder<Own<IoStream>>();
conveyor<own<IoStream>> UnixServer::accept() {
auto caf = new_conveyor_and_feeder<own<IoStream>>();
accept_feeder = std::move(caf.feeder);
return std::move(caf.conveyor);
}
@ -117,7 +117,7 @@ void UnixServer::notify(uint32_t mask) {
if (accept_fd < 0) {
return;
}
auto fd_stream = heap<UnixIoStream>(event_port, accept_fd, 0,
auto fd_stream = heap<UnixIoStream>(m_event_port, accept_fd, 0,
EPOLLIN | EPOLLOUT);
accept_feeder->feed(std::move(fd_stream));
}
@ -126,10 +126,10 @@ void UnixServer::notify(uint32_t mask) {
UnixDatagram::UnixDatagram(UnixEventPort &event_port, int file_descriptor,
int fd_flags)
: IFdOwner{event_port, file_descriptor, fd_flags, EPOLLIN | EPOLLOUT} {}
: i_fd_owner{event_port, file_descriptor, fd_flags, EPOLLIN | EPOLLOUT} {}
namespace {
ssize_t unixReadMsg(int fd, void *buffer, size_t length) {
ssize_t unix_read_msg(int fd, void *buffer, size_t length) {
struct ::sockaddr_storage their_addr;
socklen_t addr_len = sizeof(sockaddr_storage);
return ::recvfrom(fd, buffer, length, 0,
@ -137,42 +137,42 @@ ssize_t unixReadMsg(int fd, void *buffer, size_t length) {
&addr_len);
}
ssize_t unixWriteMsg(int fd, const void *buffer, size_t length,
::sockaddr *dest_addr, socklen_t dest_addr_len) {
ssize_t unix_write_msg(int fd, const void *buffer, size_t length,
::sockaddr *dest_addr, socklen_t dest_addr_len) {
return ::sendto(fd, buffer, length, 0, dest_addr, dest_addr_len);
}
} // namespace
ErrorOr<size_t> UnixDatagram::read(void *buffer, size_t length) {
ssize_t read_bytes = unixReadMsg(fd(), buffer, length);
error_or<size_t> UnixDatagram::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 recoverableError("Currently busy");
return recoverable_error("Currently busy");
}
Conveyor<void> UnixDatagram::readReady() {
auto caf = newConveyorAndFeeder<void>();
conveyor<void> UnixDatagram::readReady() {
auto caf = new_conveyor_and_feeder<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) {
error_or<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);
ssize_t write_bytes = unix_write_msg(fd(), buffer, length,
sock_addr.getRaw(), sock_addr_length);
if (write_bytes > 0) {
return static_cast<size_t>(write_bytes);
}
return recoverableError("Currently busy");
return recoverable_error("Currently busy");
}
Conveyor<void> UnixDatagram::writeReady() {
auto caf = newConveyorAndFeeder<void>();
conveyor<void> UnixDatagram::writeReady() {
auto caf = new_conveyor_and_feeder<void>();
write_ready = std::move(caf.feeder);
return std::move(caf.conveyor);
}
@ -192,14 +192,14 @@ void UnixDatagram::notify(uint32_t mask) {
}
namespace {
bool beginsWith(const std::string_view &viewed,
const std::string_view &begins) {
bool string_view_begins_with(const std::string_view &viewed,
const std::string_view &begins) {
return viewed.size() >= begins.size() &&
viewed.compare(0, begins.size(), begins) == 0;
}
std::variant<UnixNetworkAddress, UnixNetworkAddress *>
translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
translate_network_address_to_unix_network_address(NetworkAddress &addr) {
auto addr_variant = addr.representation();
std::variant<UnixNetworkAddress, UnixNetworkAddress *> os_addr = std::visit(
[](auto &arg)
@ -210,7 +210,7 @@ translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
return static_cast<UnixNetworkAddress *>(arg);
}
auto sock_addrs = SocketAddress::parse(
auto sock_addrs = SocketAddress::resolve(
std::string_view{arg->address()}, arg->port());
return UnixNetworkAddress{arg->address(), arg->port(),
@ -220,7 +220,7 @@ translateNetworkAddressToUnixNetworkAddress(NetworkAddress &addr) {
return os_addr;
}
UnixNetworkAddress &translateToUnixAddressRef(
UnixNetworkAddress &translate_to_unix_address_ref(
std::variant<UnixNetworkAddress, UnixNetworkAddress *> &addr_variant) {
return std::visit(
[](auto &arg) -> UnixNetworkAddress & {
@ -239,9 +239,11 @@ UnixNetworkAddress &translateToUnixAddressRef(
} // namespace
Own<Server> UnixNetwork::listen(NetworkAddress &addr) {
auto unix_addr_storage = translateNetworkAddressToUnixNetworkAddress(addr);
UnixNetworkAddress &address = translateToUnixAddressRef(unix_addr_storage);
own<Server> UnixNetwork::listen(NetworkAddress &addr) {
auto unix_addr_storage =
translate_network_address_to_unix_network_address(addr);
UnixNetworkAddress &address =
translate_to_unix_address_ref(unix_addr_storage);
assert(address.unixAddressSize() > 0);
if (address.unixAddressSize() == 0) {
@ -271,21 +273,23 @@ Own<Server> UnixNetwork::listen(NetworkAddress &addr) {
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);
conveyor<own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
auto unix_addr_storage =
translate_network_address_to_unix_network_address(addr);
UnixNetworkAddress &address =
translate_to_unix_address_ref(unix_addr_storage);
assert(address.unixAddressSize() > 0);
if (address.unixAddressSize() == 0) {
return Conveyor<Own<IoStream>>{criticalError("No address found")};
return conveyor<own<IoStream>>{critical_error("No address found")};
}
int fd = address.unixAddress(0).socket(SOCK_STREAM);
if (fd < 0) {
return Conveyor<Own<IoStream>>{criticalError("Couldn't open socket")};
return conveyor<own<IoStream>>{critical_error("Couldn't open socket")};
}
Own<UnixIoStream> io_stream =
own<UnixIoStream> io_stream =
heap<UnixIoStream>(event_port, fd, 0, EPOLLIN | EPOLLOUT);
bool success = false;
@ -304,7 +308,7 @@ Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
/// @todo Add limit node when implemented
if (error == EINPROGRESS) {
/*
Conveyor<void> write_ready = io_stream->writeReady();
conveyor<void> write_ready = io_stream->writeReady();
return write_ready.then(
[ios{std::move(io_stream)}]() mutable {
ios->write_ready = nullptr;
@ -315,8 +319,8 @@ Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
break;
} else if (error != EINTR) {
/// @todo Push error message from
return Conveyor<Own<IoStream>>{
criticalError("Couldn't connect")};
return conveyor<own<IoStream>>{
critical_error("Couldn't connect")};
}
} else {
success = true;
@ -325,15 +329,17 @@ Conveyor<Own<IoStream>> UnixNetwork::connect(NetworkAddress &addr) {
}
if (!success) {
return criticalError("Couldn't connect");
return critical_error("Couldn't connect");
}
return Conveyor<Own<IoStream>>{std::move(io_stream)};
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);
own<Datagram> UnixNetwork::datagram(NetworkAddress &addr) {
auto unix_addr_storage =
translate_network_address_to_unix_network_address(addr);
UnixNetworkAddress &address =
translate_to_unix_address_ref(unix_addr_storage);
SAW_ASSERT(address.unixAddressSize() > 0) { return nullptr; }
@ -370,53 +376,53 @@ size_t UnixNetworkAddress::unixAddressSize() const { return addresses.size(); }
UnixNetwork::UnixNetwork(UnixEventPort &event) : event_port{event} {}
Conveyor<Own<NetworkAddress>> UnixNetwork::parseAddress(const std::string &path,
uint16_t port_hint) {
conveyor<own<NetworkAddress>>
UnixNetwork::resolveAddress(const std::string &path, uint16_t port_hint) {
std::string_view addr_view{path};
{
std::string_view begins_with = "unix:";
if (beginsWith(addr_view, begins_with)) {
if (string_view_begins_with(addr_view, begins_with)) {
addr_view.remove_prefix(begins_with.size());
}
}
std::vector<SocketAddress> addresses =
SocketAddress::parse(addr_view, port_hint);
SocketAddress::resolve(addr_view, port_hint);
return Conveyor<Own<NetworkAddress>>{
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} {}
UnixIoProvider::UnixIoProvider(UnixEventPort &port_ref, own<event_port> port)
: m_event_port{port_ref}, m_event_loop{std::move(port)}, unix_network{
port_ref} {}
Own<InputStream> UnixIoProvider::wrapInputFd(int fd) {
return heap<UnixIoStream>(event_port, fd, 0, EPOLLIN);
own<InputStream> UnixIoProvider::wrapInputFd(int fd) {
return heap<UnixIoStream>(m_event_port, fd, 0, EPOLLIN);
}
Network &UnixIoProvider::network() {
return static_cast<Network &>(unix_network);
}
EventLoop &UnixIoProvider::eventLoop() { return event_loop; }
event_loop &UnixIoProvider::eventLoop() { return m_event_loop; }
} // namespace unix
ErrorOr<AsyncIoContext> setupAsyncIo() {
error_or<AsyncIoContext> setupAsyncIo() {
using namespace unix;
try {
Own<UnixEventPort> prt = heap<UnixEventPort>();
own<UnixEventPort> prt = heap<UnixEventPort>();
UnixEventPort &prt_ref = *prt;
Own<UnixIoProvider> io_provider =
own<UnixIoProvider> io_provider =
heap<UnixIoProvider>(prt_ref, std::move(prt));
EventLoop &loop_ref = io_provider->eventLoop();
event_loop &loop_ref = io_provider->eventLoop();
return {{std::move(io_provider), loop_ref, prt_ref}};
} catch (std::bad_alloc &) {
return criticalError("Out of memory");
return critical_error("Out of memory");
}
}
} // namespace saw

View File

@ -33,9 +33,9 @@ namespace unix {
constexpr int MAX_EPOLL_EVENTS = 256;
class UnixEventPort;
class IFdOwner {
class i_fd_owner {
protected:
UnixEventPort &event_port;
UnixEventPort &m_event_port;
private:
int file_descriptor;
@ -43,24 +43,25 @@ private:
uint32_t event_mask;
public:
IFdOwner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask);
i_fd_owner(UnixEventPort &event_port, int file_descriptor, int fd_flags,
uint32_t event_mask);
virtual ~IFdOwner();
virtual ~i_fd_owner();
virtual void notify(uint32_t mask) = 0;
int fd() const { return file_descriptor; }
};
class UnixEventPort final : public EventPort {
class UnixEventPort final : public event_port {
private:
int epoll_fd;
int signal_fd;
sigset_t signal_fd_set;
std::unordered_multimap<Signal, Own<ConveyorFeeder<void>>> signal_conveyors;
std::unordered_multimap<Signal, own<conveyor_feeder<void>>>
signal_conveyors;
int pipefds[2];
@ -137,8 +138,8 @@ private:
}
}
} else {
IFdOwner *owner =
reinterpret_cast<IFdOwner *>(events[i].data.ptr);
i_fd_owner *owner =
reinterpret_cast<i_fd_owner *>(events[i].data.ptr);
if (owner) {
owner->notify(events[i].events);
}
@ -187,8 +188,8 @@ public:
::close(pipefds[1]);
}
Conveyor<void> onSignal(Signal signal) override {
auto caf = newConveyorAndFeeder<void>();
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)));
@ -200,10 +201,8 @@ public:
::sigprocmask(SIG_BLOCK, &signal_fd_set, nullptr);
::signalfd(signal_fd, &signal_fd_set, SFD_NONBLOCK | SFD_CLOEXEC);
auto node_and_storage =
Conveyor<void>::fromConveyor(std::move(caf.conveyor));
return Conveyor<void>::toConveyor(std::move(node_and_storage.first),
node_and_storage.second);
auto node = conveyor<void>::from_conveyor(std::move(caf.conveyor));
return conveyor<void>::to_conveyor(std::move(node));
}
void poll() override { pollImpl(0); }
@ -236,7 +235,7 @@ public:
::send(pipefds[1], &i, sizeof(i), MSG_DONTWAIT);
}
void subscribe(IFdOwner &owner, int fd, uint32_t event_mask) {
void subscribe(i_fd_owner &owner, int fd, uint32_t event_mask) {
if (epoll_fd < 0 || fd < 0) {
return;
}
@ -265,67 +264,67 @@ public:
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 {
class UnixIoStream final : public IoStream, public i_fd_owner {
private:
Own<ConveyorFeeder<void>> read_ready = nullptr;
Own<ConveyorFeeder<void>> on_read_disconnect = nullptr;
Own<ConveyorFeeder<void>> write_ready = nullptr;
own<conveyor_feeder<void>> read_ready = nullptr;
own<conveyor_feeder<void>> on_read_disconnect = nullptr;
own<conveyor_feeder<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;
error_or<size_t> read(void *buffer, size_t length) override;
Conveyor<void> readReady() override;
conveyor<void> readReady() override;
Conveyor<void> onReadDisconnected() override;
conveyor<void> onReadDisconnected() override;
ErrorOr<size_t> write(const void *buffer, size_t length) override;
error_or<size_t> write(const void *buffer, size_t length) override;
Conveyor<void> writeReady() 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<size_t> readDone() override;
conveyor<void> readReady() override;
Conveyor<void> onReadDisconnected() override;
conveyor<void> onReadDisconnected() override;
void write(const void *buffer, size_t length) override;
Conveyor<size_t> writeDone() override;
Conveyor<void> writeReady() override;
conveyor<size_t> writeDone() override;
conveyor<void> writeReady() override;
*/
void notify(uint32_t mask) override;
};
class UnixServer final : public Server, public IFdOwner {
class UnixServer final : public Server, public i_fd_owner {
private:
Own<ConveyorFeeder<Own<IoStream>>> accept_feeder = nullptr;
own<conveyor_feeder<own<IoStream>>> accept_feeder = nullptr;
public:
UnixServer(UnixEventPort &event_port, int file_descriptor, int fd_flags);
Conveyor<Own<IoStream>> accept() override;
conveyor<own<IoStream>> accept() override;
void notify(uint32_t mask) override;
};
class UnixDatagram final : public Datagram, public IFdOwner {
class UnixDatagram final : public Datagram, public i_fd_owner {
private:
Own<ConveyorFeeder<void>> read_ready = nullptr;
Own<ConveyorFeeder<void>> write_ready = nullptr;
own<conveyor_feeder<void>> read_ready = nullptr;
own<conveyor_feeder<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;
error_or<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;
error_or<size_t> write(const void *buffer, size_t length,
NetworkAddress &dest) override;
conveyor<void> writeReady() override;
void notify(uint32_t mask) override;
};
@ -379,8 +378,8 @@ public:
socklen_t getRawLength() const { return address_length; }
static std::vector<SocketAddress> parse(std::string_view str,
uint16_t port_hint) {
static std::vector<SocketAddress> resolve(std::string_view str,
uint16_t port_hint) {
std::vector<SocketAddress> results;
struct ::addrinfo *head;
@ -437,31 +436,31 @@ private:
public:
UnixNetwork(UnixEventPort &event_port);
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &address,
uint16_t port_hint = 0) override;
conveyor<own<NetworkAddress>>
resolveAddress(const std::string &address, uint16_t port_hint = 0) override;
Own<Server> listen(NetworkAddress &addr) override;
own<Server> listen(NetworkAddress &addr) override;
Conveyor<Own<IoStream>> connect(NetworkAddress &addr) override;
conveyor<own<IoStream>> connect(NetworkAddress &addr) override;
Own<Datagram> datagram(NetworkAddress &addr) override;
own<Datagram> datagram(NetworkAddress &addr) override;
};
class UnixIoProvider final : public IoProvider {
private:
UnixEventPort &event_port;
EventLoop event_loop;
UnixEventPort &m_event_port;
event_loop m_event_loop;
UnixNetwork unix_network;
public:
UnixIoProvider(UnixEventPort &port_ref, Own<EventPort> port);
UnixIoProvider(UnixEventPort &port_ref, own<event_port> port);
Network &network() override;
Own<InputStream> wrapInputFd(int fd) override;
own<InputStream> wrapInputFd(int fd) override;
EventLoop &eventLoop();
event_loop &eventLoop();
};
} // namespace unix
} // namespace saw

15
shell.nix Normal file
View File

@ -0,0 +1,15 @@
with import <nixpkgs> {};
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShellNoCC {
name = "forstio";
nativeBuildInputs = [
scons
clang-tools_12
clang-analyzer
clang_12
cppcheck
];
buildInputs = [ gnutls ];
}

View File

@ -12,5 +12,25 @@ dir_path = Dir('.').abspath
env.sources += sorted(glob.glob(dir_path + "/*.cpp"))
env.headers += sorted(glob.glob(dir_path + "/*.h"))
env.tls_sources += sorted(glob.glob(dir_path + "/tls/*.cpp"))
env.tls_headers += sorted(glob.glob(dir_path + "/tls/*.h"))
# Environment for base library
base_lib_env = env.Clone();
## Shared lib
objects_shared = []
base_lib_env.add_source_files(objects_shared, env.sources + env.driver_sources, shared=True);
env.library_shared = base_lib_env.SharedLibrary('#build/forstio', [objects_shared]);
## Static lib
objects_static = []
base_lib_env.add_source_files(objects_static, env.sources + env.driver_sources, shared=False);
env.library_static = base_lib_env.StaticLibrary('#build/forstio', [objects_static]);
# Export to other libs
Export('base_lib_env')
#SConscript("rpc/SConscript");
SConscript("tls/SConscript");
# Set Alias
env.Alias('library_base', [env.library_shared, env.library_static]);
env.Alias('library', ['library_base', 'library_tls']);

View File

@ -1,68 +1,106 @@
#include "async.h"
#include "common.h"
#include "error.h"
#include <algorithm>
#include <cassert>
namespace saw {
namespace {
thread_local EventLoop *local_loop = nullptr;
thread_local event_loop *local_loop = nullptr;
EventLoop &currentEventLoop() {
EventLoop *loop = local_loop;
event_loop &current_event_loop() {
event_loop *loop = local_loop;
assert(loop);
return *loop;
}
} // namespace
ConveyorNode::ConveyorNode() {}
conveyor_node::conveyor_node() {}
ConveyorStorage::ConveyorStorage(ConveyorStorage *c) : child_storage{c} {}
conveyor_node_with_child_mixin::conveyor_node_with_child_mixin(
own<conveyor_node> &&child_, conveyor_node &owner)
: child{std::move(child_)} {
assert(child);
ConveyorStorage::~ConveyorStorage() {
if (parent) {
parent->unlinkChild();
}
child->notify_parent_attached(owner);
}
void ConveyorStorage::unlinkChild() { child_storage = nullptr; }
error_or<own<conveyor_node>>
conveyor_node_with_child_mixin::swap_child(own<conveyor_node> &&swapee) {
SAW_ASSERT(child) {
return critical_error("Child should exist if this function is called");
}
own<conveyor_node> old_child = std::move(child);
void ConveyorEventStorage::setParent(ConveyorStorage *p) {
/**
* We need the parent of the old_child's next storage
*/
conveyor_storage *old_storage = old_child->next_storage();
conveyor_storage *old_storage_parent =
old_storage ? old_storage->get_parent() : nullptr;
/**
* Swap in the new child
*/
if (swapee) {
child = std::move(swapee);
/**
* Then we need to set the new child's storage parent since the next
* storage has a nullptr set And if the old_storage_parent is a nullptr,
* then it doesn't matter. So we don't check for it
*/
conveyor_storage *swapee_storage = child->next_storage();
if (swapee_storage) {
swapee_storage->set_parent(old_storage_parent);
}
}
return old_child;
}
conveyor_storage::conveyor_storage() {}
conveyor_storage::~conveyor_storage() {}
conveyor_storage *conveyor_storage::get_parent() const { return parent; }
void conveyor_event_storage::set_parent(conveyor_storage *p) {
/*
* parent check isn't needed, but is used
* for the assert, because the storage should
* be armed if there was an element present
* and a valid parent
*/
if (/*!parent && */ p && !isArmed() && queued() > 0) {
if (/*!parent && */ p && !is_armed() && queued() > 0) {
assert(!parent);
if (p->space() > 0) {
armLater();
arm_later();
}
}
parent = p;
}
ConveyorEventStorage::ConveyorEventStorage(ConveyorStorage *c)
: ConveyorStorage{c} {}
conveyor_event_storage::conveyor_event_storage() : conveyor_storage{} {}
ConveyorBase::ConveyorBase(Own<ConveyorNode> &&node_p,
ConveyorStorage *storage_p)
: node{std::move(node_p)}, storage{storage_p} {}
conveyor_base::conveyor_base(own<conveyor_node> &&node_p)
: node{std::move(node_p)} {}
Error PropagateError::operator()(const Error &error) const {
return error.copyError();
error propagate_error::operator()(const error &error) const {
return error.copy_error();
}
Error PropagateError::operator()(Error &&error) { return std::move(error); }
error propagate_error::operator()(error &&error) { return std::move(error); }
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);
if (prev == nullptr) {
// Push the next_insert_point back by one
@ -91,11 +129,11 @@ void Event::armNext() {
loop.tail = &next;
}
loop.setRunnable(true);
loop.set_runnable(true);
}
}
void Event::armLater() {
void event::arm_later() {
assert(&loop == local_loop);
if (prev == nullptr) {
@ -111,11 +149,11 @@ void Event::armLater() {
loop.tail = &next;
}
loop.setRunnable(true);
loop.set_runnable(true);
}
}
void Event::armLast() {
void event::arm_last() {
assert(&loop == local_loop);
if (prev == nullptr) {
@ -130,11 +168,11 @@ void Event::armLast() {
loop.tail = &next;
}
loop.setRunnable(true);
loop.set_runnable(true);
}
}
void Event::disarm() {
void event::disarm() {
if (prev != nullptr) {
if (loop.tail == &next) {
loop.tail = prev;
@ -154,33 +192,33 @@ void Event::disarm() {
}
}
bool Event::isArmed() const { return prev != nullptr; }
bool event::is_armed() const { return prev != nullptr; }
SinkConveyor::SinkConveyor() : node{nullptr} {}
conveyor_sink::conveyor_sink() : node{nullptr} {}
SinkConveyor::SinkConveyor(Own<ConveyorNode> &&node_p)
conveyor_sink::conveyor_sink(own<conveyor_node> &&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_port{std::move(event_port)} {}
event_loop::event_loop(own<class event_port> &&event_port_)
: m_event_port{std::move(event_port_)} {}
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);
local_loop = this;
}
void EventLoop::leaveScope() {
void event_loop::leave_scope() {
assert(local_loop == this);
local_loop = nullptr;
}
bool EventLoop::turnLoop() {
bool event_loop::turn_loop() {
size_t turn_step = 0;
while (head && turn_step < 65536) {
if (!turn()) {
@ -191,8 +229,8 @@ bool EventLoop::turnLoop() {
return true;
}
bool EventLoop::turn() {
Event *event = head;
bool event_loop::turn() {
event *event = head;
if (!event) {
return false;
@ -221,127 +259,160 @@ bool EventLoop::turn() {
return true;
}
bool EventLoop::wait(const std::chrono::steady_clock::duration &duration) {
if (event_port) {
event_port->wait(duration);
bool event_loop::wait(const std::chrono::steady_clock::duration &duration) {
if (m_event_port) {
m_event_port->wait(duration);
}
return turnLoop();
return turn_loop();
}
bool EventLoop::wait(const std::chrono::steady_clock::time_point &time_point) {
if (event_port) {
event_port->wait(time_point);
bool event_loop::wait(const std::chrono::steady_clock::time_point &time_point) {
if (m_event_port) {
m_event_port->wait(time_point);
}
return turnLoop();
return turn_loop();
}
bool EventLoop::wait() {
if (event_port) {
event_port->wait();
bool event_loop::wait() {
if (m_event_port) {
m_event_port->wait();
}
return turnLoop();
return turn_loop();
}
bool EventLoop::poll() {
if (event_port) {
event_port->poll();
bool event_loop::poll() {
if (m_event_port) {
m_event_port->poll();
}
return turnLoop();
return turn_loop();
}
EventPort *EventLoop::eventPort() { return event_port.get(); }
event_port *event_loop::event_port() { return m_event_port.get(); }
ConveyorSinks &EventLoop::daemon() {
conveyor_sink_set &event_loop::daemon() {
if (!daemon_sink) {
daemon_sink = heap<ConveyorSinks>();
daemon_sink = heap<conveyor_sink_set>();
}
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);
}
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);
}
void WaitScope::poll() { loop.poll(); }
void wait_scope::poll() { loop.poll(); }
ImmediateConveyorNodeBase::ImmediateConveyorNodeBase()
: ConveyorEventStorage{nullptr} {}
error_or<own<conveyor_node>>
convert_conveyor_node_base::swap_child(own<conveyor_node> &&swapee) noexcept {
return child_mixin.swap_child(std::move(swapee));
}
MergeConveyorNodeBase::MergeConveyorNodeBase()
: ConveyorEventStorage{nullptr} {}
conveyor_storage *convert_conveyor_node_base::next_storage() noexcept {
if (!child_mixin.child) {
return nullptr;
}
return child_mixin.child->next_storage();
}
void ConveyorSinks::destroySinkConveyorNode(ConveyorNode &node) {
if (!isArmed()) {
armLast();
immediate_conveyor_node_base::immediate_conveyor_node_base()
: conveyor_event_storage{} {}
merge_conveyor_node_base::merge_conveyor_node_base()
: conveyor_event_storage{} {}
error_or<own<conveyor_node>> queue_buffer_conveyor_node_base::swap_child(
own<conveyor_node> &&swapee_) noexcept {
return child_mixin.swap_child(std::move(swapee_));
}
void conveyor_sink_set::destroy_sink_conveyor_node(conveyor_node &node) {
if (!is_armed()) {
arm_last();
}
delete_nodes.push(&node);
}
void ConveyorSinks::fail(Error &&error) {
void conveyor_sink_set::fail(error &&error) {
/// @todo call error_handler
}
ConveyorSinks::ConveyorSinks(EventLoop &event_loop) : Event{event_loop} {}
conveyor_sink_set::conveyor_sink_set(event_loop &event_loop)
: event{event_loop} {}
void ConveyorSinks::add(Conveyor<void> &&sink) {
auto nas = Conveyor<void>::fromConveyor(std::move(sink));
void conveyor_sink_set::add(conveyor<void> &&sink) {
auto nas = conveyor<void>::from_conveyor(std::move(sink));
SAW_ASSERT(nas) { return; }
conveyor_storage *storage = nas->next_storage();
Own<SinkConveyorNode> sink_node = nullptr;
own<sink_conveyor_node> sink_node = nullptr;
try {
sink_node =
heap<SinkConveyorNode>(nas.second, std::move(nas.first), *this);
sink_node = heap<sink_conveyor_node>(std::move(nas), *this);
} catch (std::bad_alloc &) {
return;
}
if (nas.second) {
nas.second->setParent(sink_node.get());
if (storage) {
storage->set_parent(sink_node.get());
}
sink_nodes.emplace_back(std::move(sink_node));
}
void ConveyorSinks::fire() {
void conveyor_sink_set::fire() {
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(),
[node](Own<ConveyorNode> &element) {
[node](own<conveyor_node> &element) {
return node == element.get();
});
delete_nodes.pop();
}
}
ConvertConveyorNodeBase::ConvertConveyorNodeBase(Own<ConveyorNode> &&dep)
: child{std::move(dep)} {}
convert_conveyor_node_base::convert_conveyor_node_base(own<conveyor_node> &&dep)
: child_mixin{std::move(dep), *this} {}
void ConvertConveyorNodeBase::getResult(ErrorOrValue &err_or_val) {
getImpl(err_or_val);
void convert_conveyor_node_base::get_result(error_or_value &err_or_val) {
get_impl(err_or_val);
}
void AttachConveyorNodeBase::getResult(ErrorOrValue &err_or_val) noexcept {
if (child) {
child->getResult(err_or_val);
void attach_conveyor_node_base::get_result(
error_or_value &err_or_val) noexcept {
if (child_mixin.child) {
child_mixin.child->get_result(err_or_val);
}
}
void detachConveyor(Conveyor<void> &&conveyor) {
EventLoop &loop = currentEventLoop();
ConveyorSinks &sink = loop.daemon();
error_or<own<conveyor_node>>
attach_conveyor_node_base::swap_child(own<conveyor_node> &&swapee_) noexcept {
return child_mixin.swap_child(std::move(swapee_));
}
conveyor_storage *attach_conveyor_node_base::next_storage() noexcept {
if (!child_mixin.child) {
return nullptr;
}
return child_mixin.child->next_storage();
}
void detach_conveyor(conveyor<void> &&conveyor) {
event_loop &loop = current_event_loop();
conveyor_sink_set &sink = loop.daemon();
sink.add(std::move(conveyor));
}
} // namespace saw

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
#pragma once
#include "common.h"
#include "error.h"
#include <cassert>
// Template inlining
@ -9,172 +10,185 @@
namespace saw {
template <typename Func> ConveyorResult<Func, void> execLater(Func &&func) {
Conveyor<void> conveyor{FixVoid<void>{}};
template <typename Func> conveyor_result<Func, void> exec_later(Func &&func) {
conveyor<void> conveyor{fix_void<void>{}};
return conveyor.then(std::move(func));
}
template <typename T>
Conveyor<T>::Conveyor(FixVoid<T> value) : ConveyorBase(nullptr, nullptr) {
conveyor<T>::conveyor(fix_void<T> value) : conveyor_base(nullptr) {
// Is there any way to do this?
// @todo new ConveyorBase constructor for Immediate values
// @todo new conveyorBase constructor for Immediate values
Own<ImmediateConveyorNode<FixVoid<T>>> immediate =
heap<ImmediateConveyorNode<FixVoid<T>>>(std::move(value));
own<immediate_conveyor_node<fix_void<T>>> immediate =
heap<immediate_conveyor_node<fix_void<T>>>(std::move(value));
if (!immediate) {
return;
}
storage = static_cast<ConveyorStorage *>(immediate.get());
node = std::move(immediate);
}
template <typename T>
Conveyor<T>::Conveyor(Error &&error) : ConveyorBase(nullptr, nullptr) {
Own<ImmediateConveyorNode<FixVoid<T>>> immediate =
heap<ImmediateConveyorNode<FixVoid<T>>>(std::move(error));
conveyor<T>::conveyor(error &&error) : conveyor_base(nullptr) {
own<immediate_conveyor_node<fix_void<T>>> immediate =
heap<immediate_conveyor_node<fix_void<T>>>(std::move(error));
if (!immediate) {
return;
}
storage = static_cast<ConveyorStorage *>(immediate.get());
node = std::move(immediate);
}
template <typename T>
Conveyor<T>::Conveyor(Own<ConveyorNode> node_p, ConveyorStorage *storage_p)
: ConveyorBase{std::move(node_p), storage_p} {}
conveyor<T>::conveyor(own<conveyor_node> node_p)
: conveyor_base{std::move(node_p)} {}
template <typename T>
template <typename Func, typename ErrorFunc>
ConveyorResult<Func, T> Conveyor<T>::then(Func &&func, ErrorFunc &&error_func) {
Own<ConveyorNode> conversion_node =
heap<ConvertConveyorNode<FixVoid<ReturnType<Func, T>>, FixVoid<T>, Func,
ErrorFunc>>(std::move(node), std::move(func),
std::move(error_func));
conveyor_result<Func, T> conveyor<T>::then(Func &&func,
ErrorFunc &&error_func) {
own<conveyor_node> conversion_node =
heap<convert_conveyor_node<fix_void<return_type<Func, T>>, fix_void<T>,
Func, ErrorFunc>>(
std::move(node), std::move(func), std::move(error_func));
return Conveyor<RemoveErrorOr<ReturnType<Func, T>>>::toConveyor(
std::move(conversion_node), storage);
return conveyor<remove_error_or<return_type<Func, T>>>::to_conveyor(
std::move(conversion_node));
}
template <typename T> Conveyor<T> Conveyor<T>::buffer(size_t size) {
Own<QueueBufferConveyorNode<FixVoid<T>>> storage_node =
heap<QueueBufferConveyorNode<FixVoid<T>>>(storage, std::move(node),
size);
ConveyorStorage *storage_ptr =
static_cast<ConveyorStorage *>(storage_node.get());
SAW_ASSERT(storage) { return Conveyor<T>{nullptr, nullptr}; }
template <typename T> conveyor<T> conveyor<T>::buffer(size_t size) {
SAW_ASSERT(node) { return conveyor<T>{own<conveyor_node>{nullptr}}; }
conveyor_storage *storage = node->next_storage();
SAW_ASSERT(storage) { return conveyor<T>{own<conveyor_node>{nullptr}}; }
storage->setParent(storage_ptr);
return Conveyor<T>{std::move(storage_node), storage_ptr};
own<queue_buffer_conveyor_node<fix_void<T>>> storage_node =
heap<queue_buffer_conveyor_node<fix_void<T>>>(std::move(node), size);
conveyor_storage *storage_ptr =
static_cast<conveyor_storage *>(storage_node.get());
storage->set_parent(storage_ptr);
return conveyor<T>{std::move(storage_node)};
}
template <typename T>
template <typename... Args>
Conveyor<T> Conveyor<T>::attach(Args &&...args) {
Own<AttachConveyorNode<Args...>> attach_node =
heap<AttachConveyorNode<Args...>>(std::move(node), std::move(args...));
return Conveyor<T>{std::move(attach_node), storage};
conveyor<T> conveyor<T>::attach(Args &&...args) {
own<attach_conveyor_node<Args...>> attach_node =
heap<attach_conveyor_node<Args...>>(std::move(node),
std::move(args...));
return conveyor<T>{std::move(attach_node)};
}
template <typename T>
std::pair<Conveyor<T>, MergeConveyor<T>> Conveyor<T>::merge() {
Our<MergeConveyorNodeData<T>> data = share<MergeConveyorNodeData<T>>();
std::pair<conveyor<T>, merge_conveyor<T>> conveyor<T>::merge() {
our<merge_conveyor_node_data<T>> data =
share<merge_conveyor_node_data<T>>();
Own<MergeConveyorNode<T>> merge_node = heap<MergeConveyorNode<T>>(data);
own<merge_conveyor_node<T>> merge_node = heap<merge_conveyor_node<T>>(data);
data->attach(Conveyor<T>::toConveyor(std::move(node), storage));
SAW_ASSERT(node) {
return std::make_pair(conveyor<T>{own<conveyor_node>{nullptr}},
merge_conveyor<T>{});
}
conveyor_storage *storage = node->next_storage();
SAW_ASSERT(storage) {
return std::make_pair(conveyor<T>{own<conveyor_node>{nullptr}},
merge_conveyor<T>{});
}
MergeConveyor<T> node_ref{data};
data->attach(conveyor<T>::to_conveyor(std::move(node)));
ConveyorStorage *merge_storage =
static_cast<ConveyorStorage *>(merge_node.get());
merge_conveyor<T> node_ref{data};
return std::make_pair(Conveyor<T>{std::move(merge_node), merge_storage},
return std::make_pair(conveyor<T>{std::move(merge_node)},
std::move(node_ref));
}
template <>
template <typename ErrorFunc>
SinkConveyor Conveyor<void>::sink(ErrorFunc &&error_func) {
Own<SinkConveyorNode> sink_node =
heap<SinkConveyorNode>(storage, std::move(node));
ConveyorStorage *storage_ptr =
static_cast<ConveyorStorage *>(sink_node.get());
conveyor_sink conveyor<void>::sink(ErrorFunc &&error_func) {
conveyor_storage *storage = node->next_storage();
SAW_ASSERT(storage) { return conveyor_sink{}; }
SAW_ASSERT(storage) { return SinkConveyor{}; }
storage->setParent(storage_ptr);
own<sink_conveyor_node> sink_node =
heap<sink_conveyor_node>(std::move(node));
conveyor_storage *storage_ptr =
static_cast<conveyor_storage *>(sink_node.get());
return SinkConveyor{std::move(sink_node)};
storage->set_parent(storage_ptr);
return conveyor_sink{std::move(sink_node)};
}
void detachConveyor(Conveyor<void> &&conveyor);
void detach_conveyor(conveyor<void> &&conveyor);
template <typename T>
template <typename ErrorFunc>
void Conveyor<T>::detach(ErrorFunc &&func) {
detachConveyor(std::move(then([](T &&) {}, std::move(func))));
void conveyor<T>::detach(ErrorFunc &&func) {
detach_conveyor(std::move(then([](T &&) {}, std::move(func))));
}
template <>
template <typename ErrorFunc>
void Conveyor<void>::detach(ErrorFunc &&func) {
detachConveyor(std::move(then([]() {}, std::move(func))));
void conveyor<void>::detach(ErrorFunc &&func) {
detach_conveyor(std::move(then([]() {}, std::move(func))));
}
template <typename T>
Conveyor<T> Conveyor<T>::toConveyor(Own<ConveyorNode> node,
ConveyorStorage *storage) {
return Conveyor<T>{std::move(node), storage};
conveyor<T> conveyor<T>::to_conveyor(own<conveyor_node> node) {
return conveyor<T>{std::move(node)};
}
template <typename T>
std::pair<Own<ConveyorNode>, ConveyorStorage *>
Conveyor<T>::fromConveyor(Conveyor<T> conveyor) {
return std::make_pair(std::move(conveyor.node), conveyor.storage);
own<conveyor_node> conveyor<T>::from_conveyor(conveyor<T> conveyor) {
return std::move(conveyor.node);
}
template <typename T> ErrorOr<FixVoid<T>> Conveyor<T>::take() {
template <typename T> error_or<fix_void<T>> conveyor<T>::take() {
SAW_ASSERT(node) {
return error_or<fix_void<T>>{
critical_error("conveyor in invalid state")};
}
conveyor_storage *storage = node->next_storage();
if (storage) {
if (storage->queued() > 0) {
ErrorOr<FixVoid<T>> result;
node->getResult(result);
error_or<fix_void<T>> result;
node->get_result(result);
return result;
} else {
return ErrorOr<FixVoid<T>>{
recoverableError("Conveyor buffer has no elements")};
return error_or<fix_void<T>>{
recoverable_error("conveyor buffer has no elements")};
}
} else {
return ErrorOr<FixVoid<T>>{criticalError("Conveyor in invalid state")};
return error_or<fix_void<T>>{
critical_error("conveyor node has no child storage")};
}
}
template <typename T> ConveyorAndFeeder<T> newConveyorAndFeeder() {
Own<AdaptConveyorFeeder<FixVoid<T>>> feeder =
heap<AdaptConveyorFeeder<FixVoid<T>>>();
Own<AdaptConveyorNode<FixVoid<T>>> node =
heap<AdaptConveyorNode<FixVoid<T>>>();
template <typename T> conveyor_and_feeder<T> new_conveyor_and_feeder() {
own<adapt_conveyor_feeder<fix_void<T>>> feeder =
heap<adapt_conveyor_feeder<fix_void<T>>>();
own<adapt_conveyor_node<fix_void<T>>> node =
heap<adapt_conveyor_node<fix_void<T>>>();
feeder->setFeedee(node.get());
node->setFeeder(feeder.get());
feeder->set_feedee(node.get());
node->set_feeder(feeder.get());
ConveyorStorage *storage_ptr = static_cast<ConveyorStorage *>(node.get());
return ConveyorAndFeeder<T>{
std::move(feeder),
Conveyor<T>::toConveyor(std::move(node), storage_ptr)};
return conveyor_and_feeder<T>{std::move(feeder),
conveyor<T>::to_conveyor(std::move(node))};
}
// QueueBuffer
template <typename T> void QueueBufferConveyorNode<T>::fire() {
if (child) {
template <typename T> void queue_buffer_conveyor_node<T>::fire() {
if (child_mixin.child) {
if (!storage.empty()) {
if (storage.front().isError()) {
if (storage.front().error().isCritical()) {
child = nullptr;
child_storage = nullptr;
if (storage.front().is_error()) {
if (storage.front().error().is_critical()) {
child_mixin.child = nullptr;
}
}
}
@ -183,51 +197,58 @@ template <typename T> void QueueBufferConveyorNode<T>::fire() {
bool has_space_before_fire = space() > 0;
if (parent) {
parent->childHasFired();
parent->child_has_fired();
if (!storage.empty() && parent->space() > 0) {
armLater();
arm_later();
}
}
if (child_storage && !has_space_before_fire) {
child_storage->parentHasFired();
if (!child_mixin.child) {
while (!storage.empty()) {
storage.pop();
}
return;
}
conveyor_storage *ch_storage = child_mixin.child->next_storage();
if (ch_storage && !has_space_before_fire) {
ch_storage->parent_has_fired();
}
}
template <typename T>
void QueueBufferConveyorNode<T>::getResult(ErrorOrValue &eov) noexcept {
ErrorOr<T> &err_or_val = eov.as<T>();
void queue_buffer_conveyor_node<T>::get_result(error_or_value &eov) noexcept {
error_or<T> &err_or_val = eov.as<T>();
err_or_val = std::move(storage.front());
storage.pop();
}
template <typename T> size_t QueueBufferConveyorNode<T>::space() const {
template <typename T> size_t queue_buffer_conveyor_node<T>::space() const {
return max_store - storage.size();
}
template <typename T> size_t QueueBufferConveyorNode<T>::queued() const {
template <typename T> size_t queue_buffer_conveyor_node<T>::queued() const {
return storage.size();
}
template <typename T> void QueueBufferConveyorNode<T>::childHasFired() {
if (child && storage.size() < max_store) {
ErrorOr<T> eov;
child->getResult(eov);
template <typename T> void queue_buffer_conveyor_node<T>::child_has_fired() {
if (child_mixin.child && storage.size() < max_store) {
error_or<T> eov;
child_mixin.child->get_result(eov);
if (eov.isError()) {
if (eov.error().isCritical()) {
child_storage = nullptr;
if (eov.is_error()) {
if (eov.error().is_critical()) {
}
}
storage.push(std::move(eov));
if (!isArmed()) {
armLater();
if (!is_armed()) {
arm_later();
}
}
}
template <typename T> void QueueBufferConveyorNode<T>::parentHasFired() {
template <typename T> void queue_buffer_conveyor_node<T>::parent_has_fired() {
SAW_ASSERT(parent) { return; }
if (parent->space() == 0) {
@ -235,57 +256,57 @@ template <typename T> void QueueBufferConveyorNode<T>::parentHasFired() {
}
if (queued() > 0) {
armLater();
arm_later();
}
}
template <typename T>
ImmediateConveyorNode<T>::ImmediateConveyorNode(FixVoid<T> &&val)
immediate_conveyor_node<T>::immediate_conveyor_node(fix_void<T> &&val)
: value{std::move(val)}, retrieved{0} {}
template <typename T>
ImmediateConveyorNode<T>::ImmediateConveyorNode(Error &&error)
immediate_conveyor_node<T>::immediate_conveyor_node(error &&error)
: value{std::move(error)}, retrieved{0} {}
template <typename T> size_t ImmediateConveyorNode<T>::space() const {
template <typename T> size_t immediate_conveyor_node<T>::space() const {
return 0;
}
template <typename T> size_t ImmediateConveyorNode<T>::queued() const {
template <typename T> size_t immediate_conveyor_node<T>::queued() const {
return retrieved > 1 ? 0 : 1;
}
template <typename T> void ImmediateConveyorNode<T>::childHasFired() {
template <typename T> void immediate_conveyor_node<T>::child_has_fired() {
// Impossible case
assert(false);
}
template <typename T> void ImmediateConveyorNode<T>::parentHasFired() {
template <typename T> void immediate_conveyor_node<T>::parent_has_fired() {
SAW_ASSERT(parent) { return; }
assert(parent->space() > 0);
if (queued() > 0) {
armNext();
arm_next();
}
}
template <typename T> void ImmediateConveyorNode<T>::fire() {
template <typename T> void immediate_conveyor_node<T>::fire() {
if (parent) {
parent->childHasFired();
parent->child_has_fired();
if (queued() > 0 && parent->space() > 0) {
armLast();
arm_last();
}
}
}
template <typename T>
MergeConveyor<T>::MergeConveyor(Lent<MergeConveyorNodeData<T>> d)
merge_conveyor<T>::merge_conveyor(lent<merge_conveyor_node_data<T>> d)
: data{std::move(d)} {}
template <typename T> MergeConveyor<T>::~MergeConveyor() {}
template <typename T> merge_conveyor<T>::~merge_conveyor() {}
template <typename T> void MergeConveyor<T>::attach(Conveyor<T> conveyor) {
template <typename T> void merge_conveyor<T>::attach(conveyor<T> conveyor) {
auto sp = data.lock();
SAW_ASSERT(sp) { return; }
@ -293,18 +314,26 @@ template <typename T> void MergeConveyor<T>::attach(Conveyor<T> conveyor) {
}
template <typename T>
MergeConveyorNode<T>::MergeConveyorNode(Our<MergeConveyorNodeData<T>> d)
merge_conveyor_node<T>::merge_conveyor_node(our<merge_conveyor_node_data<T>> d)
: data{d} {
SAW_ASSERT(data) { return; }
data->merger = this;
}
template <typename T> MergeConveyorNode<T>::~MergeConveyorNode() {}
template <typename T> merge_conveyor_node<T>::~merge_conveyor_node() {}
template <typename T>
void MergeConveyorNode<T>::getResult(ErrorOrValue &eov) noexcept {
ErrorOr<FixVoid<T>> &err_or_val = eov.as<FixVoid<T>>();
error_or<own<conveyor_node>>
merge_conveyor_node<T>::swap_child(own<conveyor_node> &&swapee_) noexcept {
(void)swapee_;
return critical_error(
"MergeconveyorNode<T>::appendage should block calls to this class");
}
template <typename T>
void merge_conveyor_node<T>::get_result(error_or_value &eov) noexcept {
error_or<fix_void<T>> &err_or_val = eov.as<fix_void<T>>();
SAW_ASSERT(data) { return; }
@ -315,39 +344,39 @@ void MergeConveyorNode<T>::getResult(ErrorOrValue &eov) noexcept {
for (size_t i = next_appendage; i < appendages.size(); ++i) {
if (appendages[i]->queued() > 0) {
err_or_val = std::move(appendages[i]->error_or_value.value());
appendages[i]->error_or_value = std::nullopt;
err_or_val = std::move(appendages[i]->error_or_value_data.value());
appendages[i]->error_or_value_data = std::nullopt;
next_appendage = i + 1;
return;
}
}
for (size_t i = 0; i < next_appendage; ++i) {
if (appendages[i]->queued() > 0) {
err_or_val = std::move(appendages[i]->error_or_value.value());
appendages[i]->error_or_value = std::nullopt;
err_or_val = std::move(appendages[i]->error_or_value_data.value());
appendages[i]->error_or_value_data = std::nullopt;
next_appendage = i + 1;
return;
}
}
err_or_val = criticalError("No value in Merge Appendages");
err_or_val = critical_error("No value in Merge appendages");
}
template <typename T> void MergeConveyorNode<T>::fire() {
template <typename T> void merge_conveyor_node<T>::fire() {
SAW_ASSERT(queued() > 0) { return; }
if (parent) {
parent->childHasFired();
parent->child_has_fired();
if (queued() > 0 && parent->space() > 0) {
armLater();
arm_later();
}
}
}
template <typename T> size_t MergeConveyorNode<T>::space() const { return 0; }
template <typename T> size_t merge_conveyor_node<T>::space() const { return 0; }
template <typename T> size_t MergeConveyorNode<T>::queued() const {
template <typename T> size_t merge_conveyor_node<T>::queued() const {
SAW_ASSERT(data) { return 0; }
size_t queue_count = 0;
@ -359,73 +388,110 @@ template <typename T> size_t MergeConveyorNode<T>::queued() const {
return queue_count;
}
template <typename T> void MergeConveyorNode<T>::childHasFired() {
template <typename T> void merge_conveyor_node<T>::child_has_fired() {
/// This can never happen
assert(false);
}
template <typename T> void MergeConveyorNode<T>::parentHasFired() {
template <typename T> void merge_conveyor_node<T>::parent_has_fired() {
SAW_ASSERT(parent) { return; }
if (queued() > 0) {
if (parent->space() > 0) {
armLater();
arm_later();
}
}
}
template <typename T> size_t MergeConveyorNode<T>::Appendage::space() const {
/**
* MergeconveyorNode<T>::Apendage
*/
template <typename T>
error_or<own<conveyor_node>>
merge_conveyor_node<T>::appendage::swap_child(own<conveyor_node> &&swapee_) {
own<conveyor_node> old_child = std::move(child);
child = std::move(swapee_);
// This case should never happen
SAW_ASSERT(old_child) { return critical_error("No child exists"); }
return old_child;
}
template <typename T>
void merge_conveyor_node<T>::appendage::get_result(error_or_value &eov) {
error_or<fix_void<T>> &err_or_val = eov.as<fix_void<T>>();
SAW_ASSERT(queued() > 0) {
err_or_val =
critical_error("No element queued in Merge appendage Node");
return;
}
err_or_val = std::move(error_or_value_data.value());
error_or_value_data = std::nullopt;
}
template <typename T> size_t merge_conveyor_node<T>::appendage::space() const {
SAW_ASSERT(merger) { return 0; }
if (error_or_value.has_value()) {
if (error_or_value_data.has_value()) {
return 0;
}
return 1;
}
template <typename T> size_t MergeConveyorNode<T>::Appendage::queued() const {
template <typename T> size_t merge_conveyor_node<T>::appendage::queued() const {
SAW_ASSERT(merger) { return 0; }
if (error_or_value.has_value()) {
if (error_or_value_data.has_value()) {
return 1;
}
return 0;
}
/// @todo delete this function. Replaced by the regular getResult
template <typename T>
void MergeConveyorNode<T>::Appendage::getAppendageResult(ErrorOrValue &eov) {
ErrorOr<FixVoid<T>> &err_or_val = eov.as<FixVoid<T>>();
void merge_conveyor_node<T>::appendage::get_appendage_result(
error_or_value &eov) {
error_or<fix_void<T>> &err_or_val = eov.as<fix_void<T>>();
SAW_ASSERT(queued() > 0) {
err_or_val = criticalError("No element queued in Merge Appendage Node");
err_or_val =
critical_error("No element queued in Merge appendage Node");
return;
}
err_or_val = std::move(error_or_value.value());
error_or_value = std::nullopt;
err_or_val = std::move(error_or_value_data.value());
error_or_value_data = std::nullopt;
}
template <typename T> void MergeConveyorNode<T>::Appendage::childHasFired() {
SAW_ASSERT(!error_or_value.has_value()) { return; }
ErrorOr<FixVoid<T>> eov;
child->getResult(eov);
template <typename T>
void merge_conveyor_node<T>::appendage::child_has_fired() {
SAW_ASSERT(!error_or_value_data.has_value()) { return; }
error_or<fix_void<T>> eov;
child->get_result(eov);
error_or_value = std::move(eov);
error_or_value_data = std::move(eov);
if (!merger->isArmed()) {
merger->armLater();
}
}
template <typename T> void MergeConveyorNode<T>::Appendage::parentHasFired() {
if (child_storage) {
child_storage->parentHasFired();
if (!merger->is_armed()) {
merger->arm_later();
}
}
template <typename T>
void MergeConveyorNode<T>::Appendage::setParent(ConveyorStorage *par) {
void merge_conveyor_node<T>::appendage::parent_has_fired() {
conveyor_storage *child_storage = child->next_storage();
if (child_storage) {
child_storage->parent_has_fired();
}
}
template <typename T>
void merge_conveyor_node<T>::appendage::set_parent(conveyor_storage *par) {
SAW_ASSERT(merger) { return; }
SAW_ASSERT(child) { return; }
@ -434,56 +500,67 @@ void MergeConveyorNode<T>::Appendage::setParent(ConveyorStorage *par) {
}
template <typename T>
void MergeConveyorNodeData<T>::attach(Conveyor<T> conveyor) {
auto nas = Conveyor<T>::fromConveyor(std::move(conveyor));
void merge_conveyor_node_data<T>::attach(conveyor<T> conv) {
auto nas = conveyor<T>::from_conveyor(std::move(conv));
SAW_ASSERT(nas) { return; }
conveyor_storage *storage = nas->next_storage();
SAW_ASSERT(storage) { return; }
auto merge_node_appendage = heap<typename MergeConveyorNode<T>::Appendage>(
nas.second, std::move(nas.first), *merger);
auto merge_node_appendage =
heap<typename merge_conveyor_node<T>::appendage>(std::move(nas),
*merger);
auto merge_node_appendage_ptr = merge_node_appendage.get();
if (nas.second) {
nas.second->setParent(merge_node_appendage.get());
}
storage->set_parent(merge_node_appendage.get());
SAW_ASSERT(merger) { return; }
conveyor_storage *mrg_storage = merger->next_storage();
SAW_ASSERT(mrg_storage) { return; }
merge_node_appendage->set_parent(mrg_storage);
appendages.push_back(std::move(merge_node_appendage));
}
template <typename T> void MergeConveyorNodeData<T>::governingNodeDestroyed() {
template <typename T>
void merge_conveyor_node_data<T>::governing_node_destroyed() {
appendages.clear();
merger = nullptr;
}
template <typename T> AdaptConveyorFeeder<T>::~AdaptConveyorFeeder() {
template <typename T> adapt_conveyor_feeder<T>::~adapt_conveyor_feeder() {
if (feedee) {
feedee->setFeeder(nullptr);
feedee->set_feeder(nullptr);
feedee = nullptr;
}
}
template <typename T>
void AdaptConveyorFeeder<T>::setFeedee(AdaptConveyorNode<T> *feedee_p) {
void adapt_conveyor_feeder<T>::set_feedee(adapt_conveyor_node<T> *feedee_p) {
feedee = feedee_p;
}
template <typename T> void AdaptConveyorFeeder<T>::feed(T &&value) {
template <typename T> void adapt_conveyor_feeder<T>::feed(T &&value) {
if (feedee) {
feedee->feed(std::move(value));
}
}
template <typename T> void AdaptConveyorFeeder<T>::fail(Error &&error) {
template <typename T> void adapt_conveyor_feeder<T>::fail(error &&error) {
if (feedee) {
feedee->fail(std::move(error));
}
}
template <typename T> size_t AdaptConveyorFeeder<T>::queued() const {
template <typename T> size_t adapt_conveyor_feeder<T>::queued() const {
if (feedee) {
return feedee->queued();
}
return 0;
}
template <typename T> size_t AdaptConveyorFeeder<T>::space() const {
template <typename T> size_t adapt_conveyor_feeder<T>::space() const {
if (feedee) {
return feedee->space();
}
@ -491,56 +568,95 @@ template <typename T> size_t AdaptConveyorFeeder<T>::space() const {
}
template <typename T>
AdaptConveyorNode<T>::AdaptConveyorNode() : ConveyorEventStorage{nullptr} {}
error adapt_conveyor_feeder<T>::swap(conveyor<T> &&conv) noexcept {
SAW_ASSERT(feedee) { return critical_error("No feedee connected"); }
template <typename T> AdaptConveyorNode<T>::~AdaptConveyorNode() {
auto node = conveyor<T>::from_conveyor(std::move(conv));
feedee->swap_child(std::move(node));
return no_error();
}
template <typename T>
adapt_conveyor_node<T>::adapt_conveyor_node() : conveyor_event_storage{} {}
template <typename T> adapt_conveyor_node<T>::~adapt_conveyor_node() {
if (feeder) {
feeder->setFeedee(nullptr);
feeder->set_feedee(nullptr);
feeder = nullptr;
}
}
template <typename T>
void AdaptConveyorNode<T>::setFeeder(AdaptConveyorFeeder<T> *feeder_p) {
error_or<own<conveyor_node>>
adapt_conveyor_node<T>::swap_child(own<conveyor_node> &&swapee) noexcept {
// This should return the owning pointer of this instance
auto myself_err = parent_node.swap_child_of_parent(std::move(swapee));
if (myself_err.is_error()) {
return myself_err;
}
auto &myself = myself_err.value();
assert(myself.get() == this);
return myself_err;
}
template <typename T>
conveyor_storage *adapt_conveyor_node<T>::next_storage() noexcept {
return static_cast<conveyor_storage *>(this);
}
template <typename T>
void adapt_conveyor_node<T>::notify_parent_attached(
conveyor_node &par) noexcept {
parent_node.change_parent(&par);
}
template <typename T>
void adapt_conveyor_node<T>::set_feeder(adapt_conveyor_feeder<T> *feeder_p) {
feeder = feeder_p;
}
template <typename T> void AdaptConveyorNode<T>::feed(T &&value) {
template <typename T> void adapt_conveyor_node<T>::feed(T &&value) {
storage.push(std::move(value));
armNext();
arm_next();
}
template <typename T> void AdaptConveyorNode<T>::fail(Error &&error) {
template <typename T> void adapt_conveyor_node<T>::fail(error &&error) {
storage.push(std::move(error));
armNext();
arm_next();
}
template <typename T> size_t AdaptConveyorNode<T>::queued() const {
template <typename T> size_t adapt_conveyor_node<T>::queued() const {
return storage.size();
}
template <typename T> size_t AdaptConveyorNode<T>::space() const {
template <typename T> size_t adapt_conveyor_node<T>::space() const {
return std::numeric_limits<size_t>::max() - storage.size();
}
template <typename T>
void AdaptConveyorNode<T>::getResult(ErrorOrValue &err_or_val) {
void adapt_conveyor_node<T>::get_result(error_or_value &err_or_val) {
if (!storage.empty()) {
err_or_val.as<T>() = std::move(storage.front());
storage.pop();
} else {
err_or_val.as<T>() =
criticalError("Signal for retrieval of storage sent even though no "
"data is present");
err_or_val.as<T>() = critical_error(
"Signal for retrieval of storage sent even though no "
"data is present");
}
}
template <typename T> void AdaptConveyorNode<T>::childHasFired() {
template <typename T> void adapt_conveyor_node<T>::child_has_fired() {
// Adapt node has no children
assert(false);
}
template <typename T> void AdaptConveyorNode<T>::parentHasFired() {
template <typename T> void adapt_conveyor_node<T>::parent_has_fired() {
SAW_ASSERT(parent) { return; }
if (parent->space() == 0) {
@ -548,99 +664,101 @@ template <typename T> void AdaptConveyorNode<T>::parentHasFired() {
}
}
template <typename T> void AdaptConveyorNode<T>::fire() {
template <typename T> void adapt_conveyor_node<T>::fire() {
if (parent) {
parent->childHasFired();
parent->child_has_fired();
if (storage.size() > 0) {
armLater();
arm_later();
}
}
}
template <typename T> OneTimeConveyorFeeder<T>::~OneTimeConveyorFeeder() {
template <typename T> one_time_conveyor_feeder<T>::~one_time_conveyor_feeder() {
if (feedee) {
feedee->setFeeder(nullptr);
feedee->set_feeder(nullptr);
feedee = nullptr;
}
}
template <typename T>
void OneTimeConveyorFeeder<T>::setFeedee(OneTimeConveyorNode<T> *feedee_p) {
void one_time_conveyor_feeder<T>::set_feedee(
one_time_conveyor_node<T> *feedee_p) {
feedee = feedee_p;
}
template <typename T> void OneTimeConveyorFeeder<T>::feed(T &&value) {
template <typename T> void one_time_conveyor_feeder<T>::feed(T &&value) {
if (feedee) {
feedee->feed(std::move(value));
}
}
template <typename T> void OneTimeConveyorFeeder<T>::fail(Error &&error) {
template <typename T> void one_time_conveyor_feeder<T>::fail(error &&error) {
if (feedee) {
feedee->fail(std::move(error));
}
}
template <typename T> size_t OneTimeConveyorFeeder<T>::queued() const {
template <typename T> size_t one_time_conveyor_feeder<T>::queued() const {
if (feedee) {
return feedee->queued();
}
return 0;
}
template <typename T> size_t OneTimeConveyorFeeder<T>::space() const {
template <typename T> size_t one_time_conveyor_feeder<T>::space() const {
if (feedee) {
return feedee->space();
}
return 0;
}
template <typename T> OneTimeConveyorNode<T>::~OneTimeConveyorNode() {
template <typename T> one_time_conveyor_node<T>::~one_time_conveyor_node() {
if (feeder) {
feeder->setFeedee(nullptr);
feeder->set_feedee(nullptr);
feeder = nullptr;
}
}
template <typename T>
void OneTimeConveyorNode<T>::setFeeder(OneTimeConveyorFeeder<T> *feeder_p) {
void one_time_conveyor_node<T>::set_feeder(
one_time_conveyor_feeder<T> *feeder_p) {
feeder = feeder_p;
}
template <typename T> void OneTimeConveyorNode<T>::feed(T &&value) {
template <typename T> void one_time_conveyor_node<T>::feed(T &&value) {
storage = std::move(value);
armNext();
arm_next();
}
template <typename T> void OneTimeConveyorNode<T>::fail(Error &&error) {
template <typename T> void one_time_conveyor_node<T>::fail(error &&error) {
storage = std::move(error);
armNext();
arm_next();
}
template <typename T> size_t OneTimeConveyorNode<T>::queued() const {
template <typename T> size_t one_time_conveyor_node<T>::queued() const {
return storage.has_value() ? 1 : 0;
}
template <typename T> size_t OneTimeConveyorNode<T>::space() const {
template <typename T> size_t one_time_conveyor_node<T>::space() const {
return passed ? 0 : 1;
}
template <typename T>
void OneTimeConveyorNode<T>::getResult(ErrorOrValue &err_or_val) {
void one_time_conveyor_node<T>::get_result(error_or_value &err_or_val) {
if (storage.has_value()) {
err_or_val.as<T>() = std::move(storage.value());
storage = std::nullopt;
} else {
err_or_val.as<T>() =
criticalError("Signal for retrieval of storage sent even though no "
"data is present");
err_or_val.as<T>() = critical_error(
"Signal for retrieval of storage sent even though no "
"data is present");
}
}
template <typename T> void OneTimeConveyorNode<T>::fire() {
template <typename T> void one_time_conveyor_node<T>::fire() {
if (parent) {
parent->childHasFired();
parent->child_has_fired();
}
}

View File

@ -7,19 +7,19 @@
#include <sstream>
namespace saw {
Error Buffer::push(const uint8_t &value) {
error Buffer::push(const uint8_t &value) {
size_t write_remain = writeCompositeLength();
if (write_remain > 0) {
write() = value;
writeAdvance(1);
} else {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
return noError();
return no_error();
}
Error Buffer::push(const uint8_t &buffer, size_t size) {
Error error = writeRequireLength(size);
error Buffer::push(const uint8_t &buffer, size_t size) {
error error = writeRequireLength(size);
if (error.failed()) {
return error;
}
@ -31,20 +31,20 @@ Error Buffer::push(const uint8_t &buffer, size_t size) {
size -= segment;
buffer_ptr += segment;
}
return noError();
return no_error();
}
Error Buffer::pop(uint8_t &value) {
error Buffer::pop(uint8_t &value) {
if (readCompositeLength() > 0) {
value = read();
readAdvance(1);
} else {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
return noError();
return no_error();
}
Error Buffer::pop(uint8_t &buffer, size_t size) {
error Buffer::pop(uint8_t &buffer, size_t size) {
if (readCompositeLength() >= size) {
uint8_t *buffer_ptr = &buffer;
while (size > 0) {
@ -55,9 +55,9 @@ Error Buffer::pop(uint8_t &buffer, size_t size) {
buffer_ptr += segment;
}
} else {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
return noError();
return no_error();
}
std::string Buffer::toString() const {
@ -183,7 +183,7 @@ const uint8_t &BufferView::write(size_t i) const {
return buffer.write(pos);
}
Error BufferView::writeRequireLength(size_t bytes) {
error BufferView::writeRequireLength(size_t bytes) {
return buffer.writeRequireLength(bytes + write_offset);
}
@ -327,7 +327,7 @@ const uint8_t &RingBuffer::write(size_t i) const {
return buffer[pos];
}
/*
Error RingBuffer::increaseSize(size_t size){
error RingBuffer::increaseSize(size_t size){
size_t old_size = buffer.size();
size_t new_size = old_size + size;
buffer.resize(new_size);
@ -341,15 +341,15 @@ const uint8_t &RingBuffer::write(size_t i) const {
}
}
return noError();
return no_error();
}
*/
Error RingBuffer::writeRequireLength(size_t bytes) {
error RingBuffer::writeRequireLength(size_t bytes) {
size_t write_remain = writeCompositeLength();
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} {
@ -421,12 +421,12 @@ const uint8_t &ArrayBuffer::write(size_t i) const {
assert(i < writeCompositeLength());
return buffer[i + write_position];
}
Error ArrayBuffer::writeRequireLength(size_t bytes) {
error ArrayBuffer::writeRequireLength(size_t bytes) {
size_t write_remain = writeCompositeLength();
if (bytes > write_remain) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
return noError();
return no_error();
}
} // namespace saw

View File

@ -40,12 +40,12 @@ public:
* There is nothing you can do if read hasn't been filled, but at
* least write can be increased if it is demanded.
*/
virtual Error writeRequireLength(size_t bytes) = 0;
virtual error writeRequireLength(size_t bytes) = 0;
Error push(const uint8_t &value);
Error push(const uint8_t &buffer, size_t size);
Error pop(uint8_t &value);
Error pop(uint8_t &buffer, size_t size);
error push(const uint8_t &value);
error push(const uint8_t &buffer, size_t size);
error pop(uint8_t &value);
error pop(uint8_t &buffer, size_t size);
std::string toString() const;
std::string toHex() const;
@ -80,7 +80,7 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error writeRequireLength(size_t bytes) override;
error writeRequireLength(size_t bytes) override;
size_t readOffset() const;
size_t writeOffset() const;
@ -126,7 +126,7 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error writeRequireLength(size_t bytes) override;
error writeRequireLength(size_t bytes) override;
};
/*
@ -158,7 +158,7 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error writeRequireLength(size_t bytes) override;
error writeRequireLength(size_t bytes) override;
};
class ChainArrayBuffer : public Buffer {
@ -187,6 +187,6 @@ public:
uint8_t &write(size_t i = 0) override;
const uint8_t &write(size_t i = 0) const override;
Error writeRequireLength(size_t bytes) override;
error writeRequireLength(size_t bytes) override;
};
} // namespace saw

View File

@ -27,46 +27,53 @@ namespace saw {
classname(classname &&) = default; \
classname &operator=(classname &&) = default
// In case of C++20
#define SAW_ASSERT(expression) \
assert(expression); \
if (!(expression))
if (!(expression)) [[unlikely]]
template <typename T> using Maybe = std::optional<T>;
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) {
return Own<T>(new T(std::forward<Args>(args)...));
template <typename T, class... Args> own<T> heap(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)...);
}
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;
};
template <typename Func> struct ReturnTypeHelper<Func, void> {
template <typename Func> struct return_type_helper<Func, void> {
typedef decltype(instance<Func>()()) Type;
};
template <typename Func, typename T>
using ReturnType = typename ReturnTypeHelper<Func, T>::Type;
using return_type = typename return_type_helper<Func, T>::Type;
// NOLINTBEGIN
struct Void {};
// NOLINTEND
template <typename T> struct VoidFix { typedef T Type; };
template <> struct VoidFix<void> { typedef Void Type; };
template <typename T> using FixVoid = typename VoidFix<T>::Type;
template <typename T> struct void_fix { typedef T Type; };
template <> struct void_fix<void> { typedef Void Type; };
template <typename T> using fix_void = typename void_fix<T>::Type;
template <typename T> struct VoidUnfix { typedef T Type; };
template <> struct VoidUnfix<Void> { typedef void Type; };
template <typename T> using UnfixVoid = typename VoidUnfix<T>::Type;
template <typename T> struct void_unfix { typedef T Type; };
template <> struct void_unfix<Void> { typedef void Type; };
template <typename T> using unfix_void = typename void_unfix<T>::Type;
// NOLINTBEGIN
template <typename... T> constexpr bool always_false = false; // NOLINT
// NOLINTEND
} // namespace saw

View File

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

View File

@ -4,138 +4,145 @@
#include <string_view>
#include <variant>
#include <cassert>
#include "common.h"
namespace saw {
/**
* Utility class for generating errors. Has a base distinction between
* 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.
*/
class Error {
class error {
public:
enum class Code : int16_t {
GenericCritical = -1,
GenericRecoverable = 1,
Disconnected = -99,
Exhausted = -98
enum class code : int16_t {
generic_critical = -1,
generic_recoverable = 1,
disconnected = -99,
exhausted = -98
};
private:
std::variant<std::string_view, std::string> error_message;
Code error_;
code error_;
public:
Error();
Error(const std::string_view &msg, Error::Code code);
Error(std::string &&msg, Error::Code code);
Error(Error &&error);
error();
error(const std::string_view &msg, error::code code);
error(std::string &&msg, error::code code);
error(error &&error);
SAW_FORBID_COPY(Error);
SAW_FORBID_COPY(error);
Error &operator=(Error &&) = default;
error &operator=(error &&) = default;
const std::string_view message() const;
bool failed() const;
bool isCritical() const;
bool isRecoverable() const;
bool is_critical() const;
bool is_recoverable() const;
Error copyError() const;
error copy_error() const;
Code code() const;
code error_code() const;
};
Error makeError(const std::string_view &generic, Error::Code c);
error make_error(const std::string_view &generic, error::code c);
template <typename Formatter>
Error makeError(const Formatter &formatter, Error::Code code,
const std::string_view &generic) {
error make_error(const Formatter &formatter, error::code code,
const std::string_view &generic) {
// NOLINTBEGIN
try {
std::string error_msg = formatter();
return Error{std::move(error_msg), code};
return error{std::move(error_msg), code};
} catch (std::bad_alloc &) {
return Error{generic, code};
return error{generic, code};
}
// NOLINTEND
}
Error criticalError(const std::string_view &generic,
Error::Code c = Error::Code::GenericCritical);
error critical_error(const std::string_view &generic,
error::code c = error::code::generic_critical);
template <typename Formatter>
Error criticalError(const Formatter &formatter, const std::string_view &generic,
Error::Code c = Error::Code::GenericCritical) {
return makeError(formatter, c, generic);
error critical_error(const Formatter &formatter,
const std::string_view &generic,
error::code c = error::code::generic_critical) {
return make_error(formatter, c, generic);
}
Error recoverableError(const std::string_view &generic,
Error::Code c = Error::Code::GenericRecoverable);
error recoverable_error(const std::string_view &generic,
error::code c = error::code::generic_recoverable);
template <typename Formatter>
Error recoverableError(const Formatter &formatter,
const std::string_view &generic,
Error::Code c = Error::Code::GenericRecoverable) {
return makeError(formatter, c, generic);
error recoverable_error(const Formatter &formatter,
const std::string_view &generic,
error::code c = error::code::generic_recoverable) {
return make_error(formatter, c, generic);
}
Error noError();
error no_error();
/**
* Exception alternative. Since I code without exceptions this class is
* essentially a kind of exception replacement.
*/
template <typename T> class ErrorOr;
template <typename T> class error_or;
class ErrorOrValue {
class error_or_value {
public:
virtual ~ErrorOrValue() = default;
virtual ~error_or_value() = default;
template <typename T> ErrorOr<UnfixVoid<T>> &as() {
return static_cast<ErrorOr<UnfixVoid<T>> &>(*this);
template <typename T> error_or<unfix_void<T>> &as() {
return static_cast<error_or<unfix_void<T>> &>(*this);
}
template <typename T> const ErrorOr<UnfixVoid<T>> &as() const {
return static_cast<const ErrorOr<UnfixVoid<T>> &>(*this);
template <typename T> const error_or<unfix_void<T>> &as() const {
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:
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");
public:
ErrorOr() = default;
ErrorOr(const FixVoid<T> &value) : value_or_error{value} {}
error_or() = default;
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} {}
ErrorOr(Error &&error) : value_or_error{std::move(error)} {}
error_or(const error &error) : value_or_error{error} {}
error_or(error &&error) : value_or_error{std::move(error)} {}
bool isValue() const {
return std::holds_alternative<FixVoid<T>>(value_or_error);
bool is_value() const {
return std::holds_alternative<fix_void<T>>(value_or_error);
}
bool isError() const {
return std::holds_alternative<Error>(value_or_error);
bool is_error() const {
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<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 {
return std::get<FixVoid<T>>(value_or_error);
const fix_void<T> &value() const {
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:
ErrorOr() = delete;
error_or() = delete;
};
} // namespace saw

View File

@ -4,7 +4,7 @@
namespace saw {
AsyncIoStream::AsyncIoStream(Own<IoStream> str)
AsyncIoStream::AsyncIoStream(own<IoStream> str)
: stream{std::move(str)}, read_ready{stream->readReady()
.then([this]() {
read_stepper.readStep(*stream);
@ -31,14 +31,14 @@ void AsyncIoStream::read(void *buffer, size_t min_length, size_t max_length) {
read_stepper.readStep(*stream);
}
Conveyor<size_t> AsyncIoStream::readDone() {
auto caf = newConveyorAndFeeder<size_t>();
conveyor<size_t> AsyncIoStream::readDone() {
auto caf = new_conveyor_and_feeder<size_t>();
read_stepper.read_done = std::move(caf.feeder);
return std::move(caf.conveyor);
}
Conveyor<void> AsyncIoStream::onReadDisconnected() {
auto caf = newConveyorAndFeeder<void>();
conveyor<void> AsyncIoStream::onReadDisconnected() {
auto caf = new_conveyor_and_feeder<void>();
read_stepper.on_read_disconnect = std::move(caf.feeder);
return std::move(caf.conveyor);
}
@ -53,8 +53,8 @@ void AsyncIoStream::write(const void *buffer, size_t length) {
write_stepper.writeStep(*stream);
}
Conveyor<size_t> AsyncIoStream::writeDone() {
auto caf = newConveyorAndFeeder<size_t>();
conveyor<size_t> AsyncIoStream::writeDone() {
auto caf = new_conveyor_and_feeder<size_t>();
write_stepper.write_done = std::move(caf.feeder);
return std::move(caf.conveyor);
}

View File

@ -15,11 +15,11 @@ class InputStream {
public:
virtual ~InputStream() = 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> readReady() = 0;
virtual Conveyor<void> onReadDisconnected() = 0;
virtual conveyor<void> onReadDisconnected() = 0;
};
/*
@ -29,9 +29,9 @@ class OutputStream {
public:
virtual ~OutputStream() = 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> writeReady() = 0;
};
/*
@ -48,8 +48,8 @@ public:
virtual void read(void *buffer, size_t min_length, size_t max_length) = 0;
virtual Conveyor<size_t> readDone() = 0;
virtual Conveyor<void> onReadDisconnected() = 0;
virtual conveyor<size_t> readDone() = 0;
virtual conveyor<void> onReadDisconnected() = 0;
};
class AsyncOutputStream {
@ -58,42 +58,42 @@ public:
virtual void write(const void *buffer, size_t length) = 0;
virtual Conveyor<size_t> writeDone() = 0;
virtual conveyor<size_t> writeDone() = 0;
};
class AsyncIoStream final : public AsyncInputStream, public AsyncOutputStream {
private:
Own<IoStream> stream;
own<IoStream> stream;
SinkConveyor read_ready;
SinkConveyor write_ready;
SinkConveyor read_disconnected;
conveyor_sink read_ready;
conveyor_sink write_ready;
conveyor_sink read_disconnected;
ReadTaskAndStepHelper read_stepper;
WriteTaskAndStepHelper write_stepper;
public:
AsyncIoStream(Own<IoStream> str);
AsyncIoStream(own<IoStream> str);
SAW_FORBID_COPY(AsyncIoStream);
SAW_FORBID_MOVE(AsyncIoStream);
void read(void *buffer, size_t length, size_t max_length) override;
Conveyor<size_t> readDone() override;
conveyor<size_t> readDone() override;
Conveyor<void> onReadDisconnected() override;
conveyor<void> onReadDisconnected() override;
void write(const void *buffer, size_t length) override;
Conveyor<size_t> writeDone() override;
conveyor<size_t> writeDone() override;
};
class Server {
public:
virtual ~Server() = default;
virtual Conveyor<Own<IoStream>> accept() = 0;
virtual conveyor<own<IoStream>> accept() = 0;
};
class NetworkAddress;
@ -106,12 +106,12 @@ class Datagram {
public:
virtual ~Datagram() = default;
virtual ErrorOr<size_t> read(void *buffer, size_t length) = 0;
virtual Conveyor<void> readReady() = 0;
virtual error_or<size_t> read(void *buffer, size_t length) = 0;
virtual conveyor<void> readReady() = 0;
virtual ErrorOr<size_t> write(const void *buffer, size_t length,
NetworkAddress &dest) = 0;
virtual Conveyor<void> writeReady() = 0;
virtual error_or<size_t> write(const void *buffer, size_t length,
NetworkAddress &dest) = 0;
virtual conveyor<void> writeReady() = 0;
};
class OsNetworkAddress;
@ -156,41 +156,49 @@ public:
virtual ~Network() = default;
/**
* Parse 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>>
parseAddress(const std::string &addr, uint16_t port_hint = 0) = 0;
virtual conveyor<own<NetworkAddress>>
resolveAddress(const std::string &addr, uint16_t port_hint = 0) = 0;
/**
* Parse the provided string and uint16 to the preferred storage method
* Since no dns request is made here, no async conveyors have to be used.
*/
/// @todo implement
// virtual own<NetworkAddress> parseAddress(const std::string& addr,
// uint16_t port_hint = 0) = 0;
/**
* Set up a listener on this address
*/
virtual Own<Server> listen(NetworkAddress &bind_addr) = 0;
virtual own<Server> listen(NetworkAddress &bind_addr) = 0;
/**
* Connect to a remote address
*/
virtual Conveyor<Own<IoStream>> connect(NetworkAddress &address) = 0;
virtual conveyor<own<IoStream>> connect(NetworkAddress &address) = 0;
/**
* Bind a datagram socket at this address.
*/
virtual Own<Datagram> datagram(NetworkAddress &address) = 0;
virtual own<Datagram> datagram(NetworkAddress &address) = 0;
};
class IoProvider {
public:
virtual ~IoProvider() = default;
virtual Own<InputStream> wrapInputFd(int fd) = 0;
virtual own<InputStream> wrapInputFd(int fd) = 0;
virtual Network &network() = 0;
};
struct AsyncIoContext {
Own<IoProvider> io;
EventLoop &event_loop;
EventPort &event_port;
own<IoProvider> io;
event_loop &event_loop;
event_port &event_port;
};
ErrorOr<AsyncIoContext> setupAsyncIo();
error_or<AsyncIoContext> setupAsyncIo();
} // namespace saw

View File

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

53
source/forstio/io_auth.h Normal file
View File

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

View File

@ -9,18 +9,18 @@ void ReadTaskAndStepHelper::readStep(InputStream &reader) {
while (read_task.has_value()) {
ReadIoTask &task = *read_task;
ErrorOr<size_t> n_err = reader.read(task.buffer, task.max_length);
if (n_err.isError()) {
const Error &error = n_err.error();
if (error.isCritical()) {
error_or<size_t> n_err = reader.read(task.buffer, task.max_length);
if (n_err.is_error()) {
const error &error = n_err.error();
if (error.is_critical()) {
if (read_done) {
read_done->fail(error.copyError());
read_done->fail(error.copy_error());
}
read_task = std::nullopt;
}
break;
} else if (n_err.isValue()) {
} else if (n_err.is_value()) {
size_t n = n_err.value();
if (static_cast<size_t>(n) >= task.min_length &&
static_cast<size_t>(n) <= task.max_length) {
@ -37,7 +37,7 @@ void ReadTaskAndStepHelper::readStep(InputStream &reader) {
} else {
if (read_done) {
read_done->fail(criticalError("Read failed"));
read_done->fail(critical_error("Read failed"));
}
read_task = std::nullopt;
}
@ -48,9 +48,9 @@ void WriteTaskAndStepHelper::writeStep(OutputStream &writer) {
while (write_task.has_value()) {
WriteIoTask &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();
assert(n <= task.length);
@ -64,22 +64,22 @@ void WriteTaskAndStepHelper::writeStep(OutputStream &writer) {
task.length -= n;
task.already_written += n;
}
} else if (n_err.isError()) {
const Error &error = n_err.error();
if (error.isCritical()) {
} else if (n_err.is_error()) {
const error &error = n_err.error();
if (error.is_critical()) {
if (write_done) {
write_done->fail(error.copyError());
write_done->fail(error.copy_error());
}
write_task = std::nullopt;
}
break;
} else {
if (write_done) {
write_done->fail(criticalError("Write failed"));
write_done->fail(critical_error("Write failed"));
}
write_task = std::nullopt;
}
}
}
} // namespace saw
} // namespace saw

View File

@ -27,9 +27,9 @@ public:
size_t already_read = 0;
};
std::optional<ReadIoTask> 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:
void readStep(InputStream &reader);
@ -45,7 +45,7 @@ public:
size_t already_written = 0;
};
std::optional<WriteIoTask> write_task;
Own<ConveyorFeeder<size_t>> write_done = nullptr;
own<conveyor_feeder<size_t>> write_done = nullptr;
public:
void writeStep(OutputStream &writer);

View File

@ -1,41 +1,99 @@
#pragma once
#include "async.h"
#include "message.h"
#include "io.h"
#include "message.h"
namespace saw {
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer = MessageContainer<Incoming>,
typename OutContainer = MessageContainer<Outgoing>,
typename BufferT = ring_buffer>
class StreamingIoPeer {
private:
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> incoming_feeder = nullptr;
public:
/**
*
*/
StreamingIoPeer(
own<conveyor_feeder<HeapMessageRoot<Incoming, InContainer>>> feed,
own<AsyncIoStream> stream, Codec codec, BufferT in, BufferT out);
/**
*
*/
StreamingIoPeer(
own<conveyor_feeder<HeapMessageRoot<Incoming, InContainer>>> feed,
own<AsyncIoStream> stream);
Own<AsyncIoStream> io_stream;
/**
* Deleted copy and move constructors
*/
SAW_FORBID_COPY(StreamingIoPeer);
SAW_FORBID_MOVE(StreamingIoPeer);
/**
* Send a message to the remote peer
*/
void send(HeapMessageRoot<Outgoing, OutContainer> builder);
/**
* A phantom conveyor feeder. Meant for interfacing with other components
*/
conveyor_feeder<HeapMessageRoot<Outgoing, OutContainer>> &feeder();
conveyor<void> onReadDisconnected();
private:
class Peerconveyor_feeder final
: public conveyor_feeder<HeapMessageRoot<Outgoing, OutContainer>> {
public:
Peerconveyor_feeder(
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT> &peer_)
: peer{peer_} {}
void feed(T &&data) override { (void)data; }
void fail(error &&error) override { (void)error; }
size_t space() const override { return 0; }
size_t queued() const override { return 0; }
private:
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer,
BufferT> &peer;
};
private:
own<conveyor_feeder<HeapMessageRoot<Incoming, InContainer>>>
incoming_feeder = nullptr;
own<AsyncIoStream> io_stream;
Codec codec;
BufferT in_buffer;
BufferT out_buffer;
SinkConveyor sink_read;
SinkConveyor sink_write;
sink_conveyor sink_read;
sink_conveyor sink_write;
public:
StreamingIoPeer(Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, Own<AsyncIoStream> stream, Codec codec, BufferT in, BufferT out);
StreamingIoPeer(Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed, Own<AsyncIoStream> stream);
void send(HeapMessageRoot<Outgoing, OutContainer> builder);
Conveyor<void> onReadDisconnected();
Peerconveyor_feeder conveyor_feeder;
};
/**
* Setup new streaming io peer with the provided network protocols.
* This is a convenience wrapper intended for a faster setup of
* This is a convenience wrapper intended for a faster setup of this class
*/
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
std::pair<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>, Conveyor<HeapMessageRoot<Incoming, InContainer>>> newStreamingIoPeer(Own<AsyncIoStream> stream);
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer = MessageContainer<Incoming>,
typename OutContainer = MessageContainer<Outgoing>,
typename BufferT = ring_buffer>
std::pair<own<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>>,
conveyor<HeapMessageRoot<Incoming, InContainer>>>
newStreamingIoPeer(own<AsyncIoStream> stream);
} // namespace saw

View File

@ -1,96 +1,112 @@
namespace saw {
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::StreamingIoPeer(
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
Own<AsyncIoStream> str
):
StreamingIoPeer{std::move(feed), std::move(str), {}, {}, {}}
{
}
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT>
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::
StreamingIoPeer(
own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
own<AsyncIoStream> str)
: StreamingIoPeer{std::move(feed), std::move(str), {}, {}, {}} {}
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::StreamingIoPeer(
Own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed,
Own<AsyncIoStream> str, Codec codec, BufferT in, BufferT out):
incoming_feeder{std::move(feed)},
io_stream{std::move(str)},
codec{std::move(codec)},
in_buffer{std::move(in)},
out_buffer{std::move(out)},
sink_read{
io_stream->readDone().then([this](size_t bytes) -> ErrorOr<void> {
in_buffer.writeAdvance(bytes);
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT>
StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::
StreamingIoPeer(
own<ConveyorFeeder<HeapMessageRoot<Incoming, InContainer>>> feed_,
own<AsyncIoStream> stream_, Codec codec_, BufferT in_, BufferT out_)
: incoming_feeder{std::move(feed_)}, io_stream{std::move(stream_)},
codec{std::move(codec_)}, in_buffer{std::move(in_)}, out_buffer{std::move(
out_)},
sink_read{io_stream->readDone()
.then([this](size_t bytes) -> error_or<void> {
in_buffer.writeAdvance(bytes);
if(in_buffer.writeSegmentLength() == 0){
return criticalError("Message too long");
}
if (in_buffer.writeSegmentLength() == 0) {
return critical_error("Message too long");
}
io_stream->read(&in_buffer.write(), 1, in_buffer.writeSegmentLength());
io_stream->read(&in_buffer.write(), 1,
in_buffer.writeSegmentLength());
while(true){
auto root = heapMessageRoot<Incoming, InContainer>();
auto builder = root.build();
while (true) {
auto root =
heapMessageRoot<Incoming, InContainer>();
auto builder = root.build();
Error error = codec.template decode<Incoming, InContainer>(builder, in_buffer);
if(error.isCritical()){
return error;
}
error error =
codec.template decode<Incoming, InContainer>(
builder, in_buffer);
if (error.is_critical()) {
return error;
}
if(!error.failed()){
incoming_feeder->handle(std::move(root));
}else{
break;
}
}
if (!error.failed()) {
incoming_feeder->feed(std::move(root));
} else {
break;
}
}
return Void{};
}).sink([this](Error error){
incoming_feeder->fail(error);
return Void{};
})
.sink([this](error error) {
incoming_feeder->fail(error.copy_error());
return error;
})
},
sink_write{
io_stream->writeDone().then([this](size_bytes) -> ErrorOr<void> {
out_buffer.readAdvance(bytes);
if(out_buffer.readCompositeLength() > 0){
io_stream->write(&out_buffer.read(), out_buffer.readSegmengtLength());
}
return error;
})},
sink_write{io_stream->writeDone()
.then([this](size_t bytes) -> error_or<void> {
out_buffer.readAdvance(bytes);
if (out_buffer.readCompositeLength() > 0) {
io_stream->write(&out_buffer.read(),
out_buffer.readSegmentLength());
}
return Void{};
}).sink();
}
{
return Void{};
})
.sink()} {
io_stream->read(&in_buffer.write(), 1, in_buffer.writeSegmentLength());
}
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
void StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::send(HeapMessageRoot<Outgoing, OutContainer> msg){
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT>
void StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer,
BufferT>::send(HeapMessageRoot<Outgoing, OutContainer>
msg) {
bool restart_write = out_buffer.readSegmentLength() == 0;
Error error = codec.template encode<Outgoing, OutContainer>(msg.read(), out_buffer);
if(error.failed()){
return error;
error err =
codec.template encode<Outgoing, OutContainer>(msg.read(), out_buffer);
if (err.failed()) {
return err;
}
if(restart_write){
if (restart_write) {
io_stream->write(&out_buffer.read(), out_buffer.readSegmentLength());
}
return noError();
return no_error();
}
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
Conveyor<void> StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>::onReadDisconnected(){
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT>
Conveyor<void> StreamingIoPeer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>::onReadDisconnected() {
return io_stream->onReadDisconnected();
}
template <typename Codec, typename Incoming, typename Outgoing, typename InContainer = MessageContainer<Incoming>, typename OutContainer = MessageContainer<Outgoing>, typename BufferT = RingBuffer>
std::pair<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer, OutContainer, BufferT>, Conveyor<HeapMessageRoot<Incoming, InContainer>>> newStreamingIoPeer(Own<AsyncIoStream> stream){
template <typename Codec, typename Incoming, typename Outgoing,
typename InContainer, typename OutContainer, typename BufferT>
std::pair<own<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>>,
Conveyor<HeapMessageRoot<Incoming, InContainer>>>
newStreamingIoPeer(own<AsyncIoStream> stream) {
auto caf = newConveyorAndFeeder<HeapMessageRoot<Incoming, InContainer>>();
return {{std::move(caf.feeder), std::move(stream)}, std::move(caf.conveyor)};
return {heap<StreamingIoPeer<Codec, Incoming, Outgoing, InContainer,
OutContainer, BufferT>>(std::move(caf.feeder),
std::move(stream)),
std::move(caf.conveyor)};
}
}
} // namespace saw

View File

@ -282,7 +282,7 @@ public:
}
template <StringLiteral Literal>
constexpr size_t toIndex() const noexcept {
static constexpr size_t toIndex() noexcept {
return MessageParameterKeyPackIndex<Literal, Keys...>::Value;
}
@ -513,10 +513,10 @@ public:
template <class Schema, class Container = MessageContainer<Schema>>
class HeapMessageRoot {
private:
Own<Message<Schema, Container>> root;
own<Message<Schema, Container>> root;
public:
HeapMessageRoot(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
HeapMessageRoot(own<Message<Schema, Container>> r) : root{std::move(r)} {}
typename Message<Schema, Container>::Builder build() {
assert(root);
@ -535,10 +535,10 @@ public:
using Schema = schema::Array<T>;
private:
Own<Message<Schema, Container>> root;
own<Message<Schema, Container>> root;
public:
HeapMessageRoot(Own<Message<Schema, Container>> r) : root{std::move(r)} {}
HeapMessageRoot(own<Message<Schema, Container>> r) : root{std::move(r)} {}
typename Message<Schema, Container>::Builder build(size_t size) {
assert(root);
@ -556,7 +556,7 @@ public:
*/
template <class Schema, class Container = MessageContainer<Schema>>
inline HeapMessageRoot<Schema, Container> heapMessageRoot() {
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)};
}
} // namespace saw

View File

@ -2,6 +2,8 @@
#include "schema.h"
#include <variant>
namespace saw {
template <class T> class MessageContainer;

View File

@ -5,16 +5,12 @@
#include "stream_endian.h"
namespace saw {
/// @todo replace types with these
/*
* I'm not really sure if anyone will use a union which is
* bigger than uint32_t max. At least I hope noone would do this
*/
using msg_union_id_t = uint32_t;
using msg_array_length_t = uint64_t;
using msg_packet_length_t = uint64_t;
class ProtoKelCodec {
public:
using UnionIdT = uint32_t;
using ArrayLengthT = uint64_t;
using PacketLengthT = uint64_t;
private:
struct ReadContext {
Buffer &buffer;
@ -27,10 +23,10 @@ private:
public:
struct Limits {
msg_packet_length_t packet_size;
ProtoKelCodec::PacketLengthT packet_size;
Limits() : packet_size{4096} {}
Limits(msg_packet_length_t ps) : packet_size{ps} {}
Limits(ProtoKelCodec::PacketLengthT ps) : packet_size{ps} {}
};
struct Version {
@ -42,11 +38,11 @@ public:
const Version version() const { return Version{0, 0, 0}; }
template <class Schema, class Container = MessageContainer<Schema>>
Error encode(typename Message<Schema, Container>::Reader reader,
error encode(typename Message<Schema, Container>::Reader reader,
Buffer &buffer);
template <class Schema, class Container = MessageContainer<Schema>>
Error decode(typename Message<Schema, Container>::Builder builder,
error decode(typename Message<Schema, Container>::Builder builder,
Buffer &buffer, const Limits &limits = Limits{});
};
@ -54,12 +50,12 @@ template <class T> struct ProtoKelEncodeImpl;
template <class T, size_t N, class Container>
struct ProtoKelEncodeImpl<Message<schema::Primitive<T, N>, Container>> {
static Error
static error
encode(typename Message<schema::Primitive<T, N>, Container>::Reader data,
Buffer &buffer) {
Error error = StreamValue<typename PrimitiveTypeHelper<
error err = StreamValue<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::encode(data.get(), buffer);
return error;
return err;
}
static size_t
@ -71,26 +67,26 @@ struct ProtoKelEncodeImpl<Message<schema::Primitive<T, N>, Container>> {
template <class Container>
struct ProtoKelEncodeImpl<Message<schema::String, Container>> {
static Error
static error
encode(typename Message<schema::String, Container>::Reader data,
Buffer &buffer) {
std::string_view view = data.get();
size_t size = view.size();
Error error = buffer.writeRequireLength(sizeof(size) + size);
if (error.failed()) {
return error;
error err = buffer.writeRequireLength(sizeof(size) + size);
if (err.failed()) {
return err;
}
error = StreamValue<size_t>::encode(size, buffer);
if (error.failed()) {
return error;
err = StreamValue<size_t>::encode(size, buffer);
if (err.failed()) {
return err;
}
for (size_t i = 0; i < view.size(); ++i) {
buffer.write(i) = view[i];
}
buffer.writeAdvance(view.size());
return noError();
return no_error();
}
static size_t
@ -102,27 +98,27 @@ struct ProtoKelEncodeImpl<Message<schema::String, Container>> {
template <class... T, class Container>
struct ProtoKelEncodeImpl<Message<schema::Tuple<T...>, Container>> {
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,
Buffer &) {
return noError();
return no_error();
}
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,
Buffer &buffer) {
Error error =
error err =
ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
encode(data.template get<i>(), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
return encodeMembers<i + 1>(data, buffer);
}
static Error
static error
encode(typename Message<schema::Tuple<T...>, Container>::Reader data,
Buffer &buffer) {
return encodeMembers<0>(data, buffer);
@ -153,29 +149,29 @@ template <typename... V, StringLiteral... K, class Container>
struct ProtoKelEncodeImpl<
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> {
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>...>,
Container>::Reader,
Buffer &) {
return noError();
return no_error();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type encodeMembers(
i<sizeof...(V), error>::type encodeMembers(
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader data,
Buffer &buffer) {
Error error =
error err =
ProtoKelEncodeImpl<typename Container::template ElementType<i>>::
encode(data.template get<i>(), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
return encodeMembers<i + 1>(data, buffer);
}
static Error
static error
encode(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Reader data,
Buffer &buffer) {
@ -211,23 +207,23 @@ struct ProtoKelEncodeImpl<
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> {
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>...>,
Container>::Reader,
Buffer &) {
return noError();
return no_error();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type encodeMembers(
i<sizeof...(V), error>::type encodeMembers(
typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader,
Buffer &buffer) {
if (reader.index() == i) {
Error error = StreamValue<msg_union_id_t>::encode(i, buffer);
if (error.failed()) {
return error;
error err = StreamValue<ProtoKelCodec::UnionIdT>::encode(i, buffer);
if (err.failed()) {
return err;
}
return ProtoKelEncodeImpl<typename Container::template ElementType<
i>>::encode(reader.template get<i>(), buffer);
@ -235,7 +231,7 @@ struct ProtoKelEncodeImpl<
return encodeMembers<i + 1>(reader, buffer);
}
static Error
static error
encode(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader,
Buffer &buffer) {
@ -267,33 +263,33 @@ struct ProtoKelEncodeImpl<
static size_t
size(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Reader reader) {
return sizeof(msg_union_id_t) + sizeMembers<0>(reader);
return sizeof(ProtoKelCodec::UnionIdT) + sizeMembers<0>(reader);
}
};
template <class T, class Container>
struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> {
static Error
static error
encode(typename Message<schema::Array<T>, Container>::Reader data,
Buffer &buffer) {
msg_array_length_t array_length = data.size();
ProtoKelCodec::ArrayLengthT array_length = data.size();
{
Error error =
StreamValue<msg_array_length_t>::encode(array_length, buffer);
if (error.failed()) {
return error;
error err = StreamValue<ProtoKelCodec::ArrayLengthT>::encode(
array_length, buffer);
if (err.failed()) {
return err;
}
}
for (size_t i = 0; i < array_length; ++i) {
Error error =
error err =
ProtoKelEncodeImpl<typename Container::ElementType>::encode(
data.get(i), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
}
return noError();
return no_error();
}
/*
@ -301,7 +297,7 @@ struct ProtoKelEncodeImpl<Message<schema::Array<T>, Container>> {
*/
static size_t
size(typename Message<schema::Array<T>, Container>::Reader data) {
size_t members = sizeof(msg_array_length_t);
size_t members = sizeof(ProtoKelCodec::ArrayLengthT);
for (size_t i = 0; i < data.size(); ++i) {
members +=
ProtoKelEncodeImpl<typename Container::ElementType>::size(
@ -319,76 +315,76 @@ template <typename T> struct ProtoKelDecodeImpl;
template <class T, size_t N, class Container>
struct ProtoKelDecodeImpl<Message<schema::Primitive<T, N>, Container>> {
static Error
static error
decode(typename Message<schema::Primitive<T, N>, Container>::Builder data,
Buffer &buffer) {
typename PrimitiveTypeHelper<schema::Primitive<T, N>>::Type val = 0;
Error error = StreamValue<typename PrimitiveTypeHelper<
error err = StreamValue<typename PrimitiveTypeHelper<
schema::Primitive<T, N>>::Type>::decode(val, buffer);
data.set(val);
return error;
return err;
}
};
template <class Container>
struct ProtoKelDecodeImpl<Message<schema::String, Container>> {
static Error
static error
decode(typename Message<schema::String, Container>::Builder data,
Buffer &buffer) {
size_t size = 0;
if (sizeof(size) > buffer.readCompositeLength()) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
Error error = StreamValue<size_t>::decode(size, buffer);
if (error.failed()) {
return error;
error err = StreamValue<size_t>::decode(size, buffer);
if (err.failed()) {
return err;
}
if (size > buffer.readCompositeLength()) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
std::string value;
value.resize(size);
if (size > buffer.readCompositeLength()) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
for (size_t i = 0; i < value.size(); ++i) {
value[i] = buffer.read(i);
}
buffer.readAdvance(value.size());
data.set(std::move(value));
return noError();
return no_error();
}
};
template <class... T, class Container>
struct ProtoKelDecodeImpl<Message<schema::Tuple<T...>, Container>> {
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,
Buffer &) {
return noError();
return no_error();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(T), Error>::type decodeMembers(
i<sizeof...(T), error>::type decodeMembers(
typename Message<schema::Tuple<T...>, Container>::Builder builder,
Buffer &buffer) {
Error error =
error err =
ProtoKelDecodeImpl<typename Container::template ElementType<i>>::
decode(builder.template init<i>(), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
return decodeMembers<i + 1>(builder, buffer);
}
static Error
static error
decode(typename Message<schema::Tuple<T...>, Container>::Builder builder,
Buffer &buffer) {
return decodeMembers<0>(builder, buffer);
@ -400,30 +396,30 @@ struct ProtoKelDecodeImpl<
Message<schema::Struct<schema::NamedMember<V, K>...>, Container>> {
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>...>,
Container>::Builder,
Buffer &) {
return noError();
return no_error();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type decodeMembers(
i<sizeof...(V), error>::type decodeMembers(
typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer) {
Error error =
error err =
ProtoKelDecodeImpl<typename Container::template ElementType<i>>::
decode(builder.template init<i>(), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
return decodeMembers<i + 1>(builder, buffer);
}
static Error
static error
decode(typename Message<schema::Struct<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer) {
@ -435,42 +431,42 @@ template <class... V, StringLiteral... K, class Container>
struct ProtoKelDecodeImpl<
Message<schema::Union<schema::NamedMember<V, K>...>, Container>> {
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>...>,
Container>::Builder,
Buffer &, msg_union_id_t) {
return noError();
Buffer &, ProtoKelCodec::UnionIdT) {
return no_error();
}
template <size_t i = 0>
static typename std::enable_if <
i<sizeof...(V), Error>::type decodeMembers(
i<sizeof...(V), error>::type decodeMembers(
typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer, msg_union_id_t id) {
Buffer &buffer, ProtoKelCodec::UnionIdT id) {
if (id == i) {
Error error =
error err =
ProtoKelDecodeImpl<typename Container::template ElementType<
i>>::decode(builder.template init<i>(), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
}
return decodeMembers<i + 1>(builder, buffer, id);
}
static Error
static error
decode(typename Message<schema::Union<schema::NamedMember<V, K>...>,
Container>::Builder builder,
Buffer &buffer) {
msg_union_id_t id = 0;
Error error = StreamValue<msg_union_id_t>::decode(id, buffer);
if (error.failed()) {
return error;
ProtoKelCodec::UnionIdT id = 0;
error err = StreamValue<ProtoKelCodec::UnionIdT>::decode(id, buffer);
if (err.failed()) {
return err;
}
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);
@ -479,84 +475,84 @@ struct ProtoKelDecodeImpl<
template <class T, class Container>
struct ProtoKelDecodeImpl<Message<schema::Array<T>, Container>> {
static Error
static error
decode(typename Message<schema::Array<T>, Container>::Builder data,
Buffer &buffer) {
msg_array_length_t array_length = 0;
ProtoKelCodec::ArrayLengthT array_length = 0;
{
Error error =
StreamValue<msg_array_length_t>::decode(array_length, buffer);
if (error.failed()) {
return error;
error err = StreamValue<ProtoKelCodec::ArrayLengthT>::decode(
array_length, buffer);
if (err.failed()) {
return err;
}
}
data.resize(array_length);
for (size_t i = 0; i < array_length; ++i) {
Error error =
error err =
ProtoKelDecodeImpl<typename Container::ElementType>::decode(
data.init(i), buffer);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
}
return noError();
return no_error();
}
};
template <class Schema, class Container>
Error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader,
error ProtoKelCodec::encode(typename Message<Schema, Container>::Reader reader,
Buffer &buffer) {
BufferView view{buffer};
msg_packet_length_t packet_length =
ProtoKelCodec::PacketLengthT packet_length =
ProtoKelEncodeImpl<Message<Schema, Container>>::size(reader);
// Check the size of the packet for the first
// message length description
Error error =
view.writeRequireLength(packet_length + sizeof(msg_packet_length_t));
if (error.failed()) {
return error;
error err = view.writeRequireLength(packet_length +
sizeof(ProtoKelCodec::PacketLengthT));
if (err.failed()) {
return err;
}
{
Error error =
StreamValue<msg_packet_length_t>::encode(packet_length, view);
if (error.failed()) {
return error;
error err = StreamValue<ProtoKelCodec::PacketLengthT>::encode(
packet_length, view);
if (err.failed()) {
return err;
}
}
{
Error error = ProtoKelEncodeImpl<Message<Schema, Container>>::encode(
error err = ProtoKelEncodeImpl<Message<Schema, Container>>::encode(
reader, view);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
}
buffer.writeAdvance(view.writeOffset());
return noError();
return no_error();
}
template <class Schema, class Container>
Error ProtoKelCodec::decode(
error ProtoKelCodec::decode(
typename Message<Schema, Container>::Builder builder, Buffer &buffer,
const Limits &limits) {
BufferView view{buffer};
msg_packet_length_t packet_length = 0;
ProtoKelCodec::PacketLengthT packet_length = 0;
{
Error error =
StreamValue<msg_packet_length_t>::decode(packet_length, view);
if (error.failed()) {
return error;
error err = StreamValue<ProtoKelCodec::PacketLengthT>::decode(
packet_length, view);
if (err.failed()) {
return err;
}
}
if (packet_length > limits.packet_size) {
return criticalError(
return critical_error(
[packet_length]() {
return std::string{"Packet size too big: "} +
std::to_string(packet_length);
@ -565,21 +561,21 @@ Error ProtoKelCodec::decode(
}
{
Error error = ProtoKelDecodeImpl<Message<Schema, Container>>::decode(
error err = ProtoKelDecodeImpl<Message<Schema, Container>>::decode(
builder, view);
if (error.failed()) {
return error;
if (err.failed()) {
return err;
}
}
{
if (ProtoKelEncodeImpl<Message<Schema, Container>>::size(
builder.asReader()) != packet_length) {
return criticalError("Bad packet format");
return critical_error("Bad packet format");
}
}
buffer.readAdvance(view.readOffset());
return noError();
return no_error();
}
} // namespace saw

35
source/forstio/rpc/rpc.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
namespace saw {
template<typename Codec, typename Schema> class Rpc;
/**
* Provides the interface for messages with an rpc type behaviour
*/
template<typename Codec, typename... Responses, typename... Requests, StringLiteral... Literals>
class Rpc<schema::Interface<schema::Function<Responses, Requests, Literals>...>> {
public:
class Client {
public:
/**
*
*/
template<StringLiteral FunctionLiteral>
Conveyor<Message<FunctionResponse>> request(Message<FunctionRequest> parameters);
};
class Service {
public:
/**
*
*/
template<StringLiteral FunctionLiteral>
Conveyor<Message<FunctionResponse>> handle(Message<FunctionRequest> request);
};
class Server {
};
};
}

View File

@ -5,20 +5,29 @@
namespace saw {
namespace schema {
template <class T, StringLiteral Literal> struct NamedMember {};
template <typename T, StringLiteral Literal> struct NamedMember {};
template <class... T> struct Struct;
template <typename... T> struct Struct {
static_assert(
always_false<T...>,
"This schema template doesn't support this type of template argument");
};
template <class... V, StringLiteral... K>
template <typename... V, StringLiteral... K>
struct Struct<NamedMember<V, K>...> {};
template <class... T> struct Union;
template <typename... T> struct Union {
static_assert(
always_false<T...>,
"This schema template doesn't support this type of template argument");
};
template <class... V, StringLiteral... K> struct Union<NamedMember<V, K>...> {};
template <typename... V, StringLiteral... K>
struct Union<NamedMember<V, K>...> {};
template <class T> struct Array {};
template <typename T> struct Array {};
template <class... T> struct Tuple {};
template <typename... T> struct Tuple {};
struct String {};
@ -47,5 +56,20 @@ using UInt64 = Primitive<UnsignedInteger, 8>;
using Float32 = Primitive<FloatingPoint, 4>;
using Float64 = Primitive<FloatingPoint, 8>;
/**
* Classes enabling Rpc calls
*/
template <class Request, class Response, StringLiteral Literal>
struct Function {};
template <class... T> struct Interface {
static_assert(
always_false<T...>,
"This schema template doesn't support this type of template argument");
};
template <class... Request, class... Response, StringLiteral... Literal>
struct Interface<Function<Request, Response, Literal>...> {};
} // namespace schema
} // namespace saw

View File

@ -19,12 +19,12 @@ template <typename T, size_t size = sizeof(T)> class ShiftStreamValue;
template <typename T> class ShiftStreamValue<T, 1> {
public:
inline static Error decode(T &val, Buffer &buffer) {
inline static error decode(T &val, Buffer &buffer) {
uint8_t &raw = reinterpret_cast<uint8_t &>(val);
return buffer.pop(raw, sizeof(T));
}
inline static Error encode(const T &val, Buffer &buffer) {
inline static error encode(const T &val, Buffer &buffer) {
const uint8_t &raw = reinterpret_cast<const uint8_t &>(val);
return buffer.push(raw, sizeof(T));
}
@ -34,9 +34,9 @@ public:
template <typename T> class ShiftStreamValue<T, 2> {
public:
inline static Error decode(T &val, Buffer &buffer) {
inline static error decode(T &val, Buffer &buffer) {
if (buffer.readCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
uint16_t raw = 0;
@ -47,11 +47,11 @@ public:
memcpy(&val, &raw, sizeof(T));
buffer.readAdvance(sizeof(T));
return noError();
return no_error();
}
inline static Error encode(const T &val, Buffer &buffer) {
Error error = buffer.writeRequireLength(sizeof(T));
inline static error encode(const T &val, Buffer &buffer) {
error error = buffer.writeRequireLength(sizeof(T));
if (error.failed()) {
return error;
}
@ -64,7 +64,7 @@ public:
}
buffer.writeAdvance(sizeof(T));
return noError();
return no_error();
}
inline static size_t size() { return sizeof(T); }
@ -72,9 +72,9 @@ public:
template <typename T> class ShiftStreamValue<T, 4> {
public:
inline static Error decode(T &val, Buffer &buffer) {
inline static error decode(T &val, Buffer &buffer) {
if (buffer.readCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
uint32_t raw = 0;
@ -85,11 +85,11 @@ public:
memcpy(&val, &raw, sizeof(T));
buffer.readAdvance(sizeof(T));
return noError();
return no_error();
}
inline static Error encode(const T &val, Buffer &buffer) {
Error error = buffer.writeRequireLength(sizeof(T));
inline static error encode(const T &val, Buffer &buffer) {
error error = buffer.writeRequireLength(sizeof(T));
if (error.failed()) {
return error;
}
@ -102,7 +102,7 @@ public:
}
buffer.writeAdvance(sizeof(T));
return noError();
return no_error();
}
inline static size_t size() { return sizeof(T); }
@ -110,9 +110,9 @@ public:
template <typename T> class ShiftStreamValue<T, 8> {
public:
inline static Error decode(T &val, Buffer &buffer) {
inline static error decode(T &val, Buffer &buffer) {
if (buffer.readCompositeLength() < sizeof(T)) {
return recoverableError("Buffer too small");
return recoverable_error("Buffer too small");
}
uint64_t raw = 0;
@ -124,11 +124,11 @@ public:
memcpy(&val, &raw, sizeof(T));
buffer.readAdvance(sizeof(T));
return noError();
return no_error();
}
inline static Error encode(const T &val, Buffer &buffer) {
Error error = buffer.writeRequireLength(sizeof(T));
inline static error encode(const T &val, Buffer &buffer) {
error error = buffer.writeRequireLength(sizeof(T));
if (error.failed()) {
return error;
}
@ -141,7 +141,7 @@ public:
}
buffer.writeAdvance(sizeof(T));
return noError();
return no_error();
}
inline static size_t size() { return sizeof(T); }

View File

@ -0,0 +1,35 @@
#!/bin/false
import os
import os.path
import glob
Import('base_lib_env');
Import('env');
dir_path = Dir('.').abspath
env.tls_sources += sorted(glob.glob(dir_path + "/*.cpp"))
env.tls_headers += sorted(glob.glob(dir_path + "/*.h"))
tls_lib_env = base_lib_env.Clone();
tls_lib_env.Append(LIBS=['gnutls']);
### Shared lib
objects_shared = []
tls_lib_env.add_source_files(objects_shared, env.tls_sources, shared=True);
env.tls_library_shared = tls_lib_env.SharedLibrary('#build/forstio-tls', [objects_shared, env.library_shared]);
### Static lib
objects_static = []
tls_lib_env.add_source_files(objects_static, env.tls_sources, shared=False);
env.tls_library_static = tls_lib_env.StaticLibrary('#build/forstio-tls', [objects_static, env.library_static]);
### Set alias
env.Alias('library_tls', [env.tls_library_shared + env.tls_library_static]);

View File

@ -40,58 +40,58 @@ Tls::Impl &Tls::getImpl() { return *impl; }
class TlsIoStream final : public IoStream {
private:
Own<IoStream> internal;
own<IoStream> internal;
gnutls_session_t session_handle;
public:
TlsIoStream(Own<IoStream> internal_) : internal{std::move(internal_)} {}
TlsIoStream(own<IoStream> internal_) : internal{std::move(internal_)} {}
~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);
if (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{
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){
return criticalError("Disconnected");
return critical_error("Disconnected");
}
return static_cast<size_t>(length);
}
Conveyor<void> readReady() override { return internal->readReady(); }
conveyor<void> readReady() override { return internal->readReady(); }
Conveyor<void> onReadDisconnected() override {
conveyor<void> onReadDisconnected() override {
return internal->onReadDisconnected();
}
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);
if(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{
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);
}
Conveyor<void> writeReady() override { return internal->writeReady(); }
conveyor<void> writeReady() override { return internal->writeReady(); }
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() {
SAW_ASSERT(internal) { return Conveyor<Own<IoStream>>{nullptr, nullptr}; }
return internal->accept().then([](Own<IoStream> stream) -> Own<IoStream> {
conveyor<own<IoStream>> TlsServer::accept() {
SAW_ASSERT(internal) { return conveyor<own<IoStream>>{fix_void<own<IoStream>>{nullptr}}; }
return internal->accept().then([](own<IoStream> stream) -> own<IoStream> {
/// @todo handshake
@ -105,14 +105,14 @@ namespace {
*/
struct TlsClientStreamHelper {
public:
Own<ConveyorFeeder<Own<IoStream>>> feeder;
SinkConveyor connection_sink;
SinkConveyor stream_reader;
SinkConveyor stream_writer;
own<conveyor_feeder<own<IoStream>>> feeder;
conveyor_sink connection_sink;
conveyor_sink stream_reader;
conveyor_sink stream_writer;
Own<TlsIoStream> stream = nullptr;
own<TlsIoStream> stream = nullptr;
public:
TlsClientStreamHelper(Own<ConveyorFeeder<Own<IoStream>>> f):
TlsClientStreamHelper(own<conveyor_feeder<own<IoStream>>> f):
feeder{std::move(f)}
{}
@ -145,7 +145,7 @@ public:
} while ( (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) && gnutls_error_is_fatal(ret) == 0);
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;
}else if(ret == GNUTLS_E_SUCCESS){
feeder->feed(std::move(stream));
@ -155,19 +155,19 @@ public:
};
}
Own<Server> TlsNetwork::listen(NetworkAddress& address) {
own<Server> TlsNetwork::listen(NetworkAddress& address) {
return heap<TlsServer>(internal.listen(address));
}
Conveyor<Own<IoStream>> TlsNetwork::connect(NetworkAddress& address) {
conveyor<own<IoStream>> TlsNetwork::connect(NetworkAddress& address) {
// Helper setups
auto caf = newConveyorAndFeeder<Own<IoStream>>();
Own<TlsClientStreamHelper> helper = heap<TlsClientStreamHelper>(std::move(caf.feeder));
auto caf = new_conveyor_and_feeder<own<IoStream>>();
own<TlsClientStreamHelper> helper = heap<TlsClientStreamHelper>(std::move(caf.feeder));
TlsClientStreamHelper* hlp_ptr = helper.get();
// Conveyor entangled structure
// conveyor entangled structure
auto prim_conv = internal.connect(address).then([this, hlp_ptr, addr = address.address()](
Own<IoStream> stream) -> ErrorOr<void> {
own<IoStream> stream) -> error_or<void> {
IoStream* inner_stream = stream.get();
auto tls_stream = heap<TlsIoStream>(std::move(stream));
@ -201,7 +201,7 @@ Conveyor<Own<IoStream>> TlsNetwork::connect(NetworkAddress& address) {
return caf.conveyor.attach(std::move(helper));
}
Own<Datagram> TlsNetwork::datagram(NetworkAddress& address){
own<Datagram> TlsNetwork::datagram(NetworkAddress& address){
///@unimplemented
return nullptr;
}
@ -213,8 +213,8 @@ static ssize_t forst_tls_push_func(gnutls_transport_ptr_t p, const void *data,
return -1;
}
ErrorOr<size_t> length = stream->write(data, size);
if (length.isError() || !length.isValue()) {
error_or<size_t> length = stream->write(data, size);
if (length.is_error() || !length.is_value()) {
return -1;
}
@ -227,24 +227,24 @@ static ssize_t forst_tls_pull_func(gnutls_transport_ptr_t p, void *data, size_t
return -1;
}
ErrorOr<size_t> length = stream->read(data, size);
if (length.isError() || !length.isValue()) {
error_or<size_t> length = stream->read(data, size);
if (length.is_error() || !length.is_value()) {
return -1;
}
return static_cast<ssize_t>(length.value());
}
TlsNetwork::TlsNetwork(Network &network) : internal{network} {}
TlsNetwork::TlsNetwork(Tls& tls_, Network &network) : tls{tls_},internal{network} {}
Conveyor<Own<NetworkAddress>> TlsNetwork::parseAddress(const std::string &addr,
conveyor<own<NetworkAddress>> TlsNetwork::resolveAddress(const std::string &addr,
uint16_t port) {
/// @todo tls server name needed. Check validity. Won't matter later on, because gnutls should fail anyway. But
/// it's better to find the error source sooner rather than later
return internal.parseAddress(addr, port);
return internal.resolveAddress(addr, port);
}
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network) {
std::optional<own<TlsNetwork>> setupTlsNetwork(Network &network) {
return std::nullopt;
}
} // namespace saw

View File

@ -7,49 +7,64 @@
#include <variant>
namespace saw {
class Tls {
private:
class Impl;
Own<Impl> impl;
public:
Tls();
~Tls();
class Options {
public:
};
Impl &getImpl();
};
class Tls;
class TlsServer final : public Server {
private:
Own<Server> internal;
own<Server> internal;
public:
TlsServer(Own<Server> srv);
TlsServer(own<Server> srv);
Conveyor<Own<IoStream>> accept() override;
conveyor<own<IoStream>> accept() override;
};
class TlsNetwork final : public Network {
private:
Tls tls;
Tls& tls;
Network &internal;
public:
TlsNetwork(Network &network);
TlsNetwork(Tls& tls_, Network &network_);
Conveyor<Own<NetworkAddress>> parseAddress(const std::string &addr, uint16_t port = 0) override;
conveyor<own<NetworkAddress>> resolveAddress(const std::string &addr, uint16_t port = 0) override;
Own<Server> listen(NetworkAddress& address) override;
own<Server> listen(NetworkAddress& address) override;
Conveyor<Own<IoStream>> connect(NetworkAddress& address) override;
conveyor<own<IoStream>> connect(NetworkAddress& address) override;
Own<Datagram> datagram(NetworkAddress& address) override;
own<Datagram> datagram(NetworkAddress& address) override;
};
std::optional<Own<TlsNetwork>> setupTlsNetwork(Network &network);
/**
* Tls context class.
* Provides tls network class which ensures the usage of tls encrypted connections
*/
class Tls {
private:
class Impl;
own<Impl> impl;
public:
Tls();
~Tls();
struct Version {
struct Tls_1_0{};
struct Tls_1_1{};
struct Tls_1_2{};
};
struct Options {
public:
Version version;
};
Network& tlsNetwork();
Impl &getImpl();
private:
Options options;
};
std::optional<own<TlsNetwork>> setupTlsNetwork(Network &network);
} // namespace saw

View File

@ -6,38 +6,38 @@ namespace {
SAW_TEST("Async Immediate"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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;
});
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.isValue(), "Return is not a value");
SAW_EXPECT(!error_or_number.is_error(), error_or_number.error().message());
SAW_EXPECT(error_or_number.is_value(), "Return is not a value");
SAW_EXPECT(error_or_number.value(), "Value is not 5");
}
SAW_TEST("Async Adapt"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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);
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.is_value(), "Return is not a 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"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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);
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.is_value(), "Return is not a value");
SAW_EXPECT(foo.value() == 5, "Values not 5, but " + std::to_string(foo.value()));
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(bar.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), bar.error().message());
SAW_EXPECT(bar.is_value(), "Return is not a value");
SAW_EXPECT(bar.value() == 10, "Values not 10, but " + std::to_string(bar.value()));
feeder_conveyor.feeder->feed(2);
feeder_conveyor.feeder->feed(4234);
ErrorOr<size_t> a = feeder_conveyor.conveyor.take();
ErrorOr<size_t> b = feeder_conveyor.conveyor.take();
error_or<size_t> a = feeder_conveyor.conveyor.take();
error_or<size_t> b = feeder_conveyor.conveyor.take();
SAW_EXPECT(!foo.isError(), a.error().message());
SAW_EXPECT(a.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), a.error().message());
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(!foo.isError(), b.error().message());
SAW_EXPECT(b.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), b.error().message());
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_TEST("Async Conversion"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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);
});
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), foo.error().message());
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_TEST("Async Conversion Multistep"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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);
}).then([](const std::string& value){
return value != "10";
@ -120,29 +120,29 @@ SAW_TEST("Async Conversion Multistep"){
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo.is_error(), foo.error().message());
SAW_EXPECT(foo.is_value(), "Return is not a value");
SAW_EXPECT(foo.value(), "Values is not true");
}
SAW_TEST("Async Scheduling"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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
*/
Own<size_t> counter = heap<size_t>();
own<size_t> counter = heap<size_t>();
size_t* ctr_ptr = counter.get();
*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){
return std::to_string(foo + ++(*ctr_ptr));
})
@ -163,34 +163,34 @@ SAW_TEST("Async Scheduling"){
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo_10.is_error(), foo_10.error().message());
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());
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo_20.is_error(), foo_20.error().message());
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());
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.isValue(), "Return is not a value");
SAW_EXPECT(!foo_30.is_error(), foo_30.error().message());
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_TEST("Async Detach"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop event_loop;
wait_scope wait_scope{event_loop};
int num = 0;
Conveyor<int>{10}.then([&num](int bar){
conveyor<int>{10}.then([&num](int bar){
num = bar;
}).detach();
@ -202,14 +202,14 @@ SAW_TEST("Async Detach"){
SAW_TEST("Async Merge"){
using namespace saw;
EventLoop event_loop;
WaitScope wait_scope{event_loop};
event_loop 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;
bool wrong_value = false;
@ -227,4 +227,36 @@ SAW_TEST("Async Merge"){
SAW_EXPECT(!wrong_value, std::string{"Expected values 10 or 11"});
SAW_EXPECT(elements_passed == 3, std::string{"Expected 2 passed elements, got only "} + std::to_string(elements_passed));
}
SAW_TEST("Async Connect"){
using namespace saw;
event_loop event_loop;
wait_scope wait_scope{event_loop};
auto caf1 = new_conveyor_and_feeder<int>();
auto caf2 = new_conveyor_and_feeder<float>();
bool val_passed = false;
auto conveyor1 = caf1.conveyor.then([&val_passed](int val) -> float{
val_passed = (val == 10);
return static_cast<float>(val);
}).buffer(1);
bool val_passed_2 = false;
auto sink = caf2.conveyor.then([&val_passed_2](float val) {
val_passed_2 = (val == 10.f);
}).sink();
caf1.feeder->feed(10);
caf2.feeder->swap(std::move(conveyor1));
wait_scope.poll();
SAW_EXPECT(val_passed, std::string{"Expected value 10"});
SAW_EXPECT(val_passed_2, std::string{"Expected value 10.f"});
}
}

View File

@ -35,11 +35,11 @@ SAW_TEST("Primitive Encoding"){
RingBuffer temp_buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestSize>(root.read(), temp_buffer);
error error = codec.encode<TestSize>(root.read(), temp_buffer);
SAW_EXPECT(!error.failed(), error.message());
SAW_EXPECT(temp_buffer.readCompositeLength() == (sizeof(value)+sizeof(msg_packet_length_t)), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength()));
constexpr size_t pkt_shift = sizeof(msg_packet_length_t);
SAW_EXPECT(temp_buffer.readCompositeLength() == (sizeof(value)+sizeof(ProtoKelCodec::PacketLengthT)), "Bad Size: " + std::to_string(temp_buffer.readCompositeLength()));
constexpr size_t pkt_shift = sizeof(ProtoKelCodec::PacketLengthT);
SAW_EXPECT(temp_buffer[pkt_shift] == 5 && temp_buffer[pkt_shift+1] == 0 && temp_buffer[pkt_shift+2] == 0 && temp_buffer[pkt_shift+3] == 0, "Wrong encoded values");
}
@ -57,7 +57,7 @@ SAW_TEST("List Encoding"){
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestTuple>(root.read(), buffer);
error error = codec.encode<TestTuple>(root.read(), buffer);
SAW_EXPECT(!error.failed(), error.message());
SAW_EXPECT(buffer.readCompositeLength() == 14, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -83,7 +83,7 @@ SAW_TEST("Struct Encoding"){
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestStruct>(builder.asReader(), buffer);
error error = codec.encode<TestStruct>(builder.asReader(), buffer);
SAW_EXPECT(!error.failed(), error.message());
SAW_EXPECT(buffer.readCompositeLength() == 40, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -103,7 +103,7 @@ SAW_TEST("Union Encoding"){
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestUnion>(builder.asReader(), buffer);
error error = codec.encode<TestUnion>(builder.asReader(), buffer);
SAW_EXPECT(!error.failed(), error.message());
SAW_EXPECT(buffer.readCompositeLength() == 16, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -120,7 +120,7 @@ SAW_TEST("Union Encoding"){
RingBuffer buffer;
ProtoKelCodec codec;
Error error = codec.encode<TestUnion>(builder.asReader(), buffer);
error error = codec.encode<TestUnion>(builder.asReader(), buffer);
SAW_EXPECT(!error.failed(), error.message());
SAW_EXPECT(buffer.readCompositeLength() == 23, "Bad Size: " + std::to_string(buffer.readCompositeLength()));
@ -141,7 +141,7 @@ SAW_TEST("Tuple Decoding"){
auto root = heapMessageRoot<TestTuple>();
auto builder = root.build();
Error error = codec.decode<TestTuple>(builder, buffer);
error error = codec.decode<TestTuple>(builder, buffer);
SAW_EXPECT(!error.failed(), error.message());
auto reader = builder.asReader();
@ -164,7 +164,7 @@ SAW_TEST("Struct Decoding"){
auto root = heapMessageRoot<TestStruct>();
auto builder = root.build();
Error error = codec.decode<TestStruct>(builder, buffer);
error error = codec.decode<TestStruct>(builder, buffer);
auto reader = builder.asReader();
auto foo_string = reader.get<"test_string">();
@ -188,7 +188,7 @@ SAW_TEST("Union Decoding"){
auto builder = root.build();
auto reader = builder.asReader();
Error error = codec.decode<TestUnion>(builder, buffer);
error error = codec.decode<TestUnion>(builder, buffer);
SAW_EXPECT(!error.failed(), error.message());
SAW_EXPECT(reader.hasAlternative<"test_string">(), "Wrong union value");
@ -220,8 +220,8 @@ SAW_TEST("Array Encoding"){
RingBuffer buffer;
Error error = codec.encode<TestArrayStruct>(root.read(), buffer);
error error = codec.encode<TestArrayStruct>(root.read(), buffer);
SAW_EXPECT(!error.failed(), "Error occured");
SAW_EXPECT(!error.failed(), "error occured");
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <forstio/error.h>
namespace saw {
namespace tools {
/// @todo implement from test code base
template<typename Schema, typename Codec>
Error cliMessageAnalyzer(Codec& codec, int argc, char** argv){
// Parse Args
// If read is required
// Read file into buffer
// If read is required
// Decode file
// Execute commands
// If write is required
// Encode into buffer
// Write to file from buffer
}
}
}