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 -
//----------------------------------------------------------
 
124 -

 
125  

123  

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

125  

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

128  

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

137  

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

145  

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

147  

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

156  

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

158  

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

160  

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

169  

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

171  

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

174  

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

183  

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

185  

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

189  

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

 
200 -
//----------------------------------------------------------
 
201  
}
197  
}
202  

198  

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

200  

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

203  

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

215  

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

217  

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

219  

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

228  

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

230  

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

233  

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

242  

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

244  

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

248  

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

257  

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

259  

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

264  

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

273  

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

276  

281  
#endif
277  
#endif