ruble 0.0.3.alpha
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|