ruble 0.0.3.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gdbinit +21 -0
  3. data/.gitignore +18 -0
  4. data/.rubocop.yml +96 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +6 -0
  7. data/CMakeLists.txt +4 -0
  8. data/CODE_OF_CONDUCT.md +84 -0
  9. data/Gemfile +21 -0
  10. data/Gemfile.lock +98 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +63 -0
  13. data/Rakefile +41 -0
  14. data/ext/ruble/.gitignore +5 -0
  15. data/ext/ruble/CMakeLists.txt +157 -0
  16. data/ext/ruble/RuBLEHelpers.cmake +240 -0
  17. data/ext/ruble/bindings/Adapter.cpp +193 -0
  18. data/ext/ruble/bindings/Adapter.hpp +85 -0
  19. data/ext/ruble/bindings/Characteristic.cpp +171 -0
  20. data/ext/ruble/bindings/Characteristic.hpp +132 -0
  21. data/ext/ruble/bindings/Descriptor.cpp +34 -0
  22. data/ext/ruble/bindings/Descriptor.hpp +69 -0
  23. data/ext/ruble/bindings/Peripheral.cpp +212 -0
  24. data/ext/ruble/bindings/Peripheral.hpp +108 -0
  25. data/ext/ruble/bindings/RuBLE.cpp +115 -0
  26. data/ext/ruble/bindings/Service.cpp +112 -0
  27. data/ext/ruble/bindings/Service.hpp +61 -0
  28. data/ext/ruble/bindings/common.hpp +48 -0
  29. data/ext/ruble/bindings/globals.cpp +43 -0
  30. data/ext/ruble/cmake.mk +62 -0
  31. data/ext/ruble/concerns/CharacteristicValueTracker.cpp +18 -0
  32. data/ext/ruble/concerns/CharacteristicValueTracker.hpp +40 -0
  33. data/ext/ruble/concerns/Rubyable.cpp +4 -0
  34. data/ext/ruble/concerns/Rubyable.hpp +46 -0
  35. data/ext/ruble/config.h.in +25 -0
  36. data/ext/ruble/containers/ByteArray.cpp +64 -0
  37. data/ext/ruble/containers/ByteArray.hpp +161 -0
  38. data/ext/ruble/containers/Callback.hpp +52 -0
  39. data/ext/ruble/containers/NamedBitSet.hpp +140 -0
  40. data/ext/ruble/containers/NamedBitSet.ipp +71 -0
  41. data/ext/ruble/extconf.rb +30 -0
  42. data/ext/ruble/management/Registry.cpp +63 -0
  43. data/ext/ruble/management/Registry.hpp +170 -0
  44. data/ext/ruble/management/RegistryFactory.hpp +113 -0
  45. data/ext/ruble/management/RubyQueue.cpp +152 -0
  46. data/ext/ruble/management/RubyQueue.hpp +69 -0
  47. data/ext/ruble/modularize.diff +28 -0
  48. data/ext/ruble/types/SimpleBLE.hpp +21 -0
  49. data/ext/ruble/types/declarations.hpp +91 -0
  50. data/ext/ruble/types/helpers.hpp +12 -0
  51. data/ext/ruble/types/ruby.hpp +36 -0
  52. data/ext/ruble/types/stl.hpp +41 -0
  53. data/ext/ruble/utils/RubyCallbackTraits.cpp +28 -0
  54. data/ext/ruble/utils/RubyCallbackTraits.hpp +48 -0
  55. data/ext/ruble/utils/async.cpp +10 -0
  56. data/ext/ruble/utils/async.hpp +76 -0
  57. data/ext/ruble/utils/containers.hpp +41 -0
  58. data/ext/ruble/utils/exception_handling.cpp +50 -0
  59. data/ext/ruble/utils/exception_handling.hpp +53 -0
  60. data/ext/ruble/utils/garbage_collection.cpp +82 -0
  61. data/ext/ruble/utils/garbage_collection.hpp +22 -0
  62. data/ext/ruble/utils/hash.cpp +83 -0
  63. data/ext/ruble/utils/hash.hpp +52 -0
  64. data/ext/ruble/utils/hexadecimal.hpp +116 -0
  65. data/ext/ruble/utils/human_type_names.hpp +38 -0
  66. data/ext/ruble/utils/inspection.cpp +24 -0
  67. data/ext/ruble/utils/inspection.hpp +108 -0
  68. data/ext/ruble/utils/ruby.hpp +103 -0
  69. data/ext/ruble/utils/ruby_context.hpp +73 -0
  70. data/lib/ruble/build/.rubocop.yml +19 -0
  71. data/lib/ruble/build/boost.rb +34 -0
  72. data/lib/ruble/build/cmake.rb +134 -0
  73. data/lib/ruble/build/core_ext.rb +5 -0
  74. data/lib/ruble/build/data/bundler.rb +24 -0
  75. data/lib/ruble/build/data/extension.rb +101 -0
  76. data/lib/ruble/build/data/os.rb +21 -0
  77. data/lib/ruble/build/data/rice.rb +24 -0
  78. data/lib/ruble/build/data.rb +22 -0
  79. data/lib/ruble/build/extconf.rb +76 -0
  80. data/lib/ruble/build/github_repo.rb +129 -0
  81. data/lib/ruble/build/simpleble.rb +56 -0
  82. data/lib/ruble/build.rb +28 -0
  83. data/lib/ruble/version.rb +7 -0
  84. data/lib/ruble.rb +46 -0
  85. data/lib/tasks/dev/dev_tasks.rb +130 -0
  86. data/lib/tasks/dev/pager.rb +218 -0
  87. data/lib/tasks/dev/paths.rb +30 -0
  88. data/lib/tasks/dev/state_hash.rb +65 -0
  89. data/lib/tasks/dev.rake +41 -0
  90. data/lib/tasks/simpleble.rake +29 -0
  91. data/sig/rubble.rbs +4 -0
  92. metadata +263 -0
