/* * This source code is released into the public domain. */ module; #include #include #include #include #include #include export module nihil:fd; import :error; namespace nihil { /* * fd: a file descriptor. */ export struct fd final { // Construct an empty (invalid) fd. fd() noexcept; // Construct an fd from an exising file destrictor, taking ownership. fd(int fd_) noexcept; // Destructor. Close the fd, discarding any errors. ~fd(); // Move from another fd, leaving the moved-from fd in an invalid state. fd(fd &&other) noexcept; auto operator=(this fd &, fd &&other) noexcept -> fd &; // Not copyable. fd(fd const &) = delete; fd& operator=(this fd &, fd const &) = delete; // Return true if this fd is valid (open). [[nodiscard]] explicit operator bool(this fd const &self) noexcept; // Close the wrapped fd. [[nodiscard]] auto close(this fd &self) -> std::expected; // Return the stored fd. [[nodiscard]] auto get(this fd const &self) -> int; // Release the stored fd and return it. The caller must close it. [[nodiscard]] auto release(this fd &&self) -> int; // Write data from the provided buffer to the fd. Returns the // number of bytes written. [[nodiscard]] auto write(this fd &self, std::span) -> std::expected; // Read data from the fd to the provided buffer. Returns a // subspan containing the data which was read. [[nodiscard]] auto read(this fd &self, std::span) -> std::expected, error>; private: static constexpr int invalid_fileno = -1; int m_fileno = invalid_fileno; }; // Create a copy of this fd by calling dup(). export auto dup(fd const &self) -> std::expected; // Create a copy of this fd by calling dup2(). Note that because this results // in the existing fd and the new fd both being managed by an fd instance, // there are two potential cases that can cause problems: // // - dup()ing an fd to itself (a no-op) // - dup()ing an fd to an fd which is already managed by an fd instance // // In both of these cases, either use raw_dup() instead, or immediately call // release() on the returned fd to prevent the fd instance from closing it. export auto dup(fd const &self, int newfd) -> std::expected; // Create a copy of this fd by calling dup(). export auto raw_dup(fd const &self) -> std::expected; // Create a copy of this fd by calling dup2(). export auto raw_dup(fd const &self, int newfd) -> std::expected; // Return the fnctl flags for this fd. export auto getflags(fd const &self) -> std::expected; // Replace the fnctl flags for this fd. export auto replaceflags(fd &self, int newflags) -> std::expected; // Add bits to the fcntl flags for this fd. Returns the new flags. export auto setflags(fd &self, int newflags) -> std::expected; // Remove bits from the fcntl flags for this fd. Returns the new flags. export auto clearflags(fd &self, int clrflags) -> std::expected; // Return the fd flags for this fd. export auto getfdflags(fd const &self) -> std::expected; // Replace the fd flags for this fd. export auto replacefdflags(fd &self, int newflags) -> std::expected; // Add bits to the fd flags for this fd. Returns the new flags. export auto setfdflags(fd &self, int newflags) -> std::expected; // Remove bits from the fd flags for this fd. Returns the new flags. export auto clearfdflags(fd &self, int clrflags) -> std::expected; // Create two fds by calling pipe() and return them. export auto pipe() -> std::expected, error>; /* * Write data to a file descriptor from the provided range. Returns the * number of bytes written. */ export auto write(fd &file, std::ranges::contiguous_range auto &&range) -> std::expected requires(sizeof(std::ranges::range_value_t) == 1) { return file.write(as_bytes(std::span(range))); } /* * Read data from a file descriptor into the provided buffer. Returns a * span containing the data that was read. */ export auto read(fd &file, std::ranges::contiguous_range auto &&range) -> std::expected< std::span>, error> requires(sizeof(std::ranges::range_value_t) == 1) { auto bspan = as_writable_bytes(std::span(range)); auto rspan = co_await file.read(bspan); co_return std::span(range).subspan(0, rspan.size()); } } // namespace nihil