ruble 0.0.3.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gdbinit +21 -0
- data/.gitignore +18 -0
- data/.rubocop.yml +96 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +6 -0
- data/CMakeLists.txt +4 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +98 -0
- data/LICENSE.txt +21 -0
- data/README.md +63 -0
- data/Rakefile +41 -0
- data/ext/ruble/.gitignore +5 -0
- data/ext/ruble/CMakeLists.txt +157 -0
- data/ext/ruble/RuBLEHelpers.cmake +240 -0
- data/ext/ruble/bindings/Adapter.cpp +193 -0
- data/ext/ruble/bindings/Adapter.hpp +85 -0
- data/ext/ruble/bindings/Characteristic.cpp +171 -0
- data/ext/ruble/bindings/Characteristic.hpp +132 -0
- data/ext/ruble/bindings/Descriptor.cpp +34 -0
- data/ext/ruble/bindings/Descriptor.hpp +69 -0
- data/ext/ruble/bindings/Peripheral.cpp +212 -0
- data/ext/ruble/bindings/Peripheral.hpp +108 -0
- data/ext/ruble/bindings/RuBLE.cpp +115 -0
- data/ext/ruble/bindings/Service.cpp +112 -0
- data/ext/ruble/bindings/Service.hpp +61 -0
- data/ext/ruble/bindings/common.hpp +48 -0
- data/ext/ruble/bindings/globals.cpp +43 -0
- data/ext/ruble/cmake.mk +62 -0
- data/ext/ruble/concerns/CharacteristicValueTracker.cpp +18 -0
- data/ext/ruble/concerns/CharacteristicValueTracker.hpp +40 -0
- data/ext/ruble/concerns/Rubyable.cpp +4 -0
- data/ext/ruble/concerns/Rubyable.hpp +46 -0
- data/ext/ruble/config.h.in +25 -0
- data/ext/ruble/containers/ByteArray.cpp +64 -0
- data/ext/ruble/containers/ByteArray.hpp +161 -0
- data/ext/ruble/containers/Callback.hpp +52 -0
- data/ext/ruble/containers/NamedBitSet.hpp +140 -0
- data/ext/ruble/containers/NamedBitSet.ipp +71 -0
- data/ext/ruble/extconf.rb +30 -0
- data/ext/ruble/management/Registry.cpp +63 -0
- data/ext/ruble/management/Registry.hpp +170 -0
- data/ext/ruble/management/RegistryFactory.hpp +113 -0
- data/ext/ruble/management/RubyQueue.cpp +152 -0
- data/ext/ruble/management/RubyQueue.hpp +69 -0
- data/ext/ruble/modularize.diff +28 -0
- data/ext/ruble/types/SimpleBLE.hpp +21 -0
- data/ext/ruble/types/declarations.hpp +91 -0
- data/ext/ruble/types/helpers.hpp +12 -0
- data/ext/ruble/types/ruby.hpp +36 -0
- data/ext/ruble/types/stl.hpp +41 -0
- data/ext/ruble/utils/RubyCallbackTraits.cpp +28 -0
- data/ext/ruble/utils/RubyCallbackTraits.hpp +48 -0
- data/ext/ruble/utils/async.cpp +10 -0
- data/ext/ruble/utils/async.hpp +76 -0
- data/ext/ruble/utils/containers.hpp +41 -0
- data/ext/ruble/utils/exception_handling.cpp +50 -0
- data/ext/ruble/utils/exception_handling.hpp +53 -0
- data/ext/ruble/utils/garbage_collection.cpp +82 -0
- data/ext/ruble/utils/garbage_collection.hpp +22 -0
- data/ext/ruble/utils/hash.cpp +83 -0
- data/ext/ruble/utils/hash.hpp +52 -0
- data/ext/ruble/utils/hexadecimal.hpp +116 -0
- data/ext/ruble/utils/human_type_names.hpp +38 -0
- data/ext/ruble/utils/inspection.cpp +24 -0
- data/ext/ruble/utils/inspection.hpp +108 -0
- data/ext/ruble/utils/ruby.hpp +103 -0
- data/ext/ruble/utils/ruby_context.hpp +73 -0
- data/lib/ruble/build/.rubocop.yml +19 -0
- data/lib/ruble/build/boost.rb +34 -0
- data/lib/ruble/build/cmake.rb +134 -0
- data/lib/ruble/build/core_ext.rb +5 -0
- data/lib/ruble/build/data/bundler.rb +24 -0
- data/lib/ruble/build/data/extension.rb +101 -0
- data/lib/ruble/build/data/os.rb +21 -0
- data/lib/ruble/build/data/rice.rb +24 -0
- data/lib/ruble/build/data.rb +22 -0
- data/lib/ruble/build/extconf.rb +76 -0
- data/lib/ruble/build/github_repo.rb +129 -0
- data/lib/ruble/build/simpleble.rb +56 -0
- data/lib/ruble/build.rb +28 -0
- data/lib/ruble/version.rb +7 -0
- data/lib/ruble.rb +46 -0
- data/lib/tasks/dev/dev_tasks.rb +130 -0
- data/lib/tasks/dev/pager.rb +218 -0
- data/lib/tasks/dev/paths.rb +30 -0
- data/lib/tasks/dev/state_hash.rb +65 -0
- data/lib/tasks/dev.rake +41 -0
- data/lib/tasks/simpleble.rake +29 -0
- data/sig/rubble.rbs +4 -0
- 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,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
|
+
|