1  
//
1  
//
2  
// Copyright (c) 2026 Michael Vandeberg
2  
// Copyright (c) 2026 Michael Vandeberg
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/cppalliance/corosio
7  
// Official repository: https://github.com/cppalliance/corosio
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
10  
#ifndef BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
11  
#define BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
11  
#define BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
12  

12  

13  
#include <boost/corosio/detail/config.hpp>
13  
#include <boost/corosio/detail/config.hpp>
14  
#include <boost/corosio/detail/platform.hpp>
14  
#include <boost/corosio/detail/platform.hpp>
15  
#include <boost/corosio/detail/except.hpp>
15  
#include <boost/corosio/detail/except.hpp>
16  
#include <boost/corosio/detail/native_handle.hpp>
16  
#include <boost/corosio/detail/native_handle.hpp>
17  
#include <boost/corosio/detail/buffer_param.hpp>
17  
#include <boost/corosio/detail/buffer_param.hpp>
18  
#include <boost/corosio/file_base.hpp>
18  
#include <boost/corosio/file_base.hpp>
19  
#include <boost/corosio/io/io_object.hpp>
19  
#include <boost/corosio/io/io_object.hpp>
20  
#include <boost/capy/io_result.hpp>
20  
#include <boost/capy/io_result.hpp>
21  
#include <boost/capy/ex/executor_ref.hpp>
21  
#include <boost/capy/ex/executor_ref.hpp>
22  
#include <boost/capy/ex/execution_context.hpp>
22  
#include <boost/capy/ex/execution_context.hpp>
23  
#include <boost/capy/ex/io_env.hpp>
23  
#include <boost/capy/ex/io_env.hpp>
24  
#include <boost/capy/concept/executor.hpp>
24  
#include <boost/capy/concept/executor.hpp>
25  
#include <boost/capy/buffers.hpp>
25  
#include <boost/capy/buffers.hpp>
26  

26  

27  
#include <concepts>
27  
#include <concepts>
28  
#include <coroutine>
28  
#include <coroutine>
29  
#include <cstddef>
29  
#include <cstddef>
30  
#include <cstdint>
30  
#include <cstdint>
31  
#include <type_traits>
31  
#include <type_traits>
32  
#include <filesystem>
32  
#include <filesystem>
33  
#include <stop_token>
33  
#include <stop_token>
34  
#include <system_error>
34  
#include <system_error>
35  

35  

