Skip to content

Commit

Permalink
Add unistd C++ library
Browse files Browse the repository at this point in the history
  • Loading branch information
timower committed Oct 10, 2023
1 parent 4ac02ef commit fd071fb
Show file tree
Hide file tree
Showing 25 changed files with 823 additions and 11 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@ name: Build
on: [push, pull_request]

jobs:
build-host:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- name: Install Ninja
run: sudo apt-get install -y ninja-build

- name: Configure CMake
run: cmake --preset dev-host

- name: Build
run: cmake --build build/host

- name: Test
run: ctest --test-dir build/host

build:
runs-on: ubuntu-latest
container:
Expand All @@ -25,6 +43,7 @@ jobs:
with:
name: package
path: build/release-toltec/rm2stuff.ipk

release:
runs-on: ubuntu-latest
needs: build
Expand Down
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ add_subdirectory(tools)
add_subdirectory(apps)
add_subdirectory(vendor)

option(BUILD_TESTS "Build Tests" OFF)
if (${BUILD_TESTS})
enable_testing()
add_subdirectory(test)
endif()


set(CPACK_GENERATOR "DEB")
set(CPACK_POST_BUILD_SCRIPTS "${PROJECT_SOURCE_DIR}/cmake/GenIPK.cmake")
Expand Down
3 changes: 2 additions & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_FLAGS": "$env{BASE_FLAGS}",
"CMAKE_CXX_FLAGS": "$env{BASE_FLAGS_CXX}"
"CMAKE_CXX_FLAGS": "$env{BASE_FLAGS_CXX}",
"BUILD_TESTS": true
}
},

