@@ -64,6 +64,12 @@ struct Invoker {
64
64
return f (::sus::forward<Args>(args)...);
65
65
}
66
66
67
+ template <class R , class ... Args>
68
+ static R object_call_once (const union Storage& s, Args... args) {
69
+ F& f = *static_cast <F*>(s.object );
70
+ return ::sus::move (f)(::sus::forward<Args>(args)...);
71
+ }
72
+
67
73
template <class R , class ... Args>
68
74
static R fnptr_call_const (const union Storage& s, Args... args) {
69
75
const F f = reinterpret_cast <const F>(s.fnptr );
@@ -95,6 +101,12 @@ concept ConvertsToFunctionPointer = requires(F f) {
95
101
{ +f } -> IsFunctionPointer;
96
102
};
97
103
104
+ template <class F , class R , class ... Args>
105
+ concept CallableOnceMut =
106
+ !FunctionPointer<F, R, Args...> && requires (F && f, Args... args) {
107
+ { ::sus::move (f)(args...) } -> std::convertible_to<R>;
108
+ };
109
+
98
110
template <class F , class R , class ... Args>
99
111
concept CallableMut =
100
112
!FunctionPointer<F, R, Args...> && requires (F & f, Args... args) {
@@ -434,23 +446,23 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
434
446
// / Construction from a non-capturing lambda.
435
447
// /
436
448
// / #[doc.overloads=ctor.lambda]
437
- template <__private::CallableMut <R, CallArgs...> F>
449
+ template <__private::CallableOnceMut <R, CallArgs...> F>
438
450
requires (__private::ConvertsToFunctionPointer<F>)
439
451
constexpr FnOnce (F&& object sus_lifetimebound) noexcept {
440
452
storage_.object = ::sus::mem::addressof (object);
441
453
invoke_ = &__private::Invoker<
442
- std::remove_reference_t <F>>::template object_call_mut <R, CallArgs...>;
454
+ std::remove_reference_t <F>>::template object_call_once <R, CallArgs...>;
443
455
}
444
456
445
457
// / Construction from a capturing lambda or other callable object.
446
458
// /
447
459
// / #[doc.overloads=ctor.capturelambda]
448
- template <__private::CallableMut <R, CallArgs...> F>
460
+ template <__private::CallableOnceMut <R, CallArgs...> F>
449
461
requires (!__private::ConvertsToFunctionPointer<F>)
450
462
constexpr FnOnce (F&& object sus_lifetimebound) noexcept {
451
463
storage_.object = ::sus::mem::addressof (object);
452
464
invoke_ = &__private::Invoker<
453
- std::remove_reference_t <F>>::template object_call_mut <R, CallArgs...>;
465
+ std::remove_reference_t <F>>::template object_call_once <R, CallArgs...>;
454
466
}
455
467
456
468
// / Construction from FnMut.
@@ -489,10 +501,51 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
489
501
return *this ;
490
502
}
491
503
504
+ // / A split FnOnce object, which can be used to construct other FnOnce
505
+ // / objects, but enforces that only one of them is called.
506
+ // /
507
+ // / The Split object must not outlive the FnOnce it's constructed from or
508
+ // / Undefined Behaviour results.
509
+ class Split {
510
+ public:
511
+ Split (FnOnce& fn sus_lifetimebound) : fn_(fn) {}
512
+
513
+ // Not Copy or Move, only used to construct FnOnce objects, which are
514
+ // constructible from this type.
515
+ Split (Split&&) = delete ;
516
+ Split& operator =(Split&&) = delete ;
517
+
518
+ // / Runs the underlying `FnOnce`. The `FnOnce` may only be called a single
519
+ // / time and will panic on the second call.
520
+ R operator ()(CallArgs... args) && {
521
+ return ::sus::move (fn_)(::sus::forward<CallArgs>(args)...);
522
+ }
523
+
524
+ private:
525
+ FnOnce& fn_;
526
+ };
527
+
492
528
// Not copyable.
493
529
FnOnce (const FnOnce&) noexcept = delete ;
494
530
FnOnce& operator =(const FnOnce&) noexcept = delete ;
495
531
532
+ // / A `FnOnce` can be split into any number of `FnOnce` objects, while
533
+ // / enforcing that the underlying function is only called a single time.
534
+ // /
535
+ // / This method returns a type that can convert into any number of `FnOnce`
536
+ // / objects. If two of them are called, the second call will panic.
537
+ // /
538
+ // / The returned object must not outlive the `FnOnce` object it is constructed
539
+ // / from, this is normally enforced by only using the `FnOnce` type in
540
+ // / function parameters, which ensures it lives for the entire function body,
541
+ // / and calling `split()` to construct temporary objects for passing to other
542
+ // / functions that receive a `FnOnce`. The result of `split()` should never be
543
+ // / stored as a member of an object.
544
+ // /
545
+ // / Only callable on an lvalue FnOnce (typically written as a function
546
+ // / parameter) as an rvalue can be simply passed along without splitting.
547
+ constexpr Split split () & noexcept sus_lifetimebound { return Split (*this ); }
548
+
496
549
// / Runs and consumes the closure.
497
550
inline R operator ()(CallArgs... args) && {
498
551
::sus::check (invoke_); // Catch use-after-move.
@@ -509,7 +562,7 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
509
562
__private::FunctionPointer<R, CallArgs...> auto ptr) noexcept {
510
563
return FnOnce (ptr);
511
564
}
512
- template <__private::CallableMut <R, CallArgs...> F>
565
+ template <__private::CallableOnceMut <R, CallArgs...> F>
513
566
constexpr static auto from (F&& object sus_lifetimebound) noexcept {
514
567
return FnOnce (::sus::forward<F>(object));
515
568
}
0 commit comments