36  
namespace boost::corosio {
36  
namespace boost::corosio {
37  

37  

38  
/** An asynchronous random-access file for coroutine I/O.
38  
/** An asynchronous random-access file for coroutine I/O.
39  

39  

40  
    Provides asynchronous read and write operations at explicit
40  
    Provides asynchronous read and write operations at explicit
41  
    byte offsets, without maintaining an implicit file position.
41  
    byte offsets, without maintaining an implicit file position.
42  

42  

43  
    On POSIX platforms, file I/O is dispatched to a thread pool
43  
    On POSIX platforms, file I/O is dispatched to a thread pool
44  
    (blocking `preadv`/`pwritev`) with completion posted back to
44  
    (blocking `preadv`/`pwritev`) with completion posted back to
45  
    the scheduler. On Windows, true overlapped I/O is used via IOCP.
45  
    the scheduler. On Windows, true overlapped I/O is used via IOCP.
46  

46  

47  
    @par Thread Safety
47  
    @par Thread Safety
48  
    Distinct objects: Safe.@n
48  
    Distinct objects: Safe.@n
49  
    Shared objects: Unsafe. Multiple concurrent reads and writes
49  
    Shared objects: Unsafe. Multiple concurrent reads and writes
50  
    are supported from coroutines sharing the same file object,
50  
    are supported from coroutines sharing the same file object,
51  
    but external synchronization is required for non-async
51  
    but external synchronization is required for non-async
52  
    operations (open, close, size, resize, etc.).
52  
    operations (open, close, size, resize, etc.).
53  

53  

54  
    @par Example
54  
    @par Example
55  
    @code
55  
    @code
56  
    io_context ioc;
56  
    io_context ioc;
57  
    random_access_file f(ioc);
57  
    random_access_file f(ioc);
58  
    f.open("data.bin", file_base::read_only);
58  
    f.open("data.bin", file_base::read_only);
59  

59  

60  
    char buf[4096];
60  
    char buf[4096];
61  
    auto [ec, n] = co_await f.read_some_at(
61  
    auto [ec, n] = co_await f.read_some_at(
62  
        0, capy::mutable_buffer(buf, sizeof(buf)));
62  
        0, capy::mutable_buffer(buf, sizeof(buf)));
63  
    @endcode
63  
    @endcode
64  
*/
64  
*/
65  
class BOOST_COROSIO_DECL random_access_file : public io_object
65  
class BOOST_COROSIO_DECL random_access_file : public io_object
66  
{
66  
{
67  
public:
67  
public:
68  
    /** Platform-specific random-access file implementation interface.
68  
    /** Platform-specific random-access file implementation interface.
69  

69  

70  
        Backends derive from this to provide offset-based file I/O.
70  
        Backends derive from this to provide offset-based file I/O.
71  
    */
71  
    */
72  
    struct implementation : io_object::implementation
72  
    struct implementation : io_object::implementation
73  
    {
73  
    {
74  
        /** Initiate a read at the given offset.
74  
        /** Initiate a read at the given offset.
75  

75  

76  
            @param offset Byte offset into the file.
76  
            @param offset Byte offset into the file.
77  
            @param h Coroutine handle to resume on completion.
77  
            @param h Coroutine handle to resume on completion.
78  
            @param ex Executor for dispatching the completion.
78  
            @param ex Executor for dispatching the completion.
79  
            @param buf The buffer to read into.
79  
            @param buf The buffer to read into.
80  
            @param token Stop token for cancellation.
80  
            @param token Stop token for cancellation.
81  
            @param ec Output error code.
81  
            @param ec Output error code.
82  
            @param bytes_out Output bytes transferred.
82  
            @param bytes_out Output bytes transferred.
83  
            @return Coroutine handle to resume immediately.
83  
            @return Coroutine handle to resume immediately.
84  
        */
84  
        */
85  
        virtual std::coroutine_handle<> read_some_at(
85  
        virtual std::coroutine_handle<> read_some_at(
86  
            std::uint64_t offset,
86  
            std::uint64_t offset,
87  
            std::coroutine_handle<> h,
87  
            std::coroutine_handle<> h,
88  
            capy::executor_ref ex,
88  
            capy::executor_ref ex,
89  
            buffer_param buf,
89  
            buffer_param buf,
90  
            std::stop_token token,
90  
            std::stop_token token,
91  
            std::error_code* ec,
91  
            std::error_code* ec,
92  
            std::size_t* bytes_out) = 0;
92  
            std::size_t* bytes_out) = 0;
93  

93  

94  
        /** Initiate a write at the given offset.
94  
        /** Initiate a write at the given offset.
95  

95  

96  
            @param offset Byte offset into the file.
96  
            @param offset Byte offset into the file.
97  
            @param h Coroutine handle to resume on completion.
97  
            @param h Coroutine handle to resume on completion.
98  
            @param ex Executor for dispatching the completion.
98  
            @param ex Executor for dispatching the completion.
99  
            @param buf The buffer to write from.
99  
            @param buf The buffer to write from.
100  
            @param token Stop token for cancellation.
100  
            @param token Stop token for cancellation.
101  
            @param ec Output error code.
101  
            @param ec Output error code.
102  
            @param bytes_out Output bytes transferred.
102  
            @param bytes_out Output bytes transferred.
103  
            @return Coroutine handle to resume immediately.
103  
            @return Coroutine handle to resume immediately.
104  
        */
104  
        */
105  
        virtual std::coroutine_handle<> write_some_at(
105  
        virtual std::coroutine_handle<> write_some_at(
106  
            std::uint64_t offset,
106  
            std::uint64_t offset,
107  
            std::coroutine_handle<> h,
107  
            std::coroutine_handle<> h,
108  
            capy::executor_ref ex,
108  
            capy::executor_ref ex,
109  
            buffer_param buf,
109  
            buffer_param buf,
110  
            std::stop_token token,
110  
            std::stop_token token,
111  
            std::error_code* ec,
111  
            std::error_code* ec,
112  
            std::size_t* bytes_out) = 0;
112  
            std::size_t* bytes_out) = 0;
113  

113  

114  
        /// Return the platform file descriptor or handle.
114  
        /// Return the platform file descriptor or handle.
115  
        virtual native_handle_type native_handle() const noexcept = 0;
115  
        virtual native_handle_type native_handle() const noexcept = 0;
116  

116  

117  
        /// Cancel pending asynchronous operations.
117  
        /// Cancel pending asynchronous operations.
118  
        virtual void cancel() noexcept = 0;
118  
        virtual void cancel() noexcept = 0;
119  

119  

120  
        /// Return the file size in bytes.
120  
        /// Return the file size in bytes.
121  
        virtual std::uint64_t size() const = 0;
121  
        virtual std::uint64_t size() const = 0;
122  

122  

123  
        /// Resize the file to @p new_size bytes.
123  
        /// Resize the file to @p new_size bytes.
124  
        virtual void resize(std::uint64_t new_size) = 0;
124  
        virtual void resize(std::uint64_t new_size) = 0;
125  

125  

126  
        /// Synchronize file data to stable storage.
126  
        /// Synchronize file data to stable storage.
127  
        virtual void sync_data() = 0;
127  
        virtual void sync_data() = 0;
128  

128  

129  
        /// Synchronize file data and metadata to stable storage.
129  
        /// Synchronize file data and metadata to stable storage.
130  
        virtual void sync_all() = 0;
130  
        virtual void sync_all() = 0;
131  

131  

132  
        /// Release ownership of the native handle.
132  
        /// Release ownership of the native handle.
133  
        virtual native_handle_type release() = 0;
133  
        virtual native_handle_type release() = 0;
134  

134  

135  
        /// Adopt an existing native handle.
135  
        /// Adopt an existing native handle.
136  
        virtual void assign(native_handle_type handle) = 0;
136  
        virtual void assign(native_handle_type handle) = 0;
137  
    };
137  
    };
138  

138  

139  
    /** Awaitable for async read-at operations. */
139  
    /** Awaitable for async read-at operations. */
140  
    template<class MutableBufferSequence>
140  
    template<class MutableBufferSequence>
141  
    struct read_some_at_awaitable
141  
    struct read_some_at_awaitable
142  
    {
142  
    {
143  
        random_access_file& f_;
143  
        random_access_file& f_;
144  
        std::uint64_t offset_;
144  
        std::uint64_t offset_;
145  
        MutableBufferSequence buffers_;
145  
        MutableBufferSequence buffers_;
146  
        std::stop_token token_;
146  
        std::stop_token token_;
147  
        mutable std::error_code ec_;
147  
        mutable std::error_code ec_;
148  
        mutable std::size_t bytes_ = 0;
148  
        mutable std::size_t bytes_ = 0;
149  

149  

150  
        read_some_at_awaitable(
150  
        read_some_at_awaitable(
151  
            random_access_file& f,
151  
            random_access_file& f,
152  
            std::uint64_t offset,
152  
            std::uint64_t offset,
153  
            MutableBufferSequence buffers)
153  
            MutableBufferSequence buffers)
154  
            noexcept(std::is_nothrow_move_constructible_v<MutableBufferSequence>)
154  
            noexcept(std::is_nothrow_move_constructible_v<MutableBufferSequence>)
155  
            : f_(f)
155  
            : f_(f)
156  
            , offset_(offset)
156  
            , offset_(offset)
157  
            , buffers_(std::move(buffers))
157  
            , buffers_(std::move(buffers))
158  
        {
158  
        {
159  
        }
159  
        }
160  

160  

161  
        bool await_ready() const noexcept
161  
        bool await_ready() const noexcept
162  
        {
162  
        {
163  
            return false;
163  
            return false;
164  
        }
164  
        }
165  

165  

166  
        capy::io_result<std::size_t> await_resume() const noexcept
166  
        capy::io_result<std::size_t> await_resume() const noexcept
167  
        {
167  
        {
168  
            return {ec_, bytes_};
168  
            return {ec_, bytes_};
169  
        }
169  
        }
170  

170  

171  
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
171  
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
172  
            -> std::coroutine_handle<>
172  
            -> std::coroutine_handle<>
173  
        {
173  
        {
174  
            token_ = env->stop_token;
174  
            token_ = env->stop_token;
175  
            return f_.get().read_some_at(
175  
            return f_.get().read_some_at(
176  
                offset_, h, env->executor, buffers_, token_, &ec_, &bytes_);
176  
                offset_, h, env->executor, buffers_, token_, &ec_, &bytes_);
177  
        }
177  
        }
178  
    };
178  
    };
179  

179  

180  
    /** Awaitable for async write-at operations. */
180  
    /** Awaitable for async write-at operations. */
181  
    template<class ConstBufferSequence>
181  
    template<class ConstBufferSequence>
182  
    struct write_some_at_awaitable
182  
    struct write_some_at_awaitable
183  
    {
183  
    {
184  
        random_access_file& f_;
184  
        random_access_file& f_;
185  
        std::uint64_t offset_;
185  
        std::uint64_t offset_;
186  
        ConstBufferSequence buffers_;
186  
        ConstBufferSequence buffers_;
187  
        std::stop_token token_;
187  
        std::stop_token token_;
188  
        mutable std::error_code ec_;
188  
        mutable std::error_code ec_;
189  
        mutable std::size_t bytes_ = 0;
189  
        mutable std::size_t bytes_ = 0;
190  

190  

191  
        write_some_at_awaitable(
191  
        write_some_at_awaitable(
192  
            random_access_file& f,
192  
            random_access_file& f,
193  
            std::uint64_t offset,
193  
            std::uint64_t offset,
194  
            ConstBufferSequence buffers)
194  
            ConstBufferSequence buffers)
195  
            noexcept(std::is_nothrow_move_constructible_v<ConstBufferSequence>)
195  
            noexcept(std::is_nothrow_move_constructible_v<ConstBufferSequence>)
196  
            : f_(f)
196  
            : f_(f)
197  
            , offset_(offset)
197  
            , offset_(offset)
198  
            , buffers_(std::move(buffers))
198  
            , buffers_(std::move(buffers))
199  
        {
199  
        {
200  
        }
200  
        }
201  

201  

202  
        bool await_ready() const noexcept
202  
        bool await_ready() const noexcept
203  
        {
203  
        {
204  
            return false;
204  
            return false;
205  
        }
205  
        }
206  

206  

207  
        capy::io_result<std::size_t> await_resume() const noexcept
207  
        capy::io_result<std::size_t> await_resume() const noexcept
208  
        {
208  
        {
209  
            return {ec_, bytes_};
209  
            return {ec_, bytes_};
210  
        }
210  
        }
211  

211  

212  
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
212  
        auto await_suspend(std::coroutine_handle<> h, capy::io_env const* env)
213  
            -> std::coroutine_handle<>
213  
            -> std::coroutine_handle<>
214  
        {
214  
        {
215  
            token_ = env->stop_token;
215  
            token_ = env->stop_token;
216  
            return f_.get().write_some_at(
216  
            return f_.get().write_some_at(
217  
                offset_, h, env->executor, buffers_, token_, &ec_, &bytes_);
217  
                offset_, h, env->executor, buffers_, token_, &ec_, &bytes_);
218  
        }
218  
        }
219  
    };
219  
    };
220  

220  

221  
public:
221  
public:
222  
    /** Destructor.
222  
    /** Destructor.
223  

223  

224  
        Closes the file if open, cancelling any pending operations.
224  
        Closes the file if open, cancelling any pending operations.
225  
    */
225  
    */
226  
    ~random_access_file() override;
226  
    ~random_access_file() override;
227  

227  

228  
    /** Construct from an execution context.
228  
    /** Construct from an execution context.
229  

229  

230  
        @param ctx The execution context that will own this file.
230  
        @param ctx The execution context that will own this file.
231  
    */
231  
    */
232  
    explicit random_access_file(capy::execution_context& ctx);
232  
    explicit random_access_file(capy::execution_context& ctx);
233  

233  

234  
    /** Construct from an executor.
234  
    /** Construct from an executor.
235  

235  

236  
        @param ex The executor whose context will own this file.
236  
        @param ex The executor whose context will own this file.
237  
    */
237  
    */
238  
    template<class Ex>
238  
    template<class Ex>
239  
        requires(!std::same_as<std::remove_cvref_t<Ex>, random_access_file>) &&
239  
        requires(!std::same_as<std::remove_cvref_t<Ex>, random_access_file>) &&
240  
        capy::Executor<Ex>
240  
        capy::Executor<Ex>
241  
    explicit random_access_file(Ex const& ex) : random_access_file(ex.context())
241  
    explicit random_access_file(Ex const& ex) : random_access_file(ex.context())
242  
    {
242  
    {
243  
    }
243  
    }
244  

244  

245  
    /** Move constructor. */
245  
    /** Move constructor. */
246  
    random_access_file(random_access_file&& other) noexcept
246  
    random_access_file(random_access_file&& other) noexcept
247  
        : io_object(std::move(other))
247  
        : io_object(std::move(other))
248  
    {
248  
    {
249  
    }
249  
    }
250  

250  

251  
    /** Move assignment operator. */
251  
    /** Move assignment operator. */
252  
    random_access_file& operator=(random_access_file&& other) noexcept
252  
    random_access_file& operator=(random_access_file&& other) noexcept
253  
    {
253  
    {
254  
        if (this != &other)
254  
        if (this != &other)
255  
        {
255  
        {
256  
            close();
256  
            close();
257  
            h_ = std::move(other.h_);
257  
            h_ = std::move(other.h_);
258  
        }
258  
        }
259  
        return *this;
259  
        return *this;
260  
    }
260  
    }
261  

261  

262  
    random_access_file(random_access_file const&)            = delete;
262  
    random_access_file(random_access_file const&)            = delete;
263  
    random_access_file& operator=(random_access_file const&) = delete;
263  
    random_access_file& operator=(random_access_file const&) = delete;
264  

264  

265  
    /** Open a file.
265  
    /** Open a file.
266  

266  

267  
        @param path The filesystem path to open.
267  
        @param path The filesystem path to open.
268  
        @param mode Bitmask of @ref file_base::flags specifying
268  
        @param mode Bitmask of @ref file_base::flags specifying
269  
            access mode and creation behavior.
269  
            access mode and creation behavior.
270  

270  

271  
        @throws std::system_error on failure.
271  
        @throws std::system_error on failure.
272  
    */
272  
    */
273  
    void open(
273  
    void open(
274  
        std::filesystem::path const& path,
274  
        std::filesystem::path const& path,
275  
        file_base::flags mode = file_base::read_only);
275  
        file_base::flags mode = file_base::read_only);
276  

276  

277  
    /** Close the file.
277  
    /** Close the file.
278  

278  

279  
        Releases file resources. Any pending operations complete
279  
        Releases file resources. Any pending operations complete
280  
        with `errc::operation_canceled`.
280  
        with `errc::operation_canceled`.
281  
    */
281  
    */
282  
    void close();
282  
    void close();
283  

283  

284  
    /** Check if the file is open. */
284  
    /** Check if the file is open. */
285  
    bool is_open() const noexcept
285  
    bool is_open() const noexcept
286  
    {
286  
    {
287  
#if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
287  
#if BOOST_COROSIO_HAS_IOCP && !defined(BOOST_COROSIO_MRDOCS)
288  
        return h_ && get().native_handle() != ~native_handle_type(0);
288  
        return h_ && get().native_handle() != ~native_handle_type(0);
289  
#else
289  
#else
290  
        return h_ && get().native_handle() >= 0;
290  
        return h_ && get().native_handle() >= 0;
291  
#endif
291  
#endif
292  
    }
292  
    }
293  

293  

294  
    /** Read data at the given offset.
294  
    /** Read data at the given offset.
295  

295  

296  
        @param offset Byte offset into the file.
296  
        @param offset Byte offset into the file.
297  
        @param buffers The buffer sequence to read into.
297  
        @param buffers The buffer sequence to read into.
298  

298  

299  
        @return An awaitable yielding `(error_code, std::size_t)`.
299  
        @return An awaitable yielding `(error_code, std::size_t)`.
300  

300  

301  
        @throws std::logic_error if the file is not open.
301  
        @throws std::logic_error if the file is not open.
302  
    */
302  
    */
303  
    template<capy::MutableBufferSequence MB>
303  
    template<capy::MutableBufferSequence MB>
304  
    auto read_some_at(std::uint64_t offset, MB const& buffers)
304  
    auto read_some_at(std::uint64_t offset, MB const& buffers)
305  
    {
305  
    {
306  
        if (!is_open())
306  
        if (!is_open())
307  
            detail::throw_logic_error("read_some_at: file not open");
307  
            detail::throw_logic_error("read_some_at: file not open");
308  
        return read_some_at_awaitable<MB>(*this, offset, buffers);
308  
        return read_some_at_awaitable<MB>(*this, offset, buffers);
309  
    }
309  
    }
310  

310  

311  
    /** Write data at the given offset.
311  
    /** Write data at the given offset.
312  

312  

313  
        @param offset Byte offset into the file.
313  
        @param offset Byte offset into the file.
314  
        @param buffers The buffer sequence to write from.
314  
        @param buffers The buffer sequence to write from.
315  

315  

316  
        @return An awaitable yielding `(error_code, std::size_t)`.
316  
        @return An awaitable yielding `(error_code, std::size_t)`.
317  

317  

318  
        @throws std::logic_error if the file is not open.
318  
        @throws std::logic_error if the file is not open.
319  
    */
319  
    */
320  
    template<capy::ConstBufferSequence CB>
320  
    template<capy::ConstBufferSequence CB>
321  
    auto write_some_at(std::uint64_t offset, CB const& buffers)
321  
    auto write_some_at(std::uint64_t offset, CB const& buffers)
322  
    {
322  
    {
323  
        if (!is_open())
323  
        if (!is_open())
324  
            detail::throw_logic_error("write_some_at: file not open");
324  
            detail::throw_logic_error("write_some_at: file not open");
325  
        return write_some_at_awaitable<CB>(*this, offset, buffers);
325  
        return write_some_at_awaitable<CB>(*this, offset, buffers);
326  
    }
326  
    }
327  

327  

328  
    /** Cancel pending asynchronous operations. */
328  
    /** Cancel pending asynchronous operations. */
329  
    void cancel();
329  
    void cancel();
330  

330  

331  
    /** Get the native file descriptor or handle. */
331  
    /** Get the native file descriptor or handle. */
332  
    native_handle_type native_handle() const noexcept;
332  
    native_handle_type native_handle() const noexcept;
333  

333  

334  
    /** Return the file size in bytes. */
334  
    /** Return the file size in bytes. */
335  
    std::uint64_t size() const;
335  
    std::uint64_t size() const;
336  

336  

337  
    /** Resize the file. */
337  
    /** Resize the file. */
338  
    void resize(std::uint64_t new_size);
338  
    void resize(std::uint64_t new_size);
339  

339  

340  
    /** Synchronize file data to stable storage. */
340  
    /** Synchronize file data to stable storage. */
341  
    void sync_data();
341  
    void sync_data();
342  

342  

343  
    /** Synchronize file data and metadata to stable storage. */
343  
    /** Synchronize file data and metadata to stable storage. */
344  
    void sync_all();
344  
    void sync_all();
345  

345  

346  
    /** Release ownership of the native handle.
346  
    /** Release ownership of the native handle.
347  

347  

348  
        The file object becomes not-open. The caller is
348  
        The file object becomes not-open. The caller is
349  
        responsible for closing the returned handle.
349  
        responsible for closing the returned handle.
350  

350  

351  
        @return The native file descriptor or handle.
351  
        @return The native file descriptor or handle.
352  
    */
352  
    */
353  
    native_handle_type release();
353  
    native_handle_type release();
354  

354  

355  
    /** Adopt an existing native handle.
355  
    /** Adopt an existing native handle.
356  

356  

357  
        Closes any currently open file before adopting.
357  
        Closes any currently open file before adopting.
358  
        The file object takes ownership of the handle.
358  
        The file object takes ownership of the handle.
359  

359  

360  
        @param handle The native file descriptor or handle.
360  
        @param handle The native file descriptor or handle.
361  
    */
361  
    */
362  
    void assign(native_handle_type handle);
362  
    void assign(native_handle_type handle);
363  

363  

364  
private:
364  
private:
365  
    inline implementation& get() const noexcept
365  
    inline implementation& get() const noexcept
366  
    {
366  
    {
367  
        return *static_cast<implementation*>(h_.get());
367  
        return *static_cast<implementation*>(h_.get());
368  
    }
368  
    }
369  
};
369  
};
370  

370  

371  
} // namespace boost::corosio
371  
} // namespace boost::corosio
372  

372  

373  
#endif // BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP
373  
#endif // BOOST_COROSIO_RANDOM_ACCESS_FILE_HPP