expected.hpp 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #ifndef GI_EXPECTED_HPP
  2. #define GI_EXPECTED_HPP
  3. #if __has_include("nonstd/expected.hpp")
  4. #if __cpp_concepts >= 202002L
  5. // this is also required in gcc's libstdc++ expected
  6. #else
  7. // so if that is missing, then prevent delegation to <expected>
  8. #define nsel_CONFIG_SELECT_EXPECTED nsel_EXPECTED_NONSTD
  9. #endif
  10. #include "nonstd/expected.hpp"
  11. #else
  12. #include <expected>
  13. #endif
  14. #include "base.hpp"
  15. #include "exception.hpp"
  16. namespace gi
  17. {
  18. // alias so we might route to a std type some day ...
  19. template<typename T, typename E>
  20. #ifdef expected_lite_VERSION
  21. using expected = nonstd::expected<T, E>;
  22. #else
  23. using expected = std::expected<T, E>;
  24. #endif
  25. // standardize on glib error
  26. template<typename T>
  27. using result = expected<T, repository::GLib::Error>;
  28. namespace detail
  29. {
  30. // only use nonstd if it does not delegate to std (in incomplete way)
  31. #if defined(expected_lite_VERSION) && !nsel_USES_STD_EXPECTED
  32. inline nonstd::unexpected_type<repository::GLib::Error>
  33. make_unexpected(GError *error)
  34. {
  35. assert(error);
  36. return nonstd::make_unexpected(repository::GLib::Error(error));
  37. }
  38. inline nonstd::unexpected_type<repository::GLib::Error>
  39. make_unexpected(repository::GLib::Error error)
  40. {
  41. assert(error);
  42. return nonstd::make_unexpected(std::move(error));
  43. }
  44. #else
  45. inline std::unexpected<repository::GLib::Error>
  46. make_unexpected(GError *error)
  47. {
  48. assert(error);
  49. return std::unexpected<repository::GLib::Error>(error);
  50. }
  51. #endif
  52. } // namespace detail
  53. // no forwarding reference; T must be non-reference type
  54. template<typename T>
  55. result<T>
  56. make_result(T t, GError *error)
  57. {
  58. if (error)
  59. return detail::make_unexpected(error);
  60. return t;
  61. }
  62. // rough helpers to unwrap result/expected
  63. // unwrap by move
  64. template<typename T>
  65. T
  66. expect(gi::result<T> &&t)
  67. {
  68. if (!t)
  69. detail::try_throw(std::move(t.error()));
  70. return std::move(*t);
  71. }
  72. namespace detail
  73. {
  74. template<typename T>
  75. void test_result(const gi::result<T> &);
  76. template<typename T>
  77. int test_result(const T &);
  78. template<typename T>
  79. using is_result = std::is_same<void,
  80. decltype(test_result(std::forward<T>(std::declval<T>())))>;
  81. } // namespace detail
  82. // should only be used for a non-result
  83. // (e.g. avoid l-value result ending up here)
  84. template<typename T, typename Enable = typename std::enable_if<
  85. !detail::is_result<T>::value>::type>
  86. T
  87. expect(T &&t)
  88. {
  89. return std::forward<T>(t);
  90. }
  91. template<typename T>
  92. struct rv
  93. {
  94. #if GI_DL && GI_EXPECTED
  95. using type = gi::result<T>;
  96. #else
  97. using type = T;
  98. #endif
  99. };
  100. } // namespace gi
  101. #endif // GI_EXPECTED_HPP