1  
//
1  
//
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2025 Vinnie Falco (vinnie.falco@gmail.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/io_env.hpp>
14  
#include <boost/capy/ex/io_env.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  
    /** IoAwaitable protocol overload.
85  
    /** IoAwaitable protocol overload.
86  

86  

87  
        This overload allows `immediate` to satisfy the @ref IoAwaitable
87  
        This overload allows `immediate` to satisfy the @ref IoAwaitable
88  
        concept. Since the result is already available, the environment
88  
        concept. Since the result is already available, the environment
89  
        is unused.
89  
        is unused.
90  

90  

91  
        @param h The coroutine handle (unused).
91  
        @param h The coroutine handle (unused).
92  
        @param env The execution environment (unused).
92  
        @param env The execution environment (unused).
93  

93  

94  
        @return `std::noop_coroutine()` to indicate no suspension.
94  
        @return `std::noop_coroutine()` to indicate no suspension.
95  
    */
95  
    */
96  
    std::coroutine_handle<>
96  
    std::coroutine_handle<>
97  
    await_suspend(
97  
    await_suspend(
98  
        std::coroutine_handle<> h,
98  
        std::coroutine_handle<> h,
99  
        io_env const* env) const noexcept
99  
        io_env const* env) const noexcept
100  
    {
100  
    {
101  
        (void)h;
101  
        (void)h;
102  
        (void)env;
102  
        (void)env;
103  
        return std::noop_coroutine();
103  
        return std::noop_coroutine();
104  
    }
104  
    }
105  

105  

106  
    /** Returns the wrapped value.
106  
    /** Returns the wrapped value.
107  

107  

108  
        @return The stored value, moved if non-const.
108  
        @return The stored value, moved if non-const.
109  
    */
109  
    */
110  
    constexpr T
110  
    constexpr T
111  
    await_resume() noexcept
111  
    await_resume() noexcept
112  
    {
112  
    {
113  
        return std::move(value_);
113  
        return std::move(value_);
114  
    }
114  
    }
115  

115  

116  
    /** Returns the wrapped value (const overload). */
116  
    /** Returns the wrapped value (const overload). */
117  
    constexpr T const&
117  
    constexpr T const&
118  
    await_resume() const noexcept
118  
    await_resume() const noexcept
119  
    {
119  
    {
120  
        return value_;
120  
        return value_;
121  
    }
121  
    }
122  
};
122  
};
123  

123  

 
124 +
//----------------------------------------------------------
 
125 +

124  
/** Create an immediate awaitable for a successful io_result.
126  
/** Create an immediate awaitable for a successful io_result.
125  

127  

126  
    This helper creates an @ref immediate wrapping an @ref io_result
128  
    This helper creates an @ref immediate wrapping an @ref io_result
127  
    with no error and the provided values.
129  
    with no error and the provided values.
128  

130  

129  
    @par Example
131  
    @par Example
130  
    @code
132  
    @code
131  
    immediate<io_result<std::size_t>>
133  
    immediate<io_result<std::size_t>>
132  
    write(const_buffer buf)
134  
    write(const_buffer buf)
133  
    {
135  
    {
134  
        auto n = write_sync(buf);
136  
        auto n = write_sync(buf);
135  
        return ready(n);  // success with n bytes
137  
        return ready(n);  // success with n bytes
136  
    }
138  
    }
137  

139  

138  
    immediate<io_result<>>
140  
    immediate<io_result<>>
139  
    connect()
141  
    connect()
140  
    {
142  
    {
141  
        connect_sync();
143  
        connect_sync();
142  
        return ready();  // void success
144  
        return ready();  // void success
143  
    }
145  
    }
144  
    @endcode
146  
    @endcode
145  

147  

146  
    @return An immediate awaitable containing a successful io_result.
148  
    @return An immediate awaitable containing a successful io_result.
147  

149  

148  
    @see immediate, io_result
150  
    @see immediate, io_result
149  
*/
151  
*/
150  
inline
152  
inline
151  
immediate<io_result<>>
153  
immediate<io_result<>>
152  
ready() noexcept
154  
ready() noexcept
153  
{
155  
{
154  
    return {{}};
156  
    return {{}};
155  
}
157  
}
156  

158  

157  
/** Create an immediate awaitable for a successful io_result with one value.
159  
/** Create an immediate awaitable for a successful io_result with one value.
158  

160  

159  
    @param t1 The result value.
161  
    @param t1 The result value.
160  

162  

161  
    @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
163  
    @return An immediate awaitable containing `io_result<T1>{{}, t1}`.
162  
*/
164  
*/
163  
template<class T1>
165  
template<class T1>
164  
immediate<io_result<T1>>
166  
immediate<io_result<T1>>
165  
ready(T1 t1)
167  
ready(T1 t1)
166  
{
168  
{
167  
    return {{{}, std::move(t1)}};
169  
    return {{{}, std::move(t1)}};
168  
}
170  
}
169  

171  

170  
/** Create an immediate awaitable for a successful io_result with two values.
172  
/** Create an immediate awaitable for a successful io_result with two values.
171  

173  

172  
    @param t1 The first result value.
174  
    @param t1 The first result value.
173  
    @param t2 The second result value.
175  
    @param t2 The second result value.
174  

176  

175  
    @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
177  
    @return An immediate awaitable containing `io_result<T1,T2>{{}, t1, t2}`.
176  
*/
178  
*/
177  
template<class T1, class T2>
179  
template<class T1, class T2>
178  
immediate<io_result<T1, T2>>
180  
immediate<io_result<T1, T2>>
179  
ready(T1 t1, T2 t2)
181  
ready(T1 t1, T2 t2)
180  
{
182  
{
181  
    return {{{}, std::move(t1), std::move(t2)}};
183  
    return {{{}, std::move(t1), std::move(t2)}};
182  
}
184  
}
183  

