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

10  

11  
#ifndef BOOST_COROSIO_IO_IO_OBJECT_HPP
11  
#ifndef BOOST_COROSIO_IO_IO_OBJECT_HPP
12  
#define BOOST_COROSIO_IO_IO_OBJECT_HPP
12  
#define BOOST_COROSIO_IO_IO_OBJECT_HPP
13  

13  

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

17  

18  
#include <utility>
18  
#include <utility>
19  

19  

20  
namespace boost::corosio {
20  
namespace boost::corosio {
21  

21  

22  
/** Base class for platform I/O objects.
22  
/** Base class for platform I/O objects.
23  

23  

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

28  

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

33  

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

38  

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

41  

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

48  

49  
    /** Base interface for platform I/O implementations.
49  
    /** Base interface for platform I/O implementations.
50  

50  

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

57  

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

59  

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

67  

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

70  

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

73  

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

77  

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

79  

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

88  

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

99  

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

102  

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

110  

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

118  

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

135  

136  
        handle(handle const&)            = delete;
136  
        handle(handle const&)            = delete;
137  
        handle& operator=(handle const&) = delete;
137  
        handle& operator=(handle const&) = delete;
138  

138  

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

144  

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

150  

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

156  

157  
        /** Replace the implementation, destroying the old one.
157  
        /** Replace the implementation, destroying the old one.
158  

158  

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

170  

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

177  

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

183  

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

186  

187  
    /// Default construct for virtual base initialization.
187  
    /// Default construct for virtual base initialization.
188  
    io_object() noexcept = default;
188  
    io_object() noexcept = default;
189  

189  

190  
    /** Create a handle bound to a service found in the context.
190  
    /** Create a handle bound to a service found in the context.
191  

191  

192  
        @tparam Service The service type whose key_type is used for lookup.
192  
        @tparam Service The service type whose key_type is used for lookup.
193  
        @param ctx The execution context to search for the service.
193  
        @param ctx The execution context to search for the service.
194  

194  

195  
        @return A handle owning a freshly constructed implementation.
195  
        @return A handle owning a freshly constructed implementation.
196  

196  

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

208  

209  
    /// Construct an I/O object from a handle.
209  
    /// Construct an I/O object from a handle.
210  
    explicit io_object(handle h) noexcept : h_(std::move(h)) {}
210  
    explicit io_object(handle h) noexcept : h_(std::move(h)) {}
211  

211  

212  
    /// Move construct from another I/O object.
212  
    /// Move construct from another I/O object.
213  
    io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
213  
    io_object(io_object&& other) noexcept : h_(std::move(other.h_)) {}
214  

214  

215  
    /// Move assign from another I/O object.
215  
    /// Move assign from another I/O object.
216  
    io_object& operator=(io_object&& other) noexcept
216  
    io_object& operator=(io_object&& other) noexcept
217  
    {
217  
    {
218  
        if (this != &other)
218  
        if (this != &other)
219  
            h_ = std::move(other.h_);
219  
            h_ = std::move(other.h_);
220  
        return *this;
220  
        return *this;
221  
    }
221  
    }
222  

222  

223  
    io_object(io_object const&)            = delete;
223  
    io_object(io_object const&)            = delete;
224  
    io_object& operator=(io_object const&) = delete;
224  
    io_object& operator=(io_object const&) = delete;
225  

225  

226  
    handle h_;
226  
    handle h_;
227  
};
227  
};
228  

228  

229  
} // namespace boost::corosio
229  
} // namespace boost::corosio
230  

230  

231  
#endif
231  
#endif