- proto::parser will likely contain helper functions for parsing messages from a buffer, for now it will explicitly define message parsers for each available message. It also leverages the new unpacker API, which has type safety in mind. These messages should not be unstructured, so it doesn't make sense to use the token API.
157 lines
3.8 KiB
C++
157 lines
3.8 KiB
C++
//-----------------------------------------------------------------------------
|
|
// ___ __ _ _
|
|
// / _ \__ _ _ __ ___ ___ / /(_)_ __ | | __
|
|
// / /_)/ _` | '__/ __|/ _ \/ / | | '_ \| |/ /
|
|
// / ___/ (_| | | \__ \ __/ /__| | | | | <
|
|
// \/ \__,_|_| |___/\___\____/_|_| |_|_|\_\ .
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
// Author: Kurt Sassenrath
|
|
// Module: Utility
|
|
//
|
|
// Utility wrappers for dealing with files.
|
|
//
|
|
// Copyright (c) 2023 Kurt Sassenrath.
|
|
//
|
|
// License TBD.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef utility_file_8b49e5e471a7c3e5
|
|
#define utility_file_8b49e5e471a7c3e5
|
|
|
|
#include <fmt/format.h>
|
|
#include <tl/expected.hpp>
|
|
|
|
#include <algorithm>
|
|
#include <fcntl.h>
|
|
#include <span>
|
|
#include <system_error>
|
|
#include <unistd.h>
|
|
#include <vector>
|
|
|
|
namespace parselink {
|
|
namespace utility {
|
|
namespace file {
|
|
|
|
struct [[nodiscard]] handle {
|
|
constexpr handle() noexcept = default;
|
|
|
|
constexpr handle(int fd) noexcept
|
|
: fd_(fd) {
|
|
if (fd_ < 0) fd_ = -errno;
|
|
}
|
|
|
|
constexpr handle(handle const&) noexcept = delete;
|
|
|
|
constexpr handle(handle&& other) noexcept
|
|
: fd_(other.fd_) {
|
|
other.fd_ = -1;
|
|
}
|
|
|
|
constexpr handle& operator=(handle const&) noexcept = delete;
|
|
|
|
constexpr handle& operator=(handle&& other) noexcept {
|
|
close();
|
|
fd_ = other.fd_;
|
|
return *this;
|
|
}
|
|
|
|
constexpr operator bool() const noexcept { return fd_ >= 0; }
|
|
|
|
constexpr int operator*() const noexcept { return fd_; }
|
|
|
|
void close() {
|
|
if (*this) {
|
|
::close(fd_);
|
|
fd_ = -1;
|
|
}
|
|
}
|
|
|
|
int fd_{-1};
|
|
};
|
|
|
|
inline tl::expected<handle, std::errc> open(
|
|
std::string_view path, int flags, int mode = {}) noexcept {
|
|
handle file(::open(std::string{path}.c_str(), flags, mode));
|
|
if (file) {
|
|
return file;
|
|
} else {
|
|
return tl::make_unexpected(static_cast<std::errc>(-*file));
|
|
}
|
|
}
|
|
|
|
inline tl::expected<std::vector<std::byte>, std::errc> read_some(
|
|
handle file, std::size_t amount) noexcept {
|
|
std::vector<std::byte> data;
|
|
|
|
if (!file) {
|
|
return tl::make_unexpected(static_cast<std::errc>(-*file));
|
|
}
|
|
|
|
data.resize(amount);
|
|
|
|
auto amt_read = ::read(*file, data.data(), amount);
|
|
|
|
if (amt_read < data.size()) {
|
|
data.resize(amt_read);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
template <typename T>
|
|
requires(std::is_trivially_default_constructible_v<T> && sizeof(T) == 1)
|
|
inline tl::expected<std::vector<T>, std::errc> read(
|
|
handle const& file) noexcept {
|
|
std::vector<T> data;
|
|
|
|
if (!file) {
|
|
return tl::make_unexpected(static_cast<std::errc>(-*file));
|
|
}
|
|
|
|
auto cur = lseek(*file, 0, SEEK_CUR);
|
|
auto end = lseek(*file, 0, SEEK_END);
|
|
std::size_t amount = end - cur;
|
|
lseek(*file, SEEK_SET, cur);
|
|
data.resize(amount);
|
|
|
|
auto amt_read = ::read(*file, data.data(), amount);
|
|
|
|
if (amt_read < data.size()) {
|
|
data.resize(amt_read);
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
template <typename T>
|
|
requires(std::is_trivially_default_constructible_v<T> && sizeof(T) == 1)
|
|
inline tl::expected<std::size_t, std::errc> write(
|
|
handle const& file, std::span<T> data) noexcept {
|
|
if (!file) {
|
|
return tl::make_unexpected(static_cast<std::errc>(-*file));
|
|
}
|
|
|
|
lseek(*file, 0, SEEK_SET);
|
|
|
|
auto result = ftruncate(*file, 0);
|
|
|
|
if (result < 0) {
|
|
return tl::make_unexpected(static_cast<std::errc>(errno));
|
|
}
|
|
|
|
auto amt_written = ::write(*file, data.data(), data.size());
|
|
|
|
if (result < 0) {
|
|
return tl::make_unexpected(static_cast<std::errc>(errno));
|
|
}
|
|
|
|
return static_cast<std::size_t>(amt_written);
|
|
}
|
|
|
|
} // namespace file
|
|
} // namespace utility
|
|
} // namespace parselink
|
|
|
|
#endif // utility_file_8b49e5e471a7c3e5
|