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

125  

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

127  

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

130  

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

139  

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

147  

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

149  

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

158  

159  
/** 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.
160  

160  

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

162  

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

171  

172  
/** 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.
173  

173  

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

176  

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

185  

186  
/** 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.
187  

187  

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

191  

192  
    @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}`.
193  
*/
193  
*/
194  
template<class T1, class T2, class T3>
194  
template<class T1, class T2, class T3>
195  
immediate<io_result<T1, T2, T3>>
195  
immediate<io_result<T1, T2, T3>>
196  
ready(T1 t1, T2 t2, T3 t3)
196  
ready(T1 t1, T2 t2, T3 t3)
197  
{
197  
{
198  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
198  
    return {{{}, std::move(t1), std::move(t2), std::move(t3)}};
199  
}
199  
}
200  

200  

201  
//----------------------------------------------------------
201  
//----------------------------------------------------------
202  

202  

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

204  

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

207  

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

219  

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

221  

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

223  

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

232  

233  
/** 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.
234  

234  

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

237  

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

246  

247  
/** 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.
248  

248  

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

252  

253  
    @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}`.
254  
*/
254  
*/
255  
template<class T1, class T2>
255  
template<class T1, class T2>
256  
immediate<io_result<T1, T2>>
256  
immediate<io_result<T1, T2>>
257  
ready(std::error_code ec, T1 t1, T2 t2)
257  
ready(std::error_code ec, T1 t1, T2 t2)
258  
{
258  
{
259  
    return {{ec, std::move(t1), std::move(t2)}};
259  
    return {{ec, std::move(t1), std::move(t2)}};
260  
}
260  
}
261  

261  

262  
/** 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.
263  

263  

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

268  

269  
    @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}`.
270  
*/
270  
*/
271  
template<class T1, class T2, class T3>
271  
template<class T1, class T2, class T3>
272  
immediate<io_result<T1, T2, T3>>
272  
immediate<io_result<T1, T2, T3>>
273  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
273  
ready(std::error_code ec, T1 t1, T2 t2, T3 t3)
274  
{
274  
{
275  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
275  
    return {{ec, std::move(t1), std::move(t2), std::move(t3)}};
276  
}
276  
}
277  

277  

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

280  

281  
#endif
281  
#endif