185  

184  
/** Create an immediate awaitable for a successful io_result with three values.
186  
/** Create an immediate awaitable for a successful io_result with three values.
185  

187  

186  
    @param t1 The first result value.
188  
    @param t1 The first result value.
187  
    @param t2 The second result value.
189  
    @param t2 The second result value.
188  
    @param t3 The third result value.
190  
    @param t3 The third result value.
189  

191  

190  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
192  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{{}, t1, t2, t3}`.
191  
*/
193  
*/
192  
template<class T1, class T2, class T3>
194  
template<class T1, class T2, class T3>
193  
immediate<io_result<T1, T2, T3>>
195  
immediate<io_result<T1, T2, T3>>
194  
ready(T1 t1, T2 t2, T3 t3)
196  
ready(T1 t1, T2 t2, T3 t3)
195  
{
197  
{
196  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
198  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
197  
}
199  
}
 
200 +

 
201 +
//----------------------------------------------------------
198  

202  

199  
/** Create an immediate awaitable for a failed io_result.
203  
/** Create an immediate awaitable for a failed io_result.
200  

204  

201  
    This helper creates an @ref immediate wrapping an @ref io_result
205  
    This helper creates an @ref immediate wrapping an @ref io_result
202  
    with an error code.
206  
    with an error code.
203  

207  

204  
    @par Example
208  
    @par Example
205  
    @code
209  
    @code
206  
    immediate<io_result<std::size_t>>
210  
    immediate<io_result<std::size_t>>
207  
    write(const_buffer buf)
211  
    write(const_buffer buf)
208  
    {
212  
    {
209  
        auto ec = write_sync(buf);
213  
        auto ec = write_sync(buf);
210  
        if(ec)
214  
        if(ec)
211  
            return ready(ec, std::size_t{0});
215  
            return ready(ec, std::size_t{0});
212  
        return ready(buffer_size(buf));
216  
        return ready(buffer_size(buf));
213  
    }
217  
    }
214  
    @endcode
218  
    @endcode
215  

219  

216  
    @param ec The error code.
220  
    @param ec The error code.
217  

221  

218  
    @return An immediate awaitable containing a failed io_result.
222  
    @return An immediate awaitable containing a failed io_result.
219  

223  

220  
    @see immediate, io_result
224  
    @see immediate, io_result
221  
*/
225  
*/
222  
inline
226  
inline
223  
immediate<io_result<>>
227  
immediate<io_result<>>
224  
ready(std::error_code ec) noexcept
228  
ready(std::error_code ec) noexcept
225  
{
229  
{
226  
    return {{ec}};
230  
    return {{ec}};
227  
}
231  
}
228  

232  

229  
/** Create an immediate awaitable for an io_result with error and one value.
233  
/** Create an immediate awaitable for an io_result with error and one value.
230  

234  

231  
    @param ec The error code.
235  
    @param ec The error code.
232  
    @param t1 The result value.
236  
    @param t1 The result value.
233  

237  

234  
    @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
238  
    @return An immediate awaitable containing `io_result<T1>{ec, t1}`.
235  
*/
239  
*/
236  
template<class T1>
240  
template<class T1>
237  
immediate<io_result<T1>>
241  
immediate<io_result<T1>>
238  
ready(std::error_code ec, T1 t1)
242  
ready(std::error_code ec, T1 t1)
239  
{
243  
{
240  
    return {{ec, std::move(t1)}};
244  
    return {{ec, std::move(t1)}};
241  
}
245  
}
242  

246  

243  
/** Create an immediate awaitable for an io_result with error and two values.
247  
/** Create an immediate awaitable for an io_result with error and two values.
244  

248  

245  
    @param ec The error code.
249  
    @param ec The error code.
246  
    @param t1 The first result value.
250  
    @param t1 The first result value.
247  
    @param t2 The second result value.
251  
    @param t2 The second result value.
248  

252  

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

261  

258  
/** Create an immediate awaitable for an io_result with error and three values.
262  
/** Create an immediate awaitable for an io_result with error and three values.
259  

263  

260  
    @param ec The error code.
264  
    @param ec The error code.
261  
    @param t1 The first result value.
265  
    @param t1 The first result value.
262  
    @param t2 The second result value.
266  
    @param t2 The second result value.
263  
    @param t3 The third result value.
267  
    @param t3 The third result value.
264  

268  

265  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
269  
    @return An immediate awaitable containing `io_result<T1,T2,T3>{ec, t1, t2, t3}`.
266  
*/
270  
*/
267  
template<class T1, class T2, class T3>
271  
template<class T1, class T2, class T3>
268  
immediate<io_result<T1, T2, T3>>
272  
immediate<io_result<T1, T2, T3>>
269  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
273  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
270  
{
274  
{
271  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
275  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
272  
}
276  
}
273  

277  

274  
} // namespace capy
278  
} // namespace capy
275  
} // namespace boost
279  
} // namespace boost
276  

280  

277  
#endif
281  
#endif