9 #ifndef EAGINE_C_API_WRAP_HPP
10 #define EAGINE_C_API_WRAP_HPP
27 #include <type_traits>
42 constexpr
auto name() const noexcept {
52 template <
typename T,
typename Tag = nothing_t,
bool IsIndexed = false>
57 template <
typename ApiTraits,
typename Api>
75 typename Tag = nothing_t,
76 bool IsIndexed =
false>
81 template <
typename ApiTraits,
typename Api>
88 constexpr
auto operator+(I index)
const noexcept -> std::enable_if_t<
89 (IsIndexed && std::is_integral_v<I>),
91 using O = std::conditional_t<
93 std::make_signed_t<I>,
94 std::make_unsigned_t<I>>;
95 return {limit_cast<T>(value + limit_cast<O>(index))};
104 typename Tag = nothing_t,
105 bool IsIndexed =
false>
110 using tag_type = Tag;
112 template <
typename ApiTraits,
typename Api>
122 template <
typename I>
123 constexpr
auto operator+(I index)
const noexcept -> std::enable_if_t<
124 (IsIndexed && std::is_integral_v<I>),
126 using O = std::conditional_t<
128 std::make_signed_t<I>,
129 std::make_unsigned_t<I>>;
130 return {limit_cast<T>(this->value + limit_cast<O>(index))};
134 template <
typename ClassList,
typename Constant,
typename Tag,
bool IsIndexed>
135 struct get_opt_c_api_constant;
137 template <
typename ClassList,
typename T, T value,
typename Tag,
bool IsIndexed>
138 struct get_opt_c_api_constant<
140 std::integral_constant<T, value>,
143 : type_identity<static_c_api_constant<ClassList, T, value, Tag, IsIndexed>> {
146 template <
typename ClassList,
typename T,
typename Tag,
bool IsIndexed>
147 struct get_opt_c_api_constant<ClassList, type_identity<T>, Tag, IsIndexed>
148 : type_identity<dynamic_c_api_constant<ClassList, T, Tag, IsIndexed>> {};
172 typename Tag = nothing_t,
173 bool IsIndexed =
false>
175 typename get_opt_c_api_constant<ClassList, Constant, Tag, IsIndexed>::type;
179 template <
typename Info>
181 :
public std::runtime_error
185 : std::runtime_error(
"bad operation result")
186 , Info(std::move(
info)) {}
201 template <
typename Result, api_result_val
idity>
202 class api_result_value;
217 template <
typename Result,
typename Info>
225 template <
typename Result,
typename Info>
230 template <
typename Result>
233 constexpr api_result_value() noexcept =
default;
236 template <
typename Info,
typename T>
241 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
245 template <
typename Info,
typename Transform>
248 Transform& transform)
const {
249 using T = decltype(transform(std::declval<Result>()));
251 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
255 template <
typename Info,
typename Check,
typename IfFalse>
261 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
268 template <
typename Result>
269 static constexpr
auto
270 extract(api_result_value<Result, api_result_validity::never>&) noexcept
275 template <
typename Result>
276 static constexpr
auto
277 extract(
const api_result_value<Result, api_result_validity::never>&) noexcept
279 return unreachable_reference(type_identity<Result>{});
282 template <
typename Result,
typename Info>
283 inline auto operator>>(
284 api_result<Result, Info, api_result_validity::never> result,
285 Result& dest) -> Result& {
286 throw bad_result<Info>(
static_cast<Info&&
>(result));
287 return dest = std::move(result._value);
294 template <
typename Info,
typename T>
296 const api_result<void, Info, api_result_validity::never>& src,
297 type_identity<T>)
const {
298 api_result<T, Info, api_result_validity::never> result{};
299 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
303 template <
typename Info,
typename Transform>
305 const api_result<void, Info, api_result_validity::never>& src,
306 Transform& transform)
const {
307 using T = decltype(transform());
308 api_result<T, Info, api_result_validity::never> result{};
309 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
313 template <
typename Info,
typename Check,
typename IfFalse>
315 const api_result<void, Info, api_result_validity::never>& src,
317 IfFalse&)
const ->
auto& {
322 template <
typename Result,
typename Info>
325 ,
public api_result_value<Result, api_result_validity::never> {
326 using base = api_result_value<Result, api_result_validity::never>;
331 explicit constexpr
operator bool() const noexcept {
335 template <
typename T>
336 auto replaced_with(T)
const {
337 api_result<T, Info, api_result_validity::never> result{};
338 static_cast<Info&
>(result) =
static_cast<const Info&
>(*
this);
342 template <
typename T>
343 auto cast_to(type_identity<T> tid)
const {
344 return this->_cast_to(*
this, tid);
347 auto cast_to(type_identity<void>)
const noexcept ->
auto& {
351 auto cast_to(type_identity<nothing_t>)
const noexcept ->
auto& {
355 template <
typename Transform>
356 auto transformed(Transform transform)
const {
357 return this->_transformed(*
this, transform);
360 template <
typename Check,
typename IfFalse>
361 auto collapsed(Check check, IfFalse if_false)
const {
362 return this->_collapsed(*
this, check, if_false);
366 static constexpr
auto
367 extract(
const api_result_value<void, api_result_validity::never>&) noexcept
372 template <
typename Result,
typename Info>
375 const api_result<Result, Info, api_result_validity::never>& r) noexcept
381 template <
typename Result,
typename Info,
typename Fallback>
382 static constexpr
auto extract_or(
383 const api_result<Result, Info, api_result_validity::never>&,
384 Fallback&& fallback) noexcept -> Result {
385 return {std::forward<Fallback>(fallback)};
392 template <
typename Result>
395 constexpr api_result_value() noexcept(noexcept(Result{})) =
default;
397 constexpr api_result_value(Result value) noexcept
398 : _value{std::move(value)} {}
407 template <
typename Info,
typename T>
412 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
416 template <
typename Info,
typename Transform>
418 const api_result<Result, Info, api_result_validity::always>& src,
419 Transform& transform)
const {
420 using T = decltype(transform(std::declval<Result>()));
421 api_result<T, Info, api_result_validity::always> result{
423 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
427 template <
typename Info,
typename Check,
typename IfFalse>
429 const api_result<Result, Info, api_result_validity::always>& src,
431 IfFalse& if_false)
const {
432 api_result<void, Info, api_result_validity::always> result{};
433 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
435 if_false(
static_cast<Info&
>(result));
444 template <
typename Result>
445 static constexpr
auto
446 extract(api_result_value<Result, api_result_validity::always>&& result) noexcept
448 return std::move(result._value);
451 template <
typename Result>
452 static constexpr
auto
453 extract(api_result_value<Result, api_result_validity::always>& result) noexcept
455 return result._value;
458 template <
typename Result>
460 const api_result_value<Result, api_result_validity::always>& result) noexcept
462 return result._value;
465 template <
typename Result>
466 inline auto operator>>(
467 api_result_value<Result, api_result_validity::always> result,
468 Result& dest) noexcept -> Result& {
469 return dest = std::move(result._value);
475 constexpr
auto is_valid() const noexcept {
480 template <
typename Info,
typename T>
482 const api_result<void, Info, api_result_validity::always>& src,
483 type_identity<T>)
const {
484 api_result<T, Info, api_result_validity::always> result{};
485 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
489 template <
typename Info,
typename Transform>
491 const api_result<void, Info, api_result_validity::always>& src,
492 Transform& transform)
const {
493 using T = decltype(transform());
494 api_result<T, Info, api_result_validity::always> result{transform()};
495 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
499 template <
typename Info,
typename Check,
typename IfFalse>
501 const api_result<void, Info, api_result_validity::always>& src,
503 IfFalse&)
const ->
auto& {
512 template <
typename Result,
typename Info>
515 ,
public api_result_value<Result, api_result_validity::always> {
522 explicit constexpr
operator bool() const noexcept {
523 return bool(*
static_cast<const Info*
>(
this));
527 template <
typename T>
531 static_cast<Info&
>(result) =
static_cast<const Info&
>(*
this);
536 template <
typename T>
538 return this->_cast_to(*
this, tid);
545 auto cast_to(type_identity<nothing_t>)
const noexcept ->
auto& {
550 template <
typename Transform>
552 return this->_transformed(*
this, transform);
555 template <
typename Check,
typename IfFalse>
556 auto collapsed(Check check, IfFalse if_false)
const {
557 return this->_collapsed(*
this, check, if_false);
561 static constexpr
auto
562 extract(
const api_result_value<void, api_result_validity::always>&) noexcept
567 template <
typename Result,
typename Info>
570 const api_result<Result, Info, api_result_validity::always>& r) noexcept
576 template <
typename Result,
typename Info,
typename Fallback>
577 static constexpr
auto extract_or(
578 const api_result<Result, Info, api_result_validity::always>& result,
579 Fallback&& fallback) noexcept -> Result {
583 return {std::forward<Fallback>(fallback)};
590 template <
typename Result>
593 constexpr api_result_value() noexcept =
default;
595 constexpr api_result_value(Result value,
bool valid) noexcept
596 : _value{std::move(value)}
605 template <
typename Info,
typename T>
610 T(_value), src.is_valid()};
611 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
615 template <
typename Info,
typename Transform>
617 const api_result<Result, Info, api_result_validity::maybe>& src,
618 Transform& transform)
const {
619 using T = decltype(transform(std::declval<Result>()));
620 api_result<T, Info, api_result_validity::maybe> result{
621 transform(_value), src.is_valid()};
622 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
626 template <
typename Info,
typename Check,
typename IfFalse>
628 const api_result<Result, Info, api_result_validity::maybe>& src,
630 IfFalse& if_false)
const {
631 api_result<void, Info, api_result_validity::maybe> result{};
632 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
633 if(src.is_valid() && !check(_value)) {
634 if_false(
static_cast<Info&
>(result));
646 template <
typename Result>
647 static constexpr
auto
650 return EAGINE_CONSTEXPR_ASSERT(result._valid, std::move(result._value));
655 template <
typename Result>
656 static constexpr
auto
659 return EAGINE_CONSTEXPR_ASSERT(result._valid, result._value);
664 template <
typename Result>
668 return EAGINE_CONSTEXPR_ASSERT(result._valid, result._value);
676 template <
typename Result,
typename Info>
677 inline auto operator>>(
679 Result& dest) -> Result& {
683 return dest = std::move(result._value);
689 constexpr api_result_value() noexcept = default;
691 constexpr api_result_value(
bool valid) noexcept
694 constexpr
auto is_valid() const noexcept {
699 template <
typename Info,
typename T>
701 const api_result<void, Info, api_result_validity::maybe>& src,
702 type_identity<T>)
const {
703 api_result<T, Info, api_result_validity::maybe> result{
704 T{}, src.is_valid()};
705 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
709 template <
typename Info,
typename Transform>
711 const api_result<void, Info, api_result_validity::maybe>& src,
712 Transform& transform)
const {
713 using T = decltype(transform());
714 api_result<T, Info, api_result_validity::maybe> result{
715 transform(), src.is_valid()};
716 static_cast<Info&
>(result) =
static_cast<const Info&
>(src);
720 template <
typename Info,
typename Check,
typename IfFalse>
722 const api_result<void, Info, api_result_validity::maybe>& src,
724 IfFalse&)
const ->
auto& {
732 template <
typename Result,
typename Info>
735 ,
public api_result_value<Result, api_result_validity::maybe> {
736 using base = api_result_value<Result, api_result_validity::maybe>;
741 explicit constexpr
operator bool() const noexcept {
742 return this->is_valid() && bool(*
static_cast<const Info*
>(
this));
745 template <
typename T>
746 auto replaced_with(T value)
const {
747 api_result<T, Info, api_result_validity::maybe> result{
748 std::move(value), this->is_valid()};
749 static_cast<Info&
>(result) =
static_cast<const Info&
>(*
this);
753 template <
typename T>
754 auto cast_to(type_identity<T> tid)
const {
755 return this->_cast_to(*
this, tid);
758 auto cast_to(type_identity<void>)
const noexcept ->
auto& {
762 auto cast_to(type_identity<nothing_t>)
const noexcept ->
auto& {
766 template <
typename Transform>
767 auto transformed(Transform transform)
const {
768 return this->_transformed(*
this, transform);
771 template <
typename Check,
typename IfFalse>
772 auto collapsed(Check check, IfFalse if_false)
const {
773 return this->_collapsed(*
this, check, if_false);
777 static constexpr
auto
778 extract(
const api_result_value<void, api_result_validity::maybe>&) noexcept
783 template <
typename Result,
typename Info>
786 const api_result<Result, Info, api_result_validity::maybe>& r) noexcept
792 template <
typename Result,
typename Info,
typename Fallback>
793 static constexpr
auto extract_or(
794 const api_result<Result, Info, api_result_validity::maybe>& result,
795 Fallback&& fallback) noexcept -> Result {
799 return {std::forward<Fallback>(fallback)};
804 template <
typename Result,
typename Info>
805 class api_combined_result
806 :
public api_result<Result, Info, api_result_validity::maybe> {
807 using base = api_result<Result, Info, api_result_validity::maybe>;
810 api_combined_result(api_result<Result, Info, api_result_validity::never> src)
812 static_cast<Info&
>(*this) =
static_cast<Info&&
>(src);
815 api_combined_result(api_result<Result, Info> src)
818 static_cast<api_result_value<Result, api_result_validity::always>&&
>(
821 static_cast<Info&
>(*this) =
static_cast<Info&&
>(src);
824 api_combined_result(api_result<Result, Info, api_result_validity::maybe> src)
825 : base{std::move(src)} {}
828 template <
typename Info>
829 class api_combined_result<void, Info>
830 :
public api_result<void, Info, api_result_validity::maybe> {
831 using base = api_result<void, Info, api_result_validity::maybe>;
834 template <
typename R>
836 const api_result<R, Info, api_result_validity::never>& src)
838 static_cast<Info&
>(*this) =
static_cast<const Info&
>(src);
841 template <
typename R>
842 api_combined_result(
const api_result<R, Info>& src)
843 : base{src.is_valid()} {
844 static_cast<Info&
>(*this) =
static_cast<const Info&
>(src);
847 template <
typename R>
849 const api_result<R, Info, api_result_validity::maybe>& src)
850 : base{src.is_valid()} {
851 static_cast<Info&
>(*this) =
static_cast<const Info&
>(src);
855 template <
typename Result,
typename Info>
856 struct ok_traits<api_combined_result<Result, Info>> {
858 const api_combined_result<Result, Info>& r) noexcept ->
const Info& {
863 template <
typename ApiTraits,
typename Tag,
typename Signature>
864 using c_api_function_ptr =
865 typename ApiTraits::template function_pointer<Tag, Signature>::type;
867 template <
typename ApiTraits,
typename Tag,
typename Signature>
868 class unimplemented_c_api_function;
882 c_api_function_ptr<ApiTraits, Tag, Signature>
function>
893 template <
typename ApiTraits,
typename Tag,
typename Signature>
896 template <
typename Api,
typename ApiTraits,
typename Tag>
897 class derived_c_api_function;
902 template <
typename Tag,
typename Signature>
903 using function_pointer = std::add_pointer<Signature>;
905 template <
typename Api,
typename Type>
907 -> std::tuple<Type, bool> {
911 template <
typename Api,
typename Tag,
typename Signature>
913 -> std::add_pointer_t<Signature> {
917 template <
typename Tag,
typename RV>
922 template <
typename Tag>
925 template <
typename RV,
typename Tag,
typename... Params,
typename... Args>
926 static constexpr
auto
927 call_static(Tag tag, RV (*
function)(Params...), Args&&... args) -> RV {
930 std::forward<Args>(args)...);
935 template <
typename RV,
typename Tag,
typename... Params,
typename... Args>
936 static constexpr
auto
937 call_dynamic(Tag tag, RV (*
function)(Params...), Args&&... args) -> RV {
940 std::forward<Args>(args)...);
945 template <
typename RV>
948 template <
typename RV>
951 template <
typename RV>
955 template <
bool IsAvailable>
956 class c_api_function_base :
public bool_constant<IsAvailable> {
958 constexpr c_api_function_base(
string_view name) noexcept
961 constexpr
explicit operator bool() const noexcept {
965 constexpr
auto name() const noexcept ->
string_view {
973 template <
typename ApiTraits,
typename Tag,
typename RV,
typename... Params>
974 class unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>
975 :
public c_api_function_base<false> {
976 using base = c_api_function_base<false>;
979 using signature = RV(Params...);
981 template <
typename Api>
982 constexpr unimplemented_c_api_function(
988 template <
typename... Args>
989 constexpr
auto operator()(Args&&...) const noexcept
990 -> std::enable_if_t<sizeof...(Params) == sizeof...(Args), RV> {
991 return ApiTraits::fallback(Tag(), type_identity<RV>());
1004 c_api_function_ptr<ApiTraits, Tag, RV(Params...)>
function>
1006 :
public c_api_function_base<true> {
1007 using base = c_api_function_base<true>;
1013 template <
typename Api>
1018 template <
typename... Args>
1020 -> std::enable_if_t<
sizeof...(Params) ==
sizeof...(Args), RV> {
1021 return ApiTraits::call_static(
1022 Tag(),
function, std::forward<Args>(args)...);
1030 template <
typename ApiTraits,
typename Tag,
typename RV,
typename... Params>
1032 :
public c_api_function_base<true> {
1034 using base = c_api_function_base<true>;
1035 using function_pointer = c_api_function_ptr<ApiTraits, Tag, RV(Params...)>;
1041 template <
typename Api>
1047 , _function{traits.link_function(
1054 constexpr
explicit operator bool() const noexcept {
1055 return bool(_function);
1059 template <
typename... Args>
1061 -> std::enable_if_t<
sizeof...(Params) ==
sizeof...(Args), RV> {
1062 return ApiTraits::call_dynamic(
1063 Tag(), _function, std::forward<Args>(args)...);
1067 function_pointer _function{
nullptr};
1087 c_api_function_ptr<ApiTraits, Tag, Signature>
function,
1094 static_c_api_function<ApiTraits, Tag, Signature, function>,
1095 dynamic_c_api_function<ApiTraits, Tag, Signature>>,
1096 unimplemented_c_api_function<ApiTraits, Tag, Signature>>;
1098 template <
typename Api,
typename ApiTraits,
typename Tag>
1099 class derived_c_api_function {
1101 template <
typename RV,
typename... Params,
typename... Args>
1102 static constexpr
auto _call(
1103 const unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>&,
1104 Args&&...) noexcept ->
typename ApiTraits::template no_result<RV> {
1112 RV (*Func)(Params...)>
1113 static constexpr
auto _call(
1115 Args&&... args) noexcept -> std::
1116 enable_if_t<!std::is_void_v<RV>,
typename ApiTraits::template result<RV>> {
1117 return {std::move(
function(std::forward<Args>(args)...))};
1120 template <
typename... Params,
typename... Args, void (*Func)(Params...)>
1121 static constexpr
auto _call(
1123 Args&&... args) noexcept ->
typename ApiTraits::template result<void> {
1124 function(std::forward<Args>(args)...);
1128 template <
typename RV,
typename... Params,
typename... Args>
1129 static constexpr
auto _call(
1131 Args&&... args) noexcept ->
typename ApiTraits::template opt_result<RV> {
1133 std::move(
function(std::forward<Args>(args)...)), bool(
function)};
1136 template <
typename... Params,
typename... Args>
1137 static constexpr
auto _call(
1139 Args&&... args) noexcept ->
1140 typename ApiTraits::template opt_result<void> {
1141 function(std::forward<Args>(args)...);
1142 return {bool(
function)};
1145 template <
typename RV,
typename... Params>
1146 static constexpr
auto _fake(
1147 const unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>&,
1148 RV fallback) noexcept ->
typename ApiTraits::template result<RV> {
1149 return {std::move(fallback)};
1152 template <
typename RV,
typename... Params>
1153 static constexpr
auto _fake(
1154 const unimplemented_c_api_function<ApiTraits, Tag, RV(Params...)>&) noexcept
1155 ->
typename ApiTraits::template result<RV> {
1159 template <
typename RV,
typename... Params, RV (*Func)(Params...),
typename F>
1160 static constexpr
auto _fake(
1162 F&& fallback) noexcept ->
typename ApiTraits::template result<RV> {
1163 return {std::forward<F>(fallback)};
1166 template <
typename RV,
typename... Params, RV (*Func)(Params...)>
1167 static constexpr
auto _fake(
1169 ->
typename ApiTraits::template result<RV> {
1173 template <
typename RV,
typename... Params,
typename F>
1174 static constexpr
auto _fake(
1176 F&& fallback) noexcept ->
typename ApiTraits::template result<RV> {
1177 return {std::forward<F>(fallback)};
1180 template <
typename RV,
typename... Params>
1181 static constexpr
auto
1183 ->
typename ApiTraits::template result<RV> {
1188 constexpr derived_c_api_function(
1191 Api& parent) noexcept
1193 , _parent{parent} {}
1195 constexpr
auto name()
const noexcept ->
string_view {
1200 constexpr
auto api()
const noexcept -> Api& {
1213 typename WrapperType,
1214 WrapperType Api::*Function>
1215 class wrapped_c_api_function
1216 :
public derived_c_api_function<Api, ApiTraits, Tag> {
1217 using base = derived_c_api_function<Api, ApiTraits, Tag>;
1220 template <
typename... Args>
1221 constexpr
auto _call(Args&&... args)
const noexcept {
1222 return base::_call(this->api().*Function, std::forward<Args>(args)...);
1225 template <
typename F>
1226 constexpr
auto _fake(F&& fallback)
const noexcept {
1227 return base::_fake(this->api().*Function, std::forward<F>(fallback));
1230 constexpr
auto _fake() const noexcept {
1231 return base::_fake(this->api().*Function);
1234 constexpr
auto _fake_empty_c_str() const noexcept ->
1235 typename ApiTraits::template result<const
char*> {
1236 return {
static_cast<const char*
>(
"")};
1239 template <
typename Arg>
1240 static constexpr
auto _conv(Arg arg) noexcept
1241 -> std::enable_if_t<std::is_scalar_v<Arg>, Arg> {
1245 template <
typename S,
typename T,
identifier_t L,
identifier_t I>
1246 static constexpr
auto _conv(enum_class<S, T, L, I> value) noexcept {
1250 template <
typename EC>
1251 static constexpr
auto _conv(enum_bitfield<EC> bits) noexcept {
1252 return _conv(bits._value);
1255 template <
typename Tg,
typename T, T inv>
1256 static constexpr
auto _conv(basic_handle<Tg, T, inv> hndl) noexcept {
1260 static constexpr
auto _conv(
string_view str) noexcept {
1275 explicit constexpr
operator bool() const noexcept {
1276 return bool((this->api()).*Function);
1283 #endif // EAGINE_C_API_WRAP_HPP