/* * This source code is released into the public domain. */ module; #include #include #include #include #include export module nihil:fd; import :generic_error; namespace nihil { /* * Exception thrown when an internal fd error occurs. This is not supposed * to be caught, since it indicates an internal logic error in the caller. */ export struct fd_logic_error final : std::logic_error { fd_logic_error(std::string what); }; /* * 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=(fd &&other) noexcept -> fd &; // Not copyable. fd(fd const &) = delete; fd& operator=(fd const &) = delete; // Return true if this fd is valid (open). explicit operator bool(this fd const &self) noexcept; // Close the wrapped fd. auto close(this fd &self) -> std::expected; // Return the stored fd. auto get(this fd const &self) -> int; // Release the stored fd and return it. The caller must close it. auto release(this fd &&self) -> int; // Write data from the provided buffer to the fd. Returns the // number of bytes written. auto write(this fd &self, std::span) -> std::expected; // Read data from the fd to the provided buffer. Returns the // number of bytes read. auto read(this fd &self, std::span) -> std::expected; private: static constexpr int _invalid_fd = -1; int _fd = _invalid_fd; }; // 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, std::error_code>; /* * Write data to a file descriptor from the provided range. Returns the * number of bytes (not objects) written. Incomplete writes may cause a * partial object to be written. */ export auto write(fd &file, std::ranges::contiguous_range auto &&range) -> std::expected { return file.write(as_bytes(std::span(range))); } /* * Read data from a file descriptor into the provided buffer. Returns the * number of bytes (not objects) read. Incomplete reads may cause a partial * object to be read. */ export auto read(fd &file, std::ranges::contiguous_range auto &&range) -> std::expected { return file.read(as_writable_bytes(std::span(range))); } } // namespace nihil