@@ -0,0 +1,36 @@
1
+ #pragma once
2
+
3
+ #include <rice/rice.hpp>
4
+ #include <ruby/ruby.h>
5
+ #include <thread>
6
+ #include <type_traits>
7
+
8
+ namespace RuBLE {
9
+ namespace Rice = ::Rice;
10
+ using ::Rice::Object, ::Rice::Data_Object, ::Rice::Data_Type, ::Rice::Arg;
11
+
12
+ using RubyThreadId = VALUE;
13
+ using CppThreadId = std::thread::id;
14
+
15
+ template <typename T = void>
16
+ using RbThreadCreateFn = VALUE(*)(T*);
17
+ template <typename Ret = void, typename T = void>
18
+ using RbThreadCallFn [[maybe_unused]] = Ret *(*)(T*);
19
+ template <typename T = void>
20
+ using RbUbfFn [[maybe_unused]] = void (*)(T*);
21
+
22
+
23
+ template <class T>
24
+ using ToRubyObjectResult = std::invoke_result_t<decltype(&T::self), const T&>;
25
+
26
+ template <class T>
27
+ concept ReturnsRubyValue = std::is_convertible_v<std::invoke_result_t<decltype(&T::value), const T&>, VALUE>;
28
+ template <class T>
29
+ concept RiceObject = std::derived_from<Rice::Object, T> && ReturnsRubyValue<T>;
30
+ template <class T>
31
+ concept RubyValue = RiceObject<T> || std::same_as<VALUE, T>;
32
+
33
+
34
+ template<typename T>
35
+ concept HasRubyObject = RubyValue<ToRubyObjectResult<T>> && requires { typename T::DataObject; };
36
+ }
@@ -0,0 +1,41 @@
1
+ #pragma once
2
+ #include <chrono>
3
+ #include <optional>
4
+ #include <ranges>
5
+ #include <semaphore>
6
+ #include <type_traits>
7
+
8
+ namespace chrono = std::chrono;
9
+ namespace views = std::views;
10
+ namespace ranges = std::ranges;
11
+
12
+ namespace RuBLE {
13
+ const constexpr auto semaphore_max = std::numeric_limits<uint16_t>::max();
14
+ using Semaphore [[maybe_unused]] = std::counting_semaphore<semaphore_max>;
15
+
16
+ template<typename T>
17
+ struct is_duration {
18
+ constexpr static const bool value = false;
19
+ };
20
+
21
+ template<typename ...Types>
22
+ struct is_duration<std::chrono::duration<Types...>> {
23
+ constexpr static const bool value = true;
24
+ };
25
+ template<typename T>
26
+ concept Duration = is_duration<T>::value;
27
+
28
+ template<class T>
29
+ concept OptionalDuration = Duration<T> || std::same_as<std::nullopt_t, T>;
30
+
31
+ template<class T, class R>
32
+ concept RangeOf = requires(const R &r, T &t) {
33
+ { *ranges::begin(r) } -> std::convertible_to<T>;
34
+ { *ranges::end(r) } -> std::convertible_to<T>;
35
+ };
36
+
37
+ template<ranges::viewable_range RangeT>
38
+ using RangeIteratorType = std::invoke_result_t<decltype(std::ranges::begin), RangeT &&>;
39
+ template<ranges::viewable_range RangeT>
40
+ using RangeElementType [[maybe_unused]] = std::invoke_result_t<decltype(RangeIteratorType<RangeT>::operator*), RangeIteratorType<RangeT> &&>;
41
+ }
@@ -0,0 +1,28 @@
1
+ #include "RubyCallbackTraits.hpp"
2
+ #include "types/ruby.hpp"
3
+
4
+ namespace RuBLE::Utils::Ruby {
5
+ CallbackTraits::CallbackTraits(const VALUE &val) {
6
+ if (RB_NIL_OR_UNDEF_P(val) || rb_obj_is_proc(val) != Qtrue)
7
+ throw std::invalid_argument("Argument must be a proc or lambda");
8
+
9
+ for (const auto &key: Ruby::FnParameterTypes) _map[key] = 0;
10
+ Rice::Array params = Object(val).call("parameters");
11
+ for (auto el: params) {
12
+ Rice::Array array = el.value();
13
+ std::string type = rb_id2name(rb_sym2id(array[0].value()));
14
+ ++_map[type];
15
+ }
16
+ _is_lambda = rb_proc_lambda_p(val) == Qtrue;
17
+ }
18
+
19
+ void CallbackTraits::assert_accepts_n_args(const VALUE &val, const uint8_t &n, bool allow_nil) {
20
+ if (RB_NIL_OR_UNDEF_P(val)) {
21
+ if (allow_nil) return;
22
+ throw std::invalid_argument("Argument must be a proc or lambda (nil values not accepted)");
23
+ }
24
+ if (CallbackTraits(val).accepts_n_args(n)) return;
25
+ throw std::invalid_argument("Argument must be callable with exactly "s +
26
+ std::to_string(n) + " positional arguments.");
27
+ }
28
+ }
@@ -0,0 +1,48 @@
1
+ #pragma once
2
+
3
+ #include <ruby/ruby.h>
4
+ #include <unordered_set>
5
+ #include <unordered_map>
6
+ #include <string>
7
+
8
+ // Used to confirm callbacks accept the number of arguments needed for callbacks
9
+ // This is preferable to alerting when callbacks are invoked, where it would be
10
+ // hard to decipher what's wrong from the ArgumentError
11
+ // unfortunately, Proc#arity isn't sufficiently informative because it doesn't
12
+ // take into account required kw args.
13
+ namespace RuBLE::Utils::Ruby {
14
+ static constexpr std::initializer_list<std::string_view> FnParameterTypes {
15
+ "req", "opt", "rest", "keyreq", "key", "keyrest"
16
+ };
17
+
18
+ class CallbackTraits {
19
+ bool _is_lambda = false;
20
+ std::unordered_map<std::string_view, uint_least8_t> _map;
21
+ public:
22
+ using MapValueType = decltype(_map)::mapped_type;
23
+
24
+ CallbackTraits(const VALUE &val);
25
+
26
+ [[maybe_unused]] constexpr bool is_lambda() const { return _is_lambda; }
27
+
28
+ [[maybe_unused]] constexpr bool is_proc() const { return !_is_lambda; }
29
+ constexpr const MapValueType &operator[](const std::string &type) const {
30
+ return _map.at(type);
31
+ }
32
+
33
+ // whether the lambda would accept exactly N positional args
34
+ constexpr bool accepts_n_args(int n) const {
35
+ if (!_is_lambda) return true;
36
+ if (_map.at("keyreq") > 0) return false; // if any keyword arguments are required
37
+ MapValueType min = _map.at("req");
38
+ MapValueType max = _map.at("rest") > 0 ? std::numeric_limits<MapValueType>::max() : min + _map.at("opt");
39
+ return min <= n && n <= max;
40
+ }
41
+
42
+ // throws an exception if the argument can't be called with exactly N positional args
43
+ static void assert_accepts_n_args(const VALUE &val, const uint8_t &n, bool allow_nil = true);
44
+ };
45
+ }
46
+ namespace RuBLE {
47
+ namespace Ruby = Utils::Ruby;
48
+ }
@@ -0,0 +1,10 @@
1
+ #include "async.hpp"
2
+
3
+ namespace RuBLE::Utils::Async {
4
+ void thread_sleep() {
5
+ rb_thread_schedule();
6
+ // TODO: maybe multiply sleep time by getloadavg() on linux (from cstdlib)
7
+ std::this_thread::sleep_for(250ms);
8
+ std::this_thread::yield();
9
+ }
10
+ }
@@ -0,0 +1,76 @@
1
+ #pragma once
2
+
3
+ #include <functional>
4
+ #include <ruby/ruby.h>
5
+ #include <thread>
6
+ #include "types/helpers.hpp"
7
+ #include "types/stl.hpp"
8
+
9
+ namespace RuBLE::Utils {
10
+ namespace Async {
11
+ using namespace std::chrono_literals;
12
+ // Not sure exactly which of these is doing the trick, but calling this when waiting
13
+ // on an async operation tends to get ruby jump to its other threads
14
+ // oddly, none of these commands, by themselves, were working for me
15
+ void thread_sleep();
16
+
17
+ template <OptionalDuration DurationT = std::nullopt_t>
18
+ bool wait_until(const std::function<bool(void)> &fn, const DurationT &duration = std::nullopt) {
19
+ using PredicateFn = std::function<bool()>;
20
+ constexpr const bool has_timeout = !is_nullopt<DurationT>;
21
+
22
+ bool fn_result = false, timed_out = false;
23
+ PredicateFn is_timed_out;
24
+
25
+ if constexpr (has_timeout) {
26
+ using clock = chrono::high_resolution_clock;
27
+ using time_point = clock::time_point;
28
+ time_point start = clock::now();
29
+ time_point until = start + chrono::duration_cast<clock::duration>(duration);
30
+
31
+ is_timed_out = [&timed_out, until] () -> bool {
32
+ return until < clock::now();
33
+ };
34
+ } else {
35
+ is_timed_out = [] { return false; };
36
+ }
37
+
38
+ auto check_if_done = [&is_timed_out, &timed_out, &fn, &fn_result] () -> bool {
39
+ fn_result = fn();
40
+ timed_out = is_timed_out();
41
+ return fn_result || timed_out;
42
+ };
43
+
44
+ while(!check_if_done()) thread_sleep();
45
+ return fn_result;
46
+ }
47
+
48
+
49
+ // template <typename From>
50
+ // using WrapReferences = std::conditional_t<std::is_reference_v<From>, std::reference_wrapper<std::remove_reference_t<From>>, From>;
51
+ //
52
+ // template <Future FutureT, typename ...Args> // T should be std::shared_future<T> or std::future<T>
53
+ // bool wait_for_future(FutureT future, const Args&... args) {
54
+ // using PredicateFn = std::function<bool()>;
55
+ // PredicateFn is_ready = [&future] { return future.wait_for(0s) == std::future_status::ready; };
56
+ // return wait_until(is_ready, args...);
57
+ // }
58
+ //
59
+ // template <Future FutureT>
60
+ // using await_future_result = typename future_traits<FutureT>::value_type;
61
+ //
62
+ // template <Future FutureT, typename ...Args> requires (sizeof...(Args) == 1)
63
+ // std::optional<WrapReferences<await_future_result<FutureT>>> await_future(FutureT future, const Args& ...args) {
64
+ // using ResultType = WrapReferences<await_future_result<FutureT>>;
65
+ // bool done = wait_for_future(future, args...);
66
+ // return done ? std::ref(future.get()) : std::optional<ResultType>();
67
+ // }
68
+ //
69
+ // template <Future FutureT>
70
+ // await_future_result<FutureT> await_future(FutureT future) {
71
+ // await_future(future, std::nullopt);
72
+ // return future.get();
73
+ // }
74
+ }
75
+ using namespace Async;
76
+ }
@@ -0,0 +1,41 @@
1
+ #pragma once
2
+ #include <ranges>
3
+ #include <functional>
4
+ #include <map>
5
+ #include <numeric>
6
+
7
+ namespace views = std::views;
8
+ namespace ranges = std::ranges;
9
+
10
+ namespace RuBLE::Utils {
11
+ namespace Containers {
12
+ constexpr std::string join(const ranges::viewable_range auto &range, const std::string_view &sep) {
13
+ if (ranges::empty(range)) return "";
14
+ if (ranges::size(range) == 1) return std::string(*ranges::cbegin(range));
15
+ const auto fold = [&sep](const std::string_view &a, const std::string_view &b) {
16
+ return std::string(a) + std::string(sep) + std::string(b);
17
+ };
18
+ return std::accumulate(std::next(ranges::cbegin(range)), ranges::cend(range),
19
+ std::string(*ranges::cbegin(range)), fold);
20
+ }
21
+
22
+ template<class KeyT, class ValueT,
23
+ class FnT = std::function<std::remove_reference_t<KeyT>(const std::remove_cvref_t<ValueT> &)>,
24
+ class ResultT = std::map<std::remove_reference_t<KeyT>, std::remove_reference_t<ValueT>>,
25
+ ranges::viewable_range RangeT> requires requires(FnT &&fnT, RangeT &&rangeT) {
26
+ { fnT(**ranges::begin(rangeT)) } -> std::convertible_to<std::remove_reference_t<KeyT>>;
27
+ }
28
+ [[maybe_unused]] ResultT map_by(RangeT &&r, FnT &&mapFn) {
29
+ auto makePair = [&mapFn](ValueT &val) -> auto {
30
+ KeyT key = mapFn(*val);
31
+ return std::make_pair(std::move(key), val);
32
+ };
33
+ auto pairView = views::transform(r, makePair);
34
+ return {pairView.begin(), pairView.end()};
35
+ }
36
+
37
+ } // Containers
38
+ using namespace Containers;
39
+ } // RuBLE::Utils
40
+
41
+
@@ -0,0 +1,50 @@
1
+ #include "exception_handling.hpp"
2
+
3
+ namespace RuBLE::ExceptionHandling {
4
+ std::terminate_handler _old_terminate_handler = nullptr;
5
+
6
+
7
+
8
+ void wrap_termination_handler() {
9
+ if (_old_terminate_handler != nullptr) {
10
+ throw std::runtime_error("Old terminate exception already set. Would overflow.");
11
+ }
12
+ _old_terminate_handler = std::get_terminate();
13
+
14
+ std::set_terminate([] {
15
+ std::exception_ptr ex = std::current_exception();
16
+
17
+ // std::cerr << "terminate called after throwing an instance of '";
18
+ // std::cerr << Utils::human_type_name(ex) << "'" << std::endl;
19
+ // std::cerr << "what(): " << ex
20
+ try {
21
+ std::cerr << "C++ Backtrace: " << std::endl;
22
+ std::cerr << boost::stacktrace::stacktrace() << std::endl;
23
+ } catch (const std::exception &ex2) {
24
+ std::throw_with_nested(ex); // TODO: test that this does what I think it does
25
+ }
26
+ try {
27
+ std::cerr << "Ruby Backtrace: " << std::endl;
28
+ rb_backtrace();
29
+ std::cerr << std::endl << std::endl;
30
+ } catch (const std::exception &ex2) {
31
+ std::throw_with_nested(ex);
32
+ }
33
+
34
+ if (_old_terminate_handler != nullptr) _old_terminate_handler();
35
+ // TODO: consider using boost::core::verbose_terminate_handler somewhere
36
+ });
37
+ }
38
+
39
+ [[maybe_unused]] void abort_with_stack() {
40
+ try {
41
+ std::cerr << boost::stacktrace::stacktrace();
42
+ } catch (const std::exception &ex2) {
43
+ std::cerr << "Could not generate C++ stacktrace. Skipping." << std::endl;
44
+ }
45
+ std::abort();
46
+ }
47
+
48
+ void throw_exception() { throw std::runtime_error("test error"); }
49
+ }
50
+
@@ -0,0 +1,53 @@
1
+ #pragma once
2
+
3
+ #include "config.h"
4
+ #include <backtrace.h>
5
+ #include <boost/stacktrace.hpp>
6
+ #include <boost/exception/all.hpp>
7
+ #include <iostream> // std::cerr
8
+ #include <exception> // std::set_terminate
9
+ #include <ruby/ruby.h>
10
+
11
+ namespace boost {
12
+ inline void assertion_failed_msg(const char *expr, const char *msg, const char *function, const char *, long) {
13
+ std::cerr << "Expression '" << expr << "' is false in function '" << function << "': " << (msg ? msg : "<...>")
14
+ << ".\nBacktrace:\n" << boost::stacktrace::stacktrace() << '\n';
15
+
16
+ std::abort();
17
+ }
18
+
19
+ [[maybe_unused]] inline void assertion_failed(const char *expr, const char *function, const char *file, long line) {
20
+ ::boost::assertion_failed_msg(expr, nullptr, function, file, line);
21
+ }
22
+ } // namespace boost
23
+
24
+ namespace RuBLE::ExceptionHandling {
25
+ [[noreturn]] void throw_exception();
26
+ [[maybe_unused]] void abort_with_stack();
27
+
28
+ using traced = boost::error_info<struct tag_stacktrace, boost::stacktrace::stacktrace>;
29
+
30
+ template <typename T>
31
+ [[maybe_unused]] boost::stacktrace::stacktrace extract_stacktrace(const T &e) {
32
+ boost::stacktrace::stacktrace *st = boost::get_error_info<traced>(e);
33
+ // TODO: does this method work / is it memory-safe
34
+ boost::stacktrace::stacktrace &st2(*st);
35
+ return st2;
36
+ }
37
+
38
+ template<class E>
39
+ constexpr auto add_backtrace(const E &e) {
40
+ return boost::enable_error_info(e) << traced(boost::stacktrace::stacktrace());
41
+ }
42
+
43
+ // TODO: see if we can somehow add C++ backtrace data to ruby exceptions
44
+ template<class E>
45
+ constexpr void throw_with_backtrace(const E &e) {
46
+ throw add_backtrace(e);
47
+ }
48
+
49
+ void wrap_termination_handler();
50
+ extern std::terminate_handler _old_terminate_handler;
51
+ }
52
+
53
+
@@ -0,0 +1,82 @@
1
+ #include "garbage_collection.hpp"
2
+
3
+ #include "management/Registry.hpp"
4
+ #include "management/RegistryFactory.hpp"
5
+ #include "bindings/Adapter.hpp"
6
+ #include "bindings/Peripheral.hpp"
7
+ #include "bindings/Service.hpp"
8
+ #include "bindings/Characteristic.hpp"
9
+ #include "containers/ByteArray.hpp"
10
+
11
+ namespace Rice {
12
+ template<>
13
+ void ruby_mark<RuBLE::AdapterRegistryFactory>(RuBLE::AdapterRegistryFactory *registryFactory) {
14
+ registryFactory->ruby_mark();
15
+ }
16
+
17
+ template<>
18
+ void ruby_mark<RuBLE::ByteArray>(RuBLE::ByteArray *byteArray) {
19
+ byteArray->ruby_mark();
20
+ }
21
+
22
+ template<>
23
+ void ruby_mark<RuBLE::PeripheralRegistryFactory>(RuBLE::PeripheralRegistryFactory *registryFactory) {
24
+ registryFactory->ruby_mark();
25
+ }
26
+
27
+ template<>
28
+ void ruby_mark<RuBLE::ServiceRegistryFactory>(RuBLE::ServiceRegistryFactory *registryFactory) {
29
+ registryFactory->ruby_mark();
30
+ }
31
+
32
+ template<>
33
+ void ruby_mark<RuBLE::CharacteristicRegistryFactory>(RuBLE::CharacteristicRegistryFactory *registryFactory) {
34
+ registryFactory->ruby_mark();
35
+ }
36
+
37
+ template<>
38
+ void ruby_mark<RuBLE::AdapterRegistry>(RuBLE::AdapterRegistry *registry) {
39
+ registry->ruby_mark();
40
+ }
41
+
42
+ template<>
43
+ void ruby_mark<RuBLE::PeripheralRegistry>(RuBLE::PeripheralRegistry *registry) { registry->ruby_mark(); }
44
+
45
+ template<>
46
+ void ruby_mark<RuBLE::ServiceRegistry>(RuBLE::ServiceRegistry *registry) { registry->ruby_mark(); }
47
+
48
+ template<>
49
+ void ruby_mark<RuBLE::CharacteristicRegistry>(RuBLE::CharacteristicRegistry *registry) { registry->ruby_mark(); }
50
+
51
+ template<>
52
+ void ruby_mark<RuBLE::Service>(RuBLE::Service *service) { service->ruby_mark(); }
53
+
54
+ template<>
55
+ void ruby_mark<RuBLE::Adapter>(RuBLE::Adapter *adapter) { adapter->ruby_mark(); }
56
+
57
+
58
+ template<>
59
+ void ruby_mark<RuBLE::Characteristic>(RuBLE::Characteristic *characteristic) { characteristic->ruby_mark(); }
60
+
61
+ template<>
62
+ void ruby_mark<RuBLE::Peripheral>(RuBLE::Peripheral *peripheral) { peripheral->ruby_mark(); }
63
+ }
64
+
65
+ // TODO: do these change anything? Without these,
66
+ // CLion seemed to be suggesting that many of the functions above were unused,
67
+ // which would tend to cause hard-to-detect errors, so just to be safe,
68
+ // assert that these templated versions of Rice::ruby_mark exist.
69
+ static_assert(&Rice::ruby_mark<RuBLE::Callback>);
70
+ static_assert(&Rice::ruby_mark<RuBLE::Adapter>);
71
+ static_assert(&Rice::ruby_mark<RuBLE::AdapterRegistry>);
72
+ static_assert(&Rice::ruby_mark<RuBLE::AdapterRegistryFactory>);
73
+ static_assert(&Rice::ruby_mark<RuBLE::Peripheral>);
74
+ static_assert(&Rice::ruby_mark<RuBLE::PeripheralRegistry>);
75
+ static_assert(&Rice::ruby_mark<RuBLE::PeripheralRegistryFactory>);
76
+ static_assert(&Rice::ruby_mark<RuBLE::Service>);
77
+ static_assert(&Rice::ruby_mark<RuBLE::ServiceRegistry>);
78
+ static_assert(&Rice::ruby_mark<RuBLE::ServiceRegistryFactory>);
79
+ static_assert(&Rice::ruby_mark<RuBLE::Characteristic>);
80
+ static_assert(&Rice::ruby_mark<RuBLE::CharacteristicRegistry>);
81
+ static_assert(&Rice::ruby_mark<RuBLE::CharacteristicRegistryFactory>);
82
+
@@ -0,0 +1,22 @@
1
+ #pragma once
2
+
3
+ #include "types/declarations.hpp"
4
+ #include "types/ruby.hpp"
5
+
6
+ namespace Rice {
7
+ template<> constexpr void ruby_mark<RuBLE::Callback>(RuBLE::Callback*);
8
+ template<> void ruby_mark<RuBLE::Adapter>(RuBLE::Adapter *);
9
+ template<> void ruby_mark<RuBLE::AdapterRegistry>(RuBLE::AdapterRegistry*);
10
+ template<> void ruby_mark<RuBLE::AdapterRegistryFactory>(RuBLE::AdapterRegistryFactory*);
11
+ template<> void ruby_mark<RuBLE::ByteArray>(RuBLE::ByteArray*);
12
+ template<> void ruby_mark<RuBLE::Peripheral>(RuBLE::Peripheral*);
13
+ template<> void ruby_mark<RuBLE::PeripheralRegistry>(RuBLE::PeripheralRegistry*);
14
+ template<> void ruby_mark<RuBLE::PeripheralRegistryFactory>(RuBLE::PeripheralRegistryFactory*);
15
+ template<> void ruby_mark<RuBLE::Service>(RuBLE::Service*);
16
+ template<> void ruby_mark<RuBLE::ServiceRegistry>(RuBLE::ServiceRegistry*);
17
+ template<> void ruby_mark<RuBLE::ServiceRegistryFactory>(RuBLE::ServiceRegistryFactory*);
18
+ template<> void ruby_mark<RuBLE::Characteristic>(RuBLE::Characteristic*);
19
+ template<> void ruby_mark<RuBLE::CharacteristicRegistry>(RuBLE::CharacteristicRegistry*);
20
+ template<> void ruby_mark<RuBLE::CharacteristicRegistryFactory>(RuBLE::CharacteristicRegistryFactory*);
21
+ }
22
+
@@ -0,0 +1,83 @@
1
+ #include "hash.hpp"
2
+ #include "bindings/Adapter.hpp"
3
+ #include "bindings/Characteristic.hpp"
4
+ #include "bindings/Peripheral.hpp"
5
+
6
+ std::size_t std::hash<SimpleBLE::Adapter>::operator()(const SimpleBLE::Adapter &a) const noexcept {
7
+ SimpleBLE::BluetoothAddress addr = const_cast<SimpleBLE::Adapter &>(a).address();
8
+ std::size_t h1 = typeid(a).hash_code();
9
+ static auto hasher = std::hash<SimpleBLE::BluetoothAddress>{};
10
+ return h1 ^ (hasher(addr) << 1);
11
+ }
12
+
13
+ std::size_t std::hash<RuBLE::Adapter>::operator()(const RuBLE::Adapter &a) const noexcept {
14
+ std::size_t h1 = typeid(a).hash_code();
15
+ static auto hasher = std::hash<SimpleBLE::Adapter>{};
16
+ return h1 ^ (hasher(a.get()) << 1);
17
+ }
18
+
19
+ std::size_t std::hash<SimpleBLE::Characteristic>::operator()(const SimpleBLE::Characteristic &p) const noexcept {
20
+ auto uuid = const_cast<SimpleBLE::Characteristic &>(p).uuid();
21
+ std::size_t h1 = typeid(p).hash_code();
22
+ static auto hasher = std::hash<decltype(uuid)>{};
23
+ return h1 ^ (hasher(uuid) << 1);
24
+ }
25
+
26
+ std::size_t std::hash<RuBLE::Characteristic>::operator()(const RuBLE::Characteristic &p) const noexcept {
27
+ std::size_t h1 = typeid(p).hash_code();
28
+ static auto hasher = std::hash<SimpleBLE::Characteristic>{};
29
+ return h1 ^ (hasher(p.get()) << 1);
30
+ }
31
+
32
+ std::size_t std::hash<RuBLE::Descriptor>::operator()(const RuBLE::Descriptor& d) const noexcept {
33
+ std::size_t h1 = typeid(d).hash_code();
34
+ static auto hasher = std::hash<std::remove_cvref_t<decltype(d.uuid())>>{};
35
+ return h1 ^ (hasher(d.uuid()) << 1);
36
+ }
37
+
38
+
39
+ std::size_t std::hash<SimpleBLE::Service>::operator()(const SimpleBLE::Service &p) const noexcept {
40
+ auto uuid = const_cast<SimpleBLE::Service &>(p).uuid();
41
+ std::size_t h1 = typeid(p).hash_code();
42
+ static auto hasher = std::hash<decltype(uuid)>{};
43
+ return h1 ^ (hasher(uuid) << 1);
44
+ }
45
+
46
+ std::size_t std::hash<RuBLE::Service>::operator()(const RuBLE::Service &p) const noexcept {
47
+ std::size_t h1 = typeid(p).hash_code();
48
+ static auto hasher = std::hash<SimpleBLE::Service>{};
49
+ return h1 ^ (hasher(p.get()) << 1);
50
+ }
51
+
52
+ size_t std::hash<SimpleBLE::Peripheral>::operator()(const SimpleBLE::Peripheral &p) const noexcept {
53
+ SimpleBLE::BluetoothAddress addr = const_cast<SimpleBLE::Peripheral &>(p).address();
54
+ std::size_t h1 = typeid(p).hash_code();
55
+ static auto hasher = std::hash<SimpleBLE::BluetoothAddress>{};
56
+ return h1 ^ (hasher(addr) << 1);
57
+ }
58
+
59
+ std::size_t std::hash<RuBLE::Peripheral>::operator()(const RuBLE::Peripheral &p) const noexcept {
60
+ std::size_t h1 = typeid(p).hash_code();
61
+ static auto hasher = std::hash<SimpleBLE::Peripheral>{};
62
+ return h1 ^ (hasher(p.get()) << 1);
63
+ }
64
+
65
+ template<> struct std::hash<SimpleBLE::Adapter>;
66
+ template<> struct std::hash<RuBLE::Adapter>;
67
+ template<> struct std::hash<SimpleBLE::Peripheral>;
68
+ template<> struct std::hash<RuBLE::Peripheral>;
69
+ template<> struct std::hash<SimpleBLE::Service>;
70
+ template<> struct std::hash<RuBLE::Service>;
71
+ template<> struct std::hash<SimpleBLE::Characteristic>;
72
+ template<> struct std::hash<RuBLE::Characteristic>;
73
+ template<> struct std::hash<RuBLE::Descriptor>;
74
+ // TODO: Use this in the registry map, but don't put in std::hash
75
+ //template<typename Key, class ProxyClass, class Value>
76
+ //struct std::hash<RuBLE::Registry<Key, ProxyClass, Value>> {
77
+ // std::size_t operator()(const RuBLE::Registry<Key, ProxyClass, Value>& r) const noexcept {
78
+ // std::size_t h1 = typeid(r).hash_code();
79
+ // using RegistryOwner = RuBLE::Registry<Key, ProxyClass, Value>::Owner;
80
+ // static auto hasher = std::hash<SimpleBLE::BluetoothAddress>{};
81
+ // return h1 ^ (hasher(r._registry) << 1);
82
+ // }
83
+ //};
@@ -0,0 +1,52 @@
1
+ #pragma once
2
+ #include <utility>
3
+ #include "types/declarations.hpp"
4
+
5
+ namespace RuBLE {
6
+ template<typename Key>
7
+ using HasherType = std::hash<Key>;
8
+
9
+ template<typename Key>
10
+ using HashFnType [[maybe_unused]] = std::invoke_result_t<std::hash<Key>()>;
11
+
12
+ template<typename Key>
13
+ using HashResultType = std::invoke_result<HashFnType<Key>, const Key &>::type;
14
+ static_assert(std::is_same<std::size_t, HashResultType<std::string>>::value);
15
+ }
16
+
17
+ template<> struct std::hash<SimpleBLE::Adapter> {
18
+ std::size_t operator()(const SimpleBLE::Adapter& a) const noexcept;
19
+ };
20
+
21
+ template<> struct std::hash<RuBLE::Adapter> {
22
+ std::size_t operator()(const RuBLE::Adapter& a) const noexcept;
23
+ };
24
+
25
+ template<> struct std::hash<SimpleBLE::Peripheral> {
26
+ std::size_t operator()(const SimpleBLE::Peripheral& p) const noexcept;
27
+ };
28
+
29
+ template<> struct std::hash<RuBLE::Peripheral> {
30
+ std::size_t operator()(const RuBLE::Peripheral& p) const noexcept;
31
+ };
32
+
33
+ template<> struct std::hash<SimpleBLE::Service> {
34
+ std::size_t operator()(const SimpleBLE::Service& s) const noexcept;
35
+ };
36
+
37
+ template<> struct std::hash<RuBLE::Service> {
38
+ std::size_t operator()(const RuBLE::Service& s) const noexcept;
39
+ };
40
+
41
+ template<> struct std::hash<SimpleBLE::Characteristic> {
42
+ std::size_t operator()(const SimpleBLE::Characteristic& s) const noexcept;
43
+ };
44
+
45
+ template<> struct std::hash<RuBLE::Characteristic> {
46
+ std::size_t operator()(const RuBLE::Characteristic& s) const noexcept;
47
+ };
48
+
49
+ template<> struct std::hash<RuBLE::Descriptor> {
50
+ std::size_t operator()(const RuBLE::Descriptor& s) const noexcept;
51
+ };
52
+