1 -
//
 
2 -
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
 
3 -
//
 
4 -
// Distributed under the Boost Software License, Version 1.0. (See accompanying
 
5 -
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
6 -
//
 
7 -
// Official repository: https://github.com/cppalliance/corosio
 
8 -
//
 
9 -

 
10 -
#ifndef BOOST_COROSIO_IO_OBJECT_HPP
 
11 -
#define BOOST_COROSIO_IO_OBJECT_HPP
 
12 -

 
13 -
#include <boost/corosio/detail/config.hpp>
 
14 -
#include <boost/corosio/detail/except.hpp>
 
15 -
#include <boost/capy/ex/execution_context.hpp>
 
16 -

 
17 -
#include <utility>
 
18 -

 
19 -
namespace boost::corosio {
 
20 -

 
21 -
/** Base class for platform I/O objects.
 
22 -

 
23 -
    Provides common infrastructure for I/O objects that wrap kernel
 
24 -
    resources (sockets, timers, signal handlers, acceptors). Derived
 
25 -
    classes dispatch operations through a platform-specific vtable
 
26 -
    (IOCP, epoll, kqueue, io_uring).
 
27 -

 
28 -
    @par Semantics
 
29 -
    Only concrete platform I/O types should inherit from `io_object`.
 
30 -
    Test mocks, decorators, and stream adapters must not inherit from
 
31 -
    this class. Use concepts or templates for generic I/O algorithms.
 
32 -

 
33 -
    @par Thread Safety
 
34 -
    Distinct objects: Safe.
 
35 -
    Shared objects: Unsafe. All operations on a single I/O object
 
36 -
    must be serialized.
 
37 -

 
38 -
    @note Intended as a protected base class. The handle member
 
39 -
        `h_` is accessible to derived classes.
 
40 -

 
41 -
    @see io_stream, tcp_socket, tcp_acceptor
 
42 -
*/
 
43 -
class BOOST_COROSIO_DECL io_object
 
44 -
{
 
45 -
public:
 
46 -
    class handle;
 
47 -

 
48 -
    /** Base interface for platform I/O implementations.
 
49 -

 
50 -
        Derived classes provide platform-specific operation dispatch.
 
51 -
    */
 
52 -
    struct implementation
 
53 -
    {
 
54 -
        virtual ~implementation() = default;
 
55 -
    };
 
56 -

 
57 -
    /** Service interface for I/O object lifecycle management.
 
58 -

 
59 -
        Platform backends implement this interface to manage the
 
60 -
        creation, closing, and destruction of I/O object
 
61 -
        implementations.
 
62 -
    */
 
63 -
    struct io_service
 
64 -
    {
 
65 -
        virtual ~io_service() = default;
 
66 -

 
67 -
        /// Construct a new implementation instance.
 
68 -
        virtual implementation* construct() = 0;
 
69 -

 
70 -
        /// Destroy the implementation, closing kernel resources and freeing memory.
 
71 -
        virtual void destroy(implementation*) = 0;
 
72 -

 
73 -
        /// Close the I/O object, releasing kernel resources without deallocating.
 
74 -
        virtual void close(handle&) {}
 
75 -
    };
 
76 -

 
77 -
    /** RAII wrapper for I/O object implementation lifetime.
 
78 -

 
79 -
        Manages ownership of the platform-specific implementation,
 
80 -
        automatically destroying it when the handle goes out of scope.
 
81 -
    */
 
82 -
    class handle
 
83 -
    {
 
84 -
        capy::execution_context* ctx_ = nullptr;
 
85 -
        io_service* svc_ = nullptr;
 
86 -
        implementation* impl_ = nullptr;
 
87 -

 
88 -
    public:
 
89 -
        /// Destroy the handle and its implementation.
 
90 -
        ~handle()
 
91 -
        {
 
92 -
            if (impl_)
 
93 -
            {
 
94 -
                svc_->close(*this);
 
95 -
                svc_->destroy(impl_);
 
96 -
            }
 
97 -
        }
 
98 -

 
99 -
        /// Construct an empty handle.
 
100 -
        handle() = default;
 
101 -

 
102 -
        /// Construct a handle bound to a context and service.
 
103 -
        handle(capy::execution_context& ctx, io_service& svc)
 
104 -
            : ctx_(&ctx)
 
105 -
            , svc_(&svc)
 
106 -
            , impl_(svc_->construct())
 
107 -
        {
 
108 -
        }
 
109 -

 
110 -
        /// Move construct from another handle.
 
111 -
        handle(handle&& other) noexcept
 
112 -
            : ctx_(std::exchange(other.ctx_, nullptr))
 
113 -
            , svc_(std::exchange(other.svc_, nullptr))
 
114 -
            , impl_(std::exchange(other.impl_, nullptr))
 
115 -
        {
 
116 -
        }
 
117 -

 
118 -
        /// Move assign from another handle.
 
119 -
        handle& operator=(handle&& other) noexcept
 
120 -
        {
 
121 -
            if (this != &other)
 
122 -
            {
 
123 -
                if (impl_)
 
124 -
                {
 
125 -
                    svc_->close(*this);
 
126 -
                    svc_->destroy(impl_);
 
127 -
                }
 
128 -
                ctx_ = std::exchange(other.ctx_, nullptr);
 
129 -
                svc_ = std::exchange(other.svc_, nullptr);
 
130 -
                impl_ = std::exchange(other.impl_, nullptr);
 
131 -
            }
 
132 -
            return *this;
 
133 -
        }
 
134 -

 
135 -
        handle(handle const&) = delete;
 
136 -
        handle& operator=(handle const&) = delete;
 
137 -

 
138 -
        /// Return true if the handle owns an implementation.
 
139 -
        explicit operator bool() const noexcept
 
140 -
        {
 
141 -
            return impl_ != nullptr;
 
142 -
        }
 
143 -

 
144 -
        /// Return the associated I/O service.
 
145 -
        io_service& service() const noexcept
 
146 -
        {
 
147 -
            return *svc_;
 
148 -
        }
 
149 -

 
150 -
        /// Return the platform implementation.
 
151 -
        implementation* get() const noexcept
 
152 -
        {
 
153 -
            return impl_;
 
154 -
        }
 
155 -

 
156 -
        /** Replace the implementation, destroying the old one.
 
157 -

 
158 -
            @param p The new implementation to own. May be nullptr.
 
159 -
        */
 
160 -
        void reset(implementation* p) noexcept
 
161 -
        {
 
162 -
            if (impl_)
 
163 -
            {
 
164 -
                svc_->close(*this);
 
165 -
                svc_->destroy(impl_);
 
166 -
            }
 
167 -
            impl_ = p;
 
168 -
        }
 
169 -

 
170 -
        /// Return the execution context.
 
171 -
        capy::execution_context& context() const noexcept
 
172 -
        {
 
173 -
            return *ctx_;
 
174 -
        }
 
175 -
    };
 
176 -

 
177 -
    /// Return the execution context.
 
178 -
    capy::execution_context& context() const noexcept
 
179 -
    {
 
180 -
        return h_.context();
 
181 -
    }
 
182 -

 
183 -
protected:
 
184 -
    virtual ~io_object() = default;
 
185 -

 
186 -
    /** Create a handle bound to a service found in the context.
 
187 -

 
188 -
        @tparam Service The service type whose key_type is used for lookup.
 
189 -
        @param ctx The execution context to search for the service.
 
190 -

 
191 -
        @return A handle owning a freshly constructed implementation.
 
192 -

 
193 -
        @throws std::logic_error if the service is not installed.
 
194 -
    */
 
195 -
    template<class Service>
 
196 -
    static handle create_handle(capy::execution_context& ctx)
 
197 -
    {
 
198 -
        auto* svc = ctx.find_service<Service>();
 
199 -
        if (!svc)
 
200 -
            detail::throw_logic_error(
 
201 -
                "io_object::create_handle: service not installed");
 
202 -
        return handle(ctx, *svc);
 
203 -
    }
 
204 -

 
205 -
    /// Construct an I/O object from a handle.
 
206 -
    explicit io_object(handle h) noexcept : h_(std::move(h)) {}
 
207 -

 
208 -
    /// Move construct from another I/O object.
 
209 -
    io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
 
210 -

 
211 -
    /// Move assign from another I/O object.
 
212 -
    io_object& operator=(io_object&& other) noexcept
 
213 -
    {
 
214 -
        if (this != &other)
 
215 -
            h_ = std::move(other.h_);
 
216 -
        return *this;
 
217 -
    }
 
218 -

 
219 -
    io_object(io_object const&) = delete;
 
220 -
    io_object& operator=(io_object const&) = delete;
 
221 -

 
222 -
    handle h_;
 
223 -
};
 
224 -

 
225 -
} // namespace boost::corosio
 
226 -

 
227 -
#endif