static_assert(sizeof(char) == sizeof(uint8_t), "your architecture's `char` is not 8 bits");
static_assert(sizeof(char16_t) == sizeof(uint16_t), "your architecture's `char16_t` is not 16 bits");
static_assert(sizeof(char32_t) == sizeof(uint32_t), "your architecture's `char32_t` is not 32 bits");
inline capi::DiplomatWrite WriteFromString(std::string& string) {
capi::DiplomatWrite w;
w.context = &string;
w.buf = &string[0];
w.len = string.length();
w.cap = string.length(); // Will never become true, as _grow is infallible.
w.grow_failed = false;
w.flush = _flush;
w.grow = _grow; return w;
}
// This "trait" allows one to use _write() methods to efficiently // write to a custom string type. To do this you need to write a specialized // `WriteTrait<YourType>` (see WriteTrait<std::string> below) // that is capable of constructing a DiplomatWrite, which can wrap // your string type with appropriate resize/flush functionality. template<typename T> struct WriteTrait { // Fill in this method on a specialization to implement this trait // static inline capi::DiplomatWrite Construct(T& t);
};
template<typename U = E, typename std::enable_if_t<!std::is_reference_v<U>, std::nullptr_t> = nullptr>
std::optional<E> err() && { if (!this->is_err()) { return std::nullopt;
} return std::make_optional(std::move(std::get<Err<E>>(std::move(this->val)).inner));
}
// std::optional does not work with reference types directly, so wrap them if present template<typename U = T, typename std::enable_if_t<std::is_reference_v<U>, std::nullptr_t> = nullptr>
std::optional<std::reference_wrapper<std::remove_reference_t<T>>> ok() && { if (!this->is_ok()) { return std::nullopt;
} return std::make_optional(std::reference_wrapper(std::forward<T>(std::get<Ok<T>>(std::move(this->val)).inner)));
}
template<typename U = E, typename std::enable_if_t<std::is_reference_v<U>, std::nullptr_t> = nullptr>
std::optional<std::reference_wrapper<std::remove_reference_t<E>>> err() && { if (!this->is_err()) { return std::nullopt;
} return std::make_optional(std::reference_wrapper(std::forward<E>(std::get<Err<E>>(std::move(this->val)).inner)));
}
// An ABI stable std::basic_string_view equivalent for the case of string // views in slices template <class CharT, class Traits = std::char_traits<CharT>> class basic_string_view_for_slice {
public:
using std_string_view = std::basic_string_view<CharT, Traits>;
using traits_type = typename std_string_view::traits_type;
using value_type = typename std_string_view::value_type;
using pointer = typename std_string_view::pointer;
using const_pointer = typename std_string_view::const_pointer;
using size_type = typename std_string_view::size_type;
using difference_type = typename std_string_view::difference_type;
static_assert(!std::is_void_v<capi_type>, "ABI compatible string_views are only supported for char and char16_t");
capi_type data_;
};
// We only implement these specialisations as diplomat doesn't provide c abi // types for others
using string_view_for_slice = basic_string_view_for_slice<char>;
using u16string_view_for_slice = basic_string_view_for_slice<char16_t>;
using string_view_span = span<const string_view_for_slice>;
using u16string_view_span = span<const u16string_view_for_slice>;
// Interop between std::function & our C Callback wrapper type
template <typename T, typename = void> struct as_ffi {
using type = T;
};
template <typename T> struct as_ffi<T, std::void_t<decltype(std::declval<std::remove_pointer_t<T>>().AsFFI())>> {
using type = decltype(std::declval<std::remove_pointer_t<T>>().AsFFI());
};
template<typename T>
using as_ffi_t = typename as_ffi<T>::type;
template<typename T>
using replace_string_view_t = std::conditional_t<std::is_same_v<T, std::string_view>, capi::DiplomatStringView, T>;
template<typename T, typename = void> struct diplomat_c_span_convert {
using type = T;
};
#define MAKE_SLICE_CONVERTERS(name, c_ty) \ template<typename T> \ struct diplomat_c_span_convert<T, std::enable_if_t<std::is_same_v<T, span<const c_ty>>>> { \
using type = diplomat::capi::Diplomat##name##View; \
}; \ template<typename T> \ struct diplomat_c_span_convert<T, std::enable_if_t<std::is_same_v<T, span<c_ty>>>> { \
using type = diplomat::capi::Diplomat##name##ViewMut; \
}; \
#if !defined(__sun) || !defined(_CHAR_IS_SIGNED) // int8_t and char are the same type on Solaris. Guard this definition to avoid // conflicts. https://github.com/rust-diplomat/diplomat/issues/1015
MAKE_SLICE_CONVERTERS(I8, int8_t) #endif
MAKE_SLICE_CONVERTERS(U8, uint8_t)
MAKE_SLICE_CONVERTERS(I16, int16_t)
MAKE_SLICE_CONVERTERS(U16, uint16_t)
MAKE_SLICE_CONVERTERS(I32, int32_t)
MAKE_SLICE_CONVERTERS(U32, uint32_t)
MAKE_SLICE_CONVERTERS(I64, int64_t)
MAKE_SLICE_CONVERTERS(U64, uint64_t)
MAKE_SLICE_CONVERTERS(F32, float)
MAKE_SLICE_CONVERTERS(F64, double)
MAKE_SLICE_CONVERTERS(Bool, bool)
MAKE_SLICE_CONVERTERS(Char, char32_t)
MAKE_SLICE_CONVERTERS(String, char)
MAKE_SLICE_CONVERTERS(String16, char16_t)
template<typename T>
using diplomat_c_span_convert_t = typename diplomat_c_span_convert<T>::type;
/// Replace the argument types from the std::function with the argument types for th function pointer template<typename T>
using replace_fn_t = diplomat_c_span_convert_t<replace_string_view_t<as_ffi_t<T>>>;
template <typename Ret, typename... Args> struct fn_traits<std::function<Ret(Args...)>> {
using fn_ptr_t = Ret(Args...);
using function_t = std::function<fn_ptr_t>;
using ret = Ret;
// For a given T, creates a function that take in the C ABI version & return the C++ type. template<typename T> static T replace(replace_fn_t<T> val) { if constexpr(std::is_same_v<T, std::string_view>) { return std::string_view{val.data, val.len};
} elseif constexpr (!std::is_same_v<T, diplomat_c_span_convert_t<T>>) { return T{ val.data, val.len };
} elseif constexpr (!std::is_same_v<T, as_ffi_t<T>>) { if constexpr (std::is_lvalue_reference_v<T>) { return *std::remove_reference_t<T>::FromFFI(val);
} else { return T::FromFFI(val);
}
} else { return val;
}
}
template<typename T> static replace_fn_t<T> replace_ret(T val) { if constexpr(std::is_same_v<T, std::string_view>) { return {val.data(), val.size()};
} elseif constexpr (!std::is_same_v<T, diplomat_c_span_convert_t<T>>) { // Can we convert straight away to our slice type, or (in the case of ABI compatible structs), do we have to do a reinterpret cast? if constexpr(std::is_same_v<decltype(std::declval<T>().data()), decltype(replace_fn_t<T>::data)>) { return replace_fn_t<T> { val.data(), val.size() };
} else { return replace_fn_t<T> { reinterpret_cast<decltype(replace_fn_t<T>::data)>(val.data()), val.size() };
}
} elseif constexpr(!std::is_same_v<T, as_ffi_t<T>>) { return val.AsFFI();
} else { return val;
}
}
if constexpr (has_ok) { if (is_ok) {
out.ok = replace_ret<T>(std::get<Ok<T>>(res.val).inner);
}
}
if constexpr(has_err) { if (!is_ok) {
out.err = replace_ret<E>(std::get<Err<E>>(res.val).inner);
}
}
return out;
}
// For DiplomatOption<> template<typename T, typename TOut> static TOut c_run_callback_diplomat_option(constvoid *cb, replace_fn_t<Args>... args) {
constexpr bool has_ok = !std::is_same_v<T, std::monostate>;
std::optional<T> ret = c_run_callback(cb, args...);
bool is_ok = ret.has_value();
TOut out;
out.is_ok = is_ok;
if constexpr(has_ok) { if (is_ok) {
out.ok = replace_ret<T>(ret.value());
}
} return out;
}
// All we need to do is just convert one pointer to another, while keeping the arguments the same: template<typename T> static T c_run_callback_diplomat_opaque(constvoid* cb, replace_fn_t<Args>... args) {
Ret out = c_run_callback(cb, args...);
// Trait for extracting inner types from either T*, std::optional, or std::unique_ptr. // These are the three potential types returned by next() functions template<typename T> struct inner { /* only T*, std::optional, and std::unique_ptr are supported */ }; template<typename T> struct inner<T*> { using type = T; }; template<typename T> struct inner<std::unique_ptr<T>> { using type = T; }; template<typename T> struct inner<std::optional<T>>{ using type = T; };
template<typename T, typename U = typename inner<T>::type> inlineconst U get_inner_if_present(T v) { if constexpr(std::is_same_v<T,U>) { return std::move(v);
} else { return *std::move(v);
}
}
/// Helper template enabling native iteration over unique ptrs to objects which implement next() template<typename T> struct next_to_iter_helper {
static_assert(has_next_v<T>, "next_to_iter_helper may only be used with types implementing next()");
using next_type = decltype(std::declval<T>().next());
// STL Iterator trait definitions
using value_type = typename inner<next_type>::type;
using difference_type = void;
using reference = std::add_lvalue_reference_t<value_type>;
using iterator_category = std::input_iterator_tag;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.