@@ -410,6 +410,172 @@ class [[nodiscard("unnecessary construction")]] AwaitableScalar
410
410
std::variant<T, std::future<T>, std::shared_ptr<const response::Value>> _value;
411
411
};
412
412
413
+ template <typename T>
414
+ struct is_optional : std::false_type
415
+ {
416
+ };
417
+
418
+ template <typename T>
419
+ struct is_optional <std::optional<T>> : std::true_type
420
+ {
421
+ };
422
+
423
+ template <typename T>
424
+ struct is_vector : std::false_type
425
+ {
426
+ };
427
+
428
+ template <typename T>
429
+ struct is_vector <std::vector<T>> : std::true_type
430
+ {
431
+ };
432
+
433
+ template <typename T>
434
+ struct is_future : std::false_type
435
+ {
436
+ };
437
+
438
+ template <typename T>
439
+ struct is_future <std::future<T>> : std::true_type
440
+ {
441
+ };
442
+
443
+ template <typename T>
444
+ struct type_tag
445
+ {
446
+ using type = T;
447
+ };
448
+
449
+ template <typename K, typename V>
450
+ struct pair
451
+ {
452
+ using first_type = K;
453
+ using second_type = V;
454
+ };
455
+
456
+ template <typename Pair>
457
+ struct element
458
+ {
459
+ static auto value (type_tag<typename Pair::first_type>) -> type_tag<typename Pair::second_type>;
460
+ };
461
+
462
+ template <typename ... elems>
463
+ struct type_map : element<elems>...
464
+ {
465
+ using element<elems>::value...;
466
+
467
+ template <typename K>
468
+ using find = typename decltype (type_map::value(type_tag<K> {}))::type;
469
+ };
470
+
471
+ template <typename U, typename T>
472
+ struct GraphQLUnion : std::false_type
473
+ {
474
+ };
475
+
476
+ template <typename ... Types>
477
+ struct Union
478
+ {
479
+ template <typename U>
480
+ Union (U&& u)
481
+ : value(std::forward<U>(u))
482
+ {
483
+ }
484
+ std::variant<std::shared_ptr<Types>...> value;
485
+ };
486
+
487
+ template <typename T>
488
+ struct is_union : std::false_type
489
+ {
490
+ };
491
+
492
+ template <typename ... Types>
493
+ struct is_union <Union<Types...>> : std::true_type
494
+ {
495
+ };
496
+
497
+ // helper type for the visitor #4
498
+ template <class ... Ts>
499
+ struct overloaded : Ts...
500
+ {
501
+ using Ts::operator ()...;
502
+ };
503
+ // explicit deduction guide (not needed as of C++20)
504
+ template <class ... Ts>
505
+ overloaded (Ts...) -> overloaded<Ts...>;
506
+
507
+ template <typename T>
508
+ struct GraphQLBuilder
509
+ {
510
+
511
+ template <typename U>
512
+ static T build (U&& u)
513
+ {
514
+
515
+ if constexpr (is_optional<T>::value)
516
+ {
517
+ if constexpr (is_optional<U>::value)
518
+ {
519
+ if (u)
520
+ return GraphQLBuilder<typename T::value_type>::build (*u);
521
+ return std::nullopt;
522
+ }
523
+ else
524
+ {
525
+ return GraphQLBuilder<typename T::value_type>::build (std::forward<U>(u));
526
+ }
527
+ }
528
+ else if constexpr (is_vector<T>::value)
529
+ {
530
+ T out;
531
+ for (auto ui : u)
532
+ {
533
+ out.push_back (GraphQLBuilder<typename T::value_type>::build (ui));
534
+ }
535
+ return out;
536
+ }
537
+ else if constexpr (is_union<typename std::remove_reference_t <U>::element_type>::value)
538
+ {
539
+
540
+ // using model_t =
541
+ // typename GraphQLUnion < typename std::remove_reference_t<U>::element_type,
542
+ // typename(typename T::element_type
543
+ // > ::model_map)::find<typename std::remove_reference_t<V>::element_type>;
544
+ // typedef std::shared_ptr<model_t> asdf_t;
545
+
546
+ static_assert (GraphQLUnion<typename std::remove_reference_t <U>::element_type,
547
+ typename T::element_type>::value,
548
+ " template<> struct GraphQLUnion<T::element_type>: std::true_type{...} not "
549
+ " defined!" );
550
+ if (u)
551
+ return std::visit (
552
+ []<typename V>(V&& arg) {
553
+ using union_t = GraphQLUnion<typename std::remove_reference_t <U>::element_type, typename T::element_type>;
554
+ using model_map_t = typename union_t ::model_map;
555
+ using model_t = model_map_t ::template find<typename std::remove_reference_t <V>::element_type>;
556
+ if constexpr (std::is_same_v<model_t , std::monostate>)
557
+ {
558
+ throw std::logic_error (" Unsupported variant type" );
559
+ return std::shared_ptr<typename T::element_type>();
560
+ }
561
+ else
562
+ {
563
+ return GraphQLBuilder<T>::build (
564
+ GraphQLBuilder<std::shared_ptr<model_t >>::build (std::move (arg)));
565
+ }
566
+ },
567
+ std::move (u->value ));
568
+ return std::shared_ptr<typename T::element_type>();
569
+ }
570
+ else
571
+ {
572
+ if (u)
573
+ return std::make_shared<typename T::element_type>(std::forward<U>(u));
574
+ return std::shared_ptr<typename T::element_type>();
575
+ }
576
+ }
577
+ };
578
+
413
579
// Field accessors may return either a result of T, an awaitable of T, or a std::future<T>, so at
414
580
// runtime the implementer may choose to return by value or defer/parallelize expensive operations
415
581
// by returning an async future or an awaitable coroutine.
@@ -418,11 +584,31 @@ class [[nodiscard("unnecessary construction")]] AwaitableObject
418
584
{
419
585
public:
420
586
template <typename U>
421
- AwaitableObject (U&& value)
587
+ AwaitableObject (U&& value, std:: enable_if_t <std::is_assignable_v<T, U>>* = nullptr )
422
588
: _value { std::forward<U>(value) }
423
589
{
424
590
}
425
591
592
+ template <typename U>
593
+ AwaitableObject (
594
+ U&& value, std::enable_if_t <!std::is_assignable_v<T, U> && !is_future<U>::value>* = nullptr )
595
+ : _value (GraphQLBuilder<T>::build (std::forward<U>(value)))
596
+ {
597
+ }
598
+
599
+ template <typename U>
600
+ AwaitableObject (
601
+ U&& value, std::enable_if_t <!std::is_assignable_v<T, U> && is_future<U>::value>* = nullptr )
602
+ : _value (std::async ([value = std::forward<U>(value)]() mutable {
603
+ if constexpr (std::is_assignable_v<T, decltype (value.get ())>){
604
+ return value.get ();
605
+ }else {
606
+ return GraphQLBuilder<T>::build (value.get ());
607
+ }
608
+ }))
609
+ {
610
+ }
611
+
426
612
struct promise_type
427
613
{
428
614
[[nodiscard(" unnecessary construction" )]] AwaitableObject<T> get_return_object () noexcept
0 commit comments