blob: d18e8553488030137028f9b45016d62182c86d34 [file] [log] [blame]
#include <stdplus/exception.hpp>
#include <stdplus/fd/ops.hpp>
#include <format>
#include <utility>
namespace stdplus
{
namespace fd
{
namespace detail
{
template <typename Fun, typename Byte, typename... Args>
static void opExact(const char* name, Fun&& fun, Fd& fd, std::span<Byte> data,
Args&&... args)
{
std::size_t total = 0;
try
{
while (total < data.size())
{
auto r = (fd.*fun)(data.subspan(total),
std::forward<Args>(args)...);
if (r.size() == 0)
{
throw exception::WouldBlock(
std::format("{} missing", name, data.size()));
}
total += r.size();
}
}
catch (const std::system_error&)
{
if (total != 0)
{
throw exception::Incomplete(
std::format("{} is {}B/{}B", name, total, data.size()));
}
throw;
}
}
void readExact(Fd& fd, std::span<std::byte> data)
{
opExact("readExact", &Fd::read, fd, data);
}
void recvExact(Fd& fd, std::span<std::byte> data, RecvFlags flags)
{
opExact("recvExact", &Fd::recv, fd, data, flags);
}
void writeExact(Fd& fd, std::span<const std::byte> data)
{
opExact("writeExact", &Fd::write, fd, data);
}
void sendExact(Fd& fd, std::span<const std::byte> data, SendFlags flags)
{
opExact("sendExact", &Fd::send, fd, data, flags);
}
template <typename Fun, typename Byte, typename... Args>
static std::span<Byte> opAligned(const char* name, Fun&& fun, Fd& fd,
size_t align, std::span<Byte> data,
Args&&... args)
{
std::size_t total = 0;
try
{
do
{
auto r = (fd.*fun)(data.subspan(total),
std::forward<Args>(args)...);
if (total != 0 && r.size() == 0)
{
throw exception::Incomplete(
std::format("{} is {}B/{}B", name, total % align, align));
}
total += r.size();
} while (total % align != 0);
}
catch (const std::system_error&)
{
if (total % align)
{
throw exception::Incomplete(
std::format("{} is {}B/{}B", name, total % align, align));
}
throw;
}
return std::span<Byte>(data.data(), total);
}
std::span<std::byte> readAligned(Fd& fd, size_t align, std::span<std::byte> buf)
{
return opAligned("readAligned", &Fd::read, fd, align, buf);
}
std::span<std::byte> recvAligned(Fd& fd, size_t align, std::span<std::byte> buf,
RecvFlags flags)
{
return opAligned("recvAligned", &Fd::recv, fd, align, buf, flags);
}
std::span<const std::byte> writeAligned(Fd& fd, size_t align,
std::span<const std::byte> data)
{
return opAligned("writeAligned", &Fd::write, fd, align, data);
}
std::span<const std::byte> sendAligned(Fd& fd, size_t align,
std::span<const std::byte> data,
SendFlags flags)
{
return opAligned("sendAligned", &Fd::send, fd, align, data, flags);
}
} // namespace detail
} // namespace fd
} // namespace stdplus