1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
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/capy
7  
// Official repository: https://github.com/cppalliance/capy
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_CAPY_EX_IMMEDIATE_HPP
10  
#ifndef BOOST_CAPY_EX_IMMEDIATE_HPP
11  
#define BOOST_CAPY_EX_IMMEDIATE_HPP
11  
#define BOOST_CAPY_EX_IMMEDIATE_HPP
12  

12  

13  
#include <boost/capy/detail/config.hpp>
13  
#include <boost/capy/detail/config.hpp>
14  
#include <boost/capy/ex/executor_ref.hpp>
14  
#include <boost/capy/ex/executor_ref.hpp>
15  
#include <boost/capy/io_result.hpp>
15  
#include <boost/capy/io_result.hpp>
16  

16  

17  
#include <coroutine>
17  
#include <coroutine>
18  
#include <stop_token>
18  
#include <stop_token>
19  
#include <utility>
19  
#include <utility>
20  

20  

21  
namespace boost {
21  
namespace boost {
22  
namespace capy {
22  
namespace capy {
23  

23  

24  
/** An awaitable that completes immediately with a value.
24  
/** An awaitable that completes immediately with a value.
25  

25  

26  
    This awaitable wraps a synchronous result so it can be used in
26  
    This awaitable wraps a synchronous result so it can be used in
27  
    contexts that require an awaitable type. It never suspends - 
27  
    contexts that require an awaitable type. It never suspends - 
28  
    `await_ready()` always returns `true`, so the coroutine machinery
28  
    `await_ready()` always returns `true`, so the coroutine machinery
29  
    is optimized away by the compiler.
29  
    is optimized away by the compiler.
30  

30  

31  
    Use this to adapt synchronous operations to satisfy async concepts
31  
    Use this to adapt synchronous operations to satisfy async concepts
32  
    like @ref IoAwaitable without the overhead of a full coroutine frame.
32  
    like @ref IoAwaitable without the overhead of a full coroutine frame.
33  

33  

34  
    @tparam T The result type to wrap.
34  
    @tparam T The result type to wrap.
35  

35  

36  
    @par Example
36  
    @par Example
37  
    @code
37  
    @code
38  
    // Wrap a sync operation as an awaitable
38  
    // Wrap a sync operation as an awaitable
39  
    immediate<int> get_value()
39  
    immediate<int> get_value()
40  
    {
40  
    {
41  
        return {42};
41  
        return {42};
42  
    }
42  
    }
43  

43  

44  
    task<void> example()
44  
    task<void> example()
45  
    {
45  
    {
46  
        int x = co_await get_value();  // No suspension, returns 42
46  
        int x = co_await get_value();  // No suspension, returns 42
47  
    }
47  
    }
48  
    @endcode
48  
    @endcode
49  

49  

50  
    @par Satisfying WriteSink with sync operations
50  
    @par Satisfying WriteSink with sync operations
51  
    @code
51  
    @code
52  
    struct my_sync_sink
52  
    struct my_sync_sink
53  
    {
53  
    {
54  
        template<ConstBufferSequence CB>
54  
        template<ConstBufferSequence CB>
55  
        immediate<io_result<std::size_t>>
55  
        immediate<io_result<std::size_t>>
56  
        write(CB buffers)
56  
        write(CB buffers)
57  
        {
57  
        {
58  
            auto n = process_sync(buffers);
58  
            auto n = process_sync(buffers);
59  
            return {{{}, n}};
59  
            return {{{}, n}};
60  
        }
60  
        }
61  

61  

62  
        immediate<io_result<>>
62  
        immediate<io_result<>>
63  
        write_eof()
63  
        write_eof()
64  
        {
64  
        {
65  
            return {{}};
65  
            return {{}};
66  
        }
66  
        }
67  
    };
67  
    };
68  
    @endcode
68  
    @endcode
69  

69  

70  
    @see ready, io_result
70  
    @see ready, io_result
71  
*/
71  
*/
72  
template<class T>
72  
template<class T>
73  
struct immediate
73  
struct immediate
74  
{
74  
{
75  
    /** The wrapped value. */
75  
    /** The wrapped value. */
76  
    T value_;
76  
    T value_;
77  

77  

78  
    /** Always returns true - this awaitable never suspends. */
78  
    /** Always returns true - this awaitable never suspends. */
79  
    constexpr bool
79  
    constexpr bool
80  
    await_ready() const noexcept
80  
    await_ready() const noexcept
81  
    {
81  
    {
82  
        return true;
82  
        return true;
83  
    }
83  
    }
84  

84  

85  
    /** Never called since await_ready() returns true. */
85  
    /** Never called since await_ready() returns true. */
86  
    constexpr void
86  
    constexpr void
87  
    await_suspend(std::coroutine_handle<>) const noexcept
87  
    await_suspend(std::coroutine_handle<>) const noexcept
88  
    {
88  
    {
89  
    }
89  
    }
90  

90  

91  
    /** IoAwaitable protocol overload.
91  
    /** IoAwaitable protocol overload.
92  

92  

93  
        This overload allows `immediate` to satisfy the @ref IoAwaitable
93  
        This overload allows `immediate` to satisfy the @ref IoAwaitable
94  
        concept. Since the result is already available, the executor and
94  
        concept. Since the result is already available, the executor and
95  
        stop token are unused.
95  
        stop token are unused.
96  

96  

97  
        @param h The coroutine handle (unused).
97  
        @param h The coroutine handle (unused).
98  
        @param ex The executor (unused).
98  
        @param ex The executor (unused).
99  
        @param token The stop token (unused).
99  
        @param token The stop token (unused).
100  

100  

101  
        @return `std::noop_coroutine()` to indicate no suspension.
101  
        @return `std::noop_coroutine()` to indicate no suspension.
102  
    */
102  
    */
103  
    std::coroutine_handle<>
103  
    std::coroutine_handle<>
104  
    await_suspend(
104  
    await_suspend(
105  
        std::coroutine_handle<> h,
105  
        std::coroutine_handle<> h,
106  
        executor_ref ex,
106  
        executor_ref ex,
107  
        std::stop_token token = {}) const noexcept
107  
        std::stop_token token = {}) const noexcept
108  
    {
108  
    {
109  
        (void)h;
109  
        (void)h;
110  
        (void)ex;
110  
        (void)ex;
111  
        (void)token;
111  
        (void)token;
112  
        return std::noop_coroutine();
112  
        return std::noop_coroutine();
113  
    }
113  
    }
114  

114  

115  
    /** Returns the wrapped value.
115  
    /** Returns the wrapped value.
116  

116  

117  
        @return The stored value, moved if non-const.
117  
        @return The stored value, moved if non-const.
118  
    */
118  
    */
119  
    constexpr T
119  
    constexpr T
120  
    await_resume() noexcept
120  
    await_resume() noexcept
121  
    {
121  
    {
122  
        return std::move(value_);
122  
        return std::move(value_);
123  
    }
123  
    }
124  

124  

125  
    /** Returns the wrapped value (const overload). */
125  
    /** Returns the wrapped value (const overload). */
126  
    constexpr T const&
126  
    constexpr T const&
127  
    await_resume() const noexcept
127  
    await_resume() const noexcept
128  
    {
128  
    {
129  
        return value_;
129  
        return value_;
130  
    }
130  
    }
131  
};
131  
};
132  

132  

133  
//----------------------------------------------------------
133  
//----------------------------------------------------------
134  

134  

135  
/** Create an immediate awaitable for a successful io_result.
135  
/** Create an immediate awaitable for a successful io_result.
136  

136  

137  
    This helper creates an @ref immediate wrapping an @ref io_result
137  
    This helper creates an @ref immediate wrapping an @ref io_result
138  
    with no error and the provided values.
138  
    with no error and the provided values.
139  

139  

140  
    @par Example
140  
    @par Example
141  
    @code
141  
    @code
142  
    immediate<io_result<std::size_t>>
142  
    immediate<io_result<std::size_t>>
143  
    write(const_buffer buf)
143  
    write(const_buffer buf)
144  
    {
144  
    {
145  
        auto n = write_sync(buf);
145  
        auto n = write_sync(buf);
146  
        return ready(n);  // success with n bytes
146  
        return ready(n);  // success with n bytes
147  
    }
147  
    }
148  

148  

149  
    immediate<io_result<>>
149  
    immediate<io_result<>>
150  
    connect()
150  
    connect()
151  
    {
151  
    {
152  
        connect_sync();
152  
        connect_sync();
153  
        return ready();  // void success
153  
        return ready();  // void success
154  
    }
154  
    }
155  
    @endcode
155  
    @endcode
156  

156  

157  
    @return An immediate awaitable containing a successful io_result.
157  
    @return An immediate awaitable containing a successful io_result.
158  

158  

159  
    @see immediate, io_result
159  
    @see immediate, io_result
160  
*/
160  
*/
161  
inline
161  
inline
162  
immediate<io_result<>>
162  
immediate<io_result<>>
163  
ready() noexcept
163  
ready() noexcept
164  
{
164  
{
165  
    return {{}};
165  
    return {{}};
166  
}
166  
}
167  

167  

168  
/** Create an immediate awaitable for a successful io_result with one value.
168  
/** Create an immediate awaitable for a successful io_result with one value.
169  

169  

170  
    @param t1 The result value.
170  
    @param t1 The result value.
171  

171  

172  
    @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
172  
    @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
173  
*/
173  
*/
174  
template<class T1>
174  
template<class T1>
175  
immediate<io_result<T1>>
175  
immediate<io_result<T1>>
176  
ready(T1 t1)
176  
ready(T1 t1)
177  
{
177  
{
178  
    return {{{}, std::move(t1)}};
178  
    return {{{}, std::move(t1)}};
179  
}
179  
}
180  

180  

181  
/** Create an immediate awaitable for a successful io_result with two values.
181  
/** Create an immediate awaitable for a successful io_result with two values.
182  

182  

183  
    @param t1 The first result value.
183  
    @param t1 The first result value.
184  
    @param t2 The second result value.
184  
    @param t2 The second result value.
185  

185  

186  
    @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
186  
    @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
187  
*/
187  
*/
188  
template<class T1, class T2>
188  
template<class T1, class T2>
189  
immediate<io_result<T1, T2>>
189  
immediate<io_result<T1, T2>>
190  
ready(T1 t1, T2 t2)
190  
ready(T1 t1, T2 t2)
191  
{
191  
{
192  
    return {{{}, std::move(t1), std::move(t2)}};
192  
    return {{{}, std::move(t1), std::move(t2)}};
193  
}
193  
}
194  

194  

195  
/** Create an immediate awaitable for a successful io_result with three values.
195  
/** Create an immediate awaitable for a successful io_result with three values.
196  

196  

197  
    @param t1 The first result value.
197  
    @param t1 The first result value.
198  
    @param t2 The second result value.
198  
    @param t2 The second result value.
199  
    @param t3 The third result value.
199  
    @param t3 The third result value.
200  

200  

201  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
201  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
202  
*/
202  
*/
203  
template<class T1, class T2, class T3>
203  
template<class T1, class T2, class T3>
204  
immediate<io_result<T1, T2, T3>>
204  
immediate<io_result<T1, T2, T3>>
205  
ready(T1 t1, T2 t2, T3 t3)
205  
ready(T1 t1, T2 t2, T3 t3)
206  
{
206  
{
207  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
207  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
208  
}
208  
}
209  

209  

210  
//----------------------------------------------------------
210  
//----------------------------------------------------------
211  

211  

212  
/** Create an immediate awaitable for a failed io_result.
212  
/** Create an immediate awaitable for a failed io_result.
213  

213  

214  
    This helper creates an @ref immediate wrapping an @ref io_result
214  
    This helper creates an @ref immediate wrapping an @ref io_result
215  
    with an error code.
215  
    with an error code.
216  

216  

217  
    @par Example
217  
    @par Example
218  
    @code
218  
    @code
219  
    immediate<io_result<std::size_t>>
219  
    immediate<io_result<std::size_t>>
220  
    write(const_buffer buf)
220  
    write(const_buffer buf)
221  
    {
221  
    {
222  
        auto ec = write_sync(buf);
222  
        auto ec = write_sync(buf);
223  
        if(ec)
223  
        if(ec)
224  
            return ready(ec, std::size_t{0});
224  
            return ready(ec, std::size_t{0});
225  
        return ready(buffer_size(buf));
225  
        return ready(buffer_size(buf));
226  
    }
226  
    }
227  
    @endcode
227  
    @endcode
228  

228  

229  
    @param ec The error code.
229  
    @param ec The error code.
230  

230  

231  
    @return An immediate awaitable containing a failed io_result.
231  
    @return An immediate awaitable containing a failed io_result.
232  

232  

233  
    @see immediate, io_result
233  
    @see immediate, io_result
234  
*/
234  
*/
235  
inline
235  
inline
236  
immediate<io_result<>>
236  
immediate<io_result<>>
237  
ready(std::error_code ec) noexcept
237  
ready(std::error_code ec) noexcept
238  
{
238  
{
239  
    return {{ec}};
239  
    return {{ec}};
240  
}
240  
}
241  

241  

242  
/** Create an immediate awaitable for an io_result with error and one value.
242  
/** Create an immediate awaitable for an io_result with error and one value.
243  

243  

244  
    @param ec The error code.
244  
    @param ec The error code.
245  
    @param t1 The result value.
245  
    @param t1 The result value.
246  

246  

247  
    @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
247  
    @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
248  
*/
248  
*/
249  
template<class T1>
249  
template<class T1>
250  
immediate<io_result<T1>>
250  
immediate<io_result<T1>>
251  
ready(std::error_code ec, T1 t1)
251  
ready(std::error_code ec, T1 t1)
252  
{
252  
{
253  
    return {{ec, std::move(t1)}};
253  
    return {{ec, std::move(t1)}};
254  
}
254  
}
255  

255  

256  
/** Create an immediate awaitable for an io_result with error and two values.
256  
/** Create an immediate awaitable for an io_result with error and two values.
257  

257  

258  
    @param ec The error code.
258  
    @param ec The error code.
259  
    @param t1 The first result value.
259  
    @param t1 The first result value.
260  
    @param t2 The second result value.
260  
    @param t2 The second result value.
261  

261  

262  
    @return An immediate awaitable containing `io_result<T1,T2>{ec, t1, t2}`.
262  
    @return An immediate awaitable containing `io_result<T1,T2>{ec, t1, t2}`.
263  
*/
263  
*/
264  
template<class T1, class T2>
264  
template<class T1, class T2>
265  
immediate<io_result<T1, T2>>
265  
immediate<io_result<T1, T2>>
266  
ready(std::error_code ec, T1 t1, T2 t2)
266  
ready(std::error_code ec, T1 t1, T2 t2)
267  
{
267  
{
268  
    return {{ec, std::move(t1), std::move(t2)}};
268  
    return {{ec, std::move(t1), std::move(t2)}};
269  
}
269  
}
270  

270  

271  
/** Create an immediate awaitable for an io_result with error and three values.
271  
/** Create an immediate awaitable for an io_result with error and three values.
272  

272  

273  
    @param ec The error code.
273  
    @param ec The error code.
274  
    @param t1 The first result value.
274  
    @param t1 The first result value.
275  
    @param t2 The second result value.
275  
    @param t2 The second result value.
276  
    @param t3 The third result value.
276  
    @param t3 The third result value.
277  

277  

278  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
278  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
279  
*/
279  
*/
280  
template<class T1, class T2, class T3>
280  
template<class T1, class T2, class T3>
281  
immediate<io_result<T1, T2, T3>>
281  
immediate<io_result<T1, T2, T3>>
282  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
282  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
283  
{
283  
{
284  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
284  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
285  
}
285  
}
286  

286  

287  
} // namespace capy
287  
} // namespace capy
288  
} // namespace boost
288  
} // namespace boost
289  

289  

290  
#endif
290  
#endif