Expand Down
1 change: 1 addition & 0 deletions libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ add_subdirectory(swtcon)
add_subdirectory(rMlib)
add_subdirectory(rm2fb)
add_subdirectory(libYaft)
add_subdirectory(unistdpp)
2 changes: 1 addition & 1 deletion libs/rMlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ target_include_directories(${PROJECT_NAME}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(${PROJECT_NAME} PUBLIC tl::expected)
target_link_libraries(${PROJECT_NAME} PUBLIC tl::expected unistdpp)

# If not emulating, or emulating uinput, link in udev, evdev and linux headers.
if (NOT EMULATE OR EMULATE_UINPUT)
Expand Down
11 changes: 2 additions & 9 deletions libs/rMlib/include/Error.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <unistdpp/error.h>

#include <cassert>
#include <cstring>

Expand All @@ -24,12 +26,3 @@ using ErrorOr = tl::expected<T, E>;

template<typename E = Error>
using OptError = tl::expected<void, E>;

#define TRY(x) \
({ \
auto xOrErr = x; \
if (!xOrErr.has_value()) { \
return tl::unexpected(xOrErr.error()); \
}; \
std::move(*xOrErr); \
})
16 changes: 16 additions & 0 deletions libs/unistdpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
project(unistdpp)

add_library(${PROJECT_NAME} STATIC
unistdpp.cpp
file.cpp
pipe.cpp
poll.cpp
socket.cpp)

target_include_directories(${PROJECT_NAME}
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(${PROJECT_NAME} PUBLIC tl::expected)
19 changes: 19 additions & 0 deletions libs/unistdpp/file.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include "unistdpp/file.h"

namespace unistdpp {

Result<std::string>
readFile(const std::filesystem::path& path) {
return open(path.c_str(), O_RDONLY).and_then([](auto fd) {
std::string buf;
return lseek(fd, 0, SEEK_END)
.and_then([&](auto offset) {
buf.resize(offset);
return lseek(fd, 0, SEEK_SET);
})
.and_then([&](auto) { return fd.readAll(buf.data(), buf.size()); })
.map([&buf]() { return std::move(buf); });
});
}

} // namespace unistdpp
68 changes: 68 additions & 0 deletions libs/unistdpp/include/unistdpp/error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

#include "traits.h"

#include <tl/expected.hpp>

#include <system_error>

namespace error_details {
template<typename T, typename E>
constexpr auto
getValue(tl::expected<T, E> v) {
if constexpr (std::is_same_v<T, void>) {
return;
} else {
return std::move(*v);
}
}
} // namespace error_details

#define TRY(x) \
({ \
auto&& xOrErr = x; \
if (!xOrErr.has_value()) { \
return tl::unexpected(xOrErr.error()); \
}; \
error_details::getValue(std::move(xOrErr)); \
})

namespace unistdpp {
template<typename T>
using Result = tl::expected<T, std::errc>;

[[nodiscard]] inline std::errc
getErrno() {
return static_cast<std::errc>(errno);
}

inline std::string
toString(std::errc error) {
return std::make_error_code(error).message();
}

template<typename T>
struct WrapperTraits<Result<T>> {
static_assert(
std::is_integral_v<T>,
"Please provide explicit wrapper trait for non integral results");

static Result<T> ret(T res) {
if (res == -1) {
return tl::unexpected(getErrno());
}
return res;
}
};

template<>
struct WrapperTraits<Result<void>> {
static Result<void> ret(int res) {
if (res == -1) {
return tl::unexpected(getErrno());
}
return {};
}
};

} // namespace unistdpp
17 changes: 17 additions & 0 deletions libs/unistdpp/include/unistdpp/file.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include "unistdpp.h"

#include <fcntl.h>
#include <filesystem>

namespace unistdpp {

constexpr auto open = FnWrapper<::open, Result<FD>(const char*, int)>{};
constexpr auto lseek =
FnWrapper<::lseek, Result<off_t>(const FD&, off_t, int)>{};

Result<std::string>
readFile(const std::filesystem::path& path);

} // namespace unistdpp
18 changes: 18 additions & 0 deletions libs/unistdpp/include/unistdpp/pipe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once

#include "unistdpp.h"

#include <system_error>
#include <tl/expected.hpp>

namespace unistdpp {

struct Pipe {
FD readPipe;
FD writePipe;
};

Result<Pipe>
pipe();

} // namespace unistdpp
38 changes: 38 additions & 0 deletions libs/unistdpp/include/unistdpp/poll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#pragma once

#include "unistdpp.h"

#include <chrono>
#include <optional>
#include <vector>

#include <poll.h>

namespace unistdpp {

enum class Wait {
READ = POLLIN,
WRITE = POLLOUT,
READ_WRITE = POLLIN | POLLOUT,
};

inline pollfd
waitFor(const FD& fd, Wait wait) {
return pollfd{ .fd = fd.fd, .events = static_cast<short>(wait) };
}

inline bool
canRead(const pollfd& fd) {
return (fd.revents & POLLIN) != 0;
}

inline bool
canWrite(const pollfd& fd) {
return (fd.revents & POLLOUT) != 0;
}

Result<int>
poll(std::vector<pollfd>& pollfds,
std::optional<std::chrono::milliseconds> timeout = std::nullopt);

} // namespace unistdpp
105 changes: 105 additions & 0 deletions libs/unistdpp/include/unistdpp/socket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#pragma once

#include "traits.h"
#include "unistdpp.h"

#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <string_view>
#include <tuple>
#include <variant>

namespace unistdpp {

struct Address {
static Address fromUnixPath(const char* path);
static Address fromHostPort(int32_t host, int port);
static Result<Address> fromHostPort(std::string_view host, int port);

sockaddr* ptr() noexcept { return reinterpret_cast<sockaddr*>(&storage); }
const sockaddr* ptr() const noexcept {
return reinterpret_cast<const sockaddr*>(&storage);
}

sa_family_t type() const noexcept { return ptr()->sa_family; }

socklen_t size() const noexcept { return addressSize; }

std::aligned_union_t<0, sockaddr_un, sockaddr_in> storage;
socklen_t addressSize = sizeof(storage);
};

template<>
struct WrapperTraits<const Address&> {
static std::tuple<const sockaddr*, socklen_t> arg(const Address& addr) {
return { addr.ptr(), addr.size() };
}
};

template<>
struct WrapperTraits<const Address*> {
static std::tuple<const sockaddr*, socklen_t> arg(const Address* addr) {
return { addr ? addr->ptr() : nullptr, addr ? addr->size() : 0 };
}
};

template<>
struct WrapperTraits<Address*> {
static std::tuple<sockaddr*, socklen_t*> arg(Address* addr) {
return { addr ? addr->ptr() : nullptr,
addr ? &addr->addressSize : nullptr };
}
};

// int
// socket(int domain, int type, int protocol);
constexpr auto socket = FnWrapper<::socket, Result<FD>(int, int, int)>{};

// int
// setsockopt(int socket, int level, int option_name,
// const void *option_value, socklen_t option_len);
constexpr auto setsockopt =
FnWrapper<::setsockopt,
Result<void>(const FD&, int, int, const void*, socklen_t)>{};

// int
// bind(int socket, const struct sockaddr *address, socklen_t address_len);
constexpr auto bindRaw =
FnWrapper<::bind, Result<void>(const FD& fd, const sockaddr*, socklen_t)>{};
constexpr auto bind =
FnWrapper<::bind, Result<void>(const FD& fd, const Address&)>{};

// int
// listen(int socket, int backlog);
constexpr auto listen = FnWrapper<::listen, Result<void>(const FD&, int)>{};

// int
// accept(int socket, struct sockaddr *restrict address,
// socklen_t *restrict address_len);
constexpr auto accept =
FnWrapper<::accept, Result<FD>(const FD&, sockaddr*, socklen_t*)>{};

// int connect(int socket, const struct sockaddr *address,
// socklen_t address_len);
constexpr auto connectRaw =
FnWrapper<::connect, Result<void>(const FD&, const sockaddr*, socklen_t)>{};
constexpr auto connect =
FnWrapper<::connect, Result<void>(const FD&, const Address&)>{};

// ssize_t sendto(int socket, const void *message, size_t length,
// int flags, const struct sockaddr *dest_addr,
// socklen_t dest_len);
constexpr auto sendto = FnWrapper<
::sendto,
Result<ssize_t>(const FD&, const void*, size_t, int, const Address*)>{};

// ssize_t recvfrom(int socket, void *restrict buffer, size_t length,
// int flags, struct sockaddr *restrict address,
// socklen_t *restrict address_len);
constexpr auto recvfrom =
FnWrapper<::recvfrom,
Result<ssize_t>(const FD&, void*, size_t, int, Address*)>{};
} // namespace unistdpp
Loading

0 comments on commit fd071fb

Please sign in to comment.