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,25 @@
1
+ #cmakedefine EXTENSION_NAME "@EXTENSION_NAME@"
2
+ #cmakedefine EXTENSION_VERSION "@EXTENSION_VERSION@"
3
+ #cmakedefine RUBY_VERSION "@RUBY_VERSION@"
4
+ #cmakedefine RICE_VERSION "@RICE_VERSION@"
5
+
6
+ // TODO: defer to single point of truth re: min ruby version elsewhere.
7
+ // e.g. minimum version already in `.gemspec` and CMakeLists
8
+
9
+ #cmakedefine RUBLE_DEBUG 1
10
+ #cmakedefine HAVE_VALGRIND 1
11
+
12
+ #cmakedefine BOOST_STACKTRACE_USE_BACKTRACE 1
13
+ #cmakedefine BOOST_STACKTRACE_USE_ADDR2LINE 1
14
+ #cmakedefine BOOST_STACKTRACE_USE_BASIC 1
15
+ #cmakedefine BOOST_STACKTRACE_USE_WINDBG 1
16
+ #cmakedefine BOOST_STACKTRACE_USE_WINDBG_CACHED 1
17
+ #cmakedefine BOOST_STACKTRACE_USE_NOOP 1
18
+ #cmakedefine BOOST_STACKTRACE_LINK 1
19
+ #cmakedefine BOOST_STACKTRACE_ADDR2LINE_LOCATION "@BOOST_STACKTRACE_ADDR2LINE_LOCATION@"
20
+ #cmakedefine BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE "@BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE@"
21
+
22
+ #ifdef BOOST_STACKTRACE_LINK
23
+ #define BOOST_ENABLE_ASSERT_DEBUG_HANDLER 1
24
+ #endif
25
+
@@ -0,0 +1,64 @@
1
+ #include "types/declarations.hpp"
2
+ #include "containers/ByteArray.hpp"
3
+
4
+ #include "utils/containers.hpp"
5
+
6
+ namespace RuBLE {
7
+
8
+ ByteArray::ByteArray(Object obj) : ByteArray() {
9
+ if (obj.is_a(rb_cByteArray)) {
10
+ *this = { *ByteArray_DO(obj).get() };
11
+ } else if(obj.is_a(rb_cNumeric)) {
12
+ *this = { rb_num2ulong(obj) };
13
+ } else if (obj.is_a(rb_cString) || obj.is_a(rb_cSymbol)) {
14
+ *this = {Rice::String(obj).str()};
15
+ } else if(obj.is_a(rb_cNilClass) || obj.is_a(rb_cTrueClass) || obj.is_a(rb_cFalseClass)) {
16
+ *this = { obj.test() };
17
+ } else {
18
+ throw std::invalid_argument("Cannot convert "s + obj.inspect().str() + " to a ByteArray");
19
+ }
20
+ }
21
+
22
+ ByteArray ByteArray::from_ruby(Object obj) {
23
+ return { std::move(obj) };
24
+ }
25
+
26
+ std::string ByteArray::to_s() const {
27
+ std::ostringstream oss;
28
+ oss << Utils::basic_object_inspect_start(*this) << " ";
29
+ oss << Utils::to_hex_data(_data);
30
+ oss << " (" << Utils::ruby_quote_string(_data) << ")>";
31
+ return oss.str();
32
+ }
33
+
34
+ std::string ByteArray::inspect() const { return to_s(); }
35
+
36
+ void ByteArray::ruby_mark() const {
37
+ Rubyable::ruby_mark();
38
+ }
39
+
40
+ void Init_ByteArray() {
41
+ rb_cByteArray = define_class_under<ByteArray>(rb_mRuBLE, "ByteArray")
42
+ .define_singleton_function("new", &ByteArray::from_ruby)
43
+ .define_method("get", &ByteArray::to_string)
44
+ .define_method("to_s", &ByteArray::to_s)
45
+ .define_method("inspect", &ByteArray::inspect)
46
+ .define_method("data", &ByteArray::data)
47
+ .define_method("to_i", &ByteArray::to_i<>)
48
+ .define_method("%", &ByteArray::operator%<>)
49
+ .define_method("&", &ByteArray::operator&<>)
50
+ .define_method("|", &ByteArray::operator|<>)
51
+ .define_method("~", &ByteArray::operator~)
52
+ .define_method("!", &ByteArray::operator!)
53
+ .define_method("<=>", &ByteArray::operator<=><>)
54
+ ;
55
+ }
56
+ }
57
+
58
+ //namespace Rice::detail {
59
+ // bool From_Ruby<RuBLE::ByteArray>::can_convert_from_ruby(VALUE obj) {
60
+ // return std::find(supported_ruby_types.cbegin(),
61
+ // supported_ruby_types.cend(),
62
+ // rb_type(obj)) != supported_ruby_types.cend();
63
+ // }
64
+ //}
@@ -0,0 +1,161 @@
1
+ #pragma once
2
+
3
+ #include "types/declarations.hpp"
4
+ #include "types/ruby.hpp"
5
+ #include "types/helpers.hpp"
6
+ #include "utils/containers.hpp"
7
+ #include "utils/hexadecimal.hpp"
8
+ #include "utils/human_type_names.hpp"
9
+ #include "concerns/Rubyable.hpp"
10
+ #include <utility>
11
+ #include <array>
12
+ #include <algorithm>
13
+ #include <compare>
14
+ #include <cstdlib>
15
+ #include <boost/endian/conversion.hpp>
16
+
17
+ namespace RuBLE {
18
+ template<typename T>
19
+ concept UnsignedIntegral = std::is_integral_v<T> && std::is_unsigned_v<T>;
20
+
21
+ // TODO: Need to test this out
22
+ class ByteArray : public Rubyable<ByteArray> {
23
+ public:
24
+ using DataObject = ByteArray_DO;
25
+ private:
26
+ SimpleBLE::ByteArray _data;
27
+
28
+ public:
29
+ using char_type = SimpleBLE::ByteArray::value_type;
30
+ using iterator_diff_type = typename std::iterator_traits<SimpleBLE::ByteArray::const_iterator>::difference_type;
31
+
32
+ static constexpr const std::size_t char_size = sizeof(char_type);
33
+
34
+ template<typename T>
35
+ static constexpr const std::size_t chars_per_val = ([]() -> std::size_t {
36
+ std::size_t quot = sizeof(T) / char_size;
37
+ std::size_t rem = sizeof(T) % char_size;
38
+ return quot + (rem > 0 ? 1 : 0);
39
+ })();
40
+
41
+ using default_integral_type = uint64_t;
42
+
43
+ [[nodiscard]] constexpr ByteArray();
44
+ constexpr ByteArray(SimpleBLE::ByteArray byteArray);
45
+
46
+ ByteArray(Rice::Object obj);
47
+ template<UnsignedIntegral T>
48
+ ByteArray(const T &data) : ByteArray() {
49
+ // TODO: modernize by using std::span
50
+ _data.assign(chars_per_val<T>, '\0');
51
+ UnsignedIntegral auto &dstVal = *reinterpret_cast<T *>(_data.data());
52
+ dstVal = boost::endian::native_to_little(data);
53
+ }
54
+
55
+ constexpr ByteArray(const char_type &chr);
56
+ constexpr ByteArray(const bool &b);
57
+
58
+ static ByteArray from_ruby(Rice::Object obj);
59
+
60
+ [[nodiscard]] constexpr std::size_t length() const { return _data.size(); }
61
+ [[nodiscard]] constexpr std::size_t byte_count() const { return length() * char_size; }
62
+
63
+ template<UnsignedIntegral T>
64
+ constexpr explicit operator T() const { return to_i<T>(); }
65
+
66
+ template<UnsignedIntegral T = default_integral_type>
67
+ constexpr T operator|(const T &other) const { return to_i<T>() | other; }
68
+
69
+ template<UnsignedIntegral T = default_integral_type>
70
+ constexpr T operator&(const T &other) const { return to_i<T>() & other; }
71
+
72
+ template<UnsignedIntegral T = default_integral_type>
73
+ constexpr T operator^(const T &other) const { return to_i<T>() ^ other; }
74
+
75
+ template<UnsignedIntegral T = default_integral_type>
76
+ constexpr T operator%(const T &other) const { return to_i<T>() % other; }
77
+
78
+ constexpr bool operator!() const { return to_i<>() != 0; }
79
+
80
+ constexpr auto operator~() const { return ~to_i<>(); }
81
+
82
+ template<typename T = default_integral_type>
83
+ constexpr int operator<=>(const T &other) const {
84
+ std::strong_ordering result = to_i<T>() <=> other;
85
+ if (result == std::strong_ordering::less) return -1;
86
+ if (result == std::strong_ordering::greater) return 1;
87
+ return 0;
88
+ }
89
+
90
+ constexpr std::strong_ordering operator<=>(const ByteArray &other) const {
91
+ return _data <=> other._data;
92
+ }
93
+ constexpr bool operator==(const ByteArray &other) const {
94
+ auto comparison = *this <=> other;
95
+ return comparison == std::strong_ordering::equivalent || comparison == std::strong_ordering::equal;
96
+ }
97
+
98
+ constexpr bool operator!=(const ByteArray &other) const { return !(*this == other); }
99
+
100
+ [[nodiscard]] constexpr std::string to_string() const { return _data; }
101
+ [[nodiscard]] std::string to_s() const;
102
+ [[nodiscard]] std::string inspect() const;
103
+
104
+ [[nodiscard]] constexpr const SimpleBLE::ByteArray &data() const { return _data; }
105
+
106
+ [[nodiscard]] constexpr const std::byte &operator[](iterator_diff_type pos) const {
107
+ assert(pos < byte_count() && pos >= 0);
108
+ const void *bytesVoid = _data.data();
109
+ const std::byte *bytes = static_cast<const std::byte*>(bytesVoid);
110
+ return bytes[pos];
111
+ }
112
+
113
+ constexpr operator const SimpleBLE::ByteArray &() const { return _data; }
114
+ // TODO: test me!
115
+ template<UnsignedIntegral T = default_integral_type>
116
+ [[nodiscard]] T to_i() const {
117
+ if (sizeof(T) < char_size * length()) {
118
+ static constexpr const auto errfmt = "Integer type %s holds only %ld bytes, "\
119
+ "while %s contains %ld bytes of data. Result will be truncated.";
120
+ rb_warn(errfmt, std::string(Utils::human_type_name<T>()).c_str(), sizeof(T),
121
+ std::string(Utils::human_type_name(*this)).c_str(), char_size * length());
122
+ }
123
+ const UnsignedIntegral auto &val = *reinterpret_cast<const T*>(_data.data());
124
+ return boost::endian::little_to_native(val);
125
+ }
126
+
127
+ void ruby_mark() const;
128
+ };
129
+
130
+ constexpr ByteArray::ByteArray() : _data(), Rubyable<ByteArray>() {}
131
+
132
+ constexpr ByteArray::ByteArray(SimpleBLE::ByteArray byteArray) :
133
+ _data(std::move(byteArray)), Rubyable<ByteArray>() {}
134
+
135
+ constexpr ByteArray::ByteArray(const ByteArray::char_type &chr) : ByteArray(std::string(chr, 1)) {}
136
+
137
+ constexpr ByteArray::ByteArray(const bool &b) : ByteArray(b ? '1' : '0') {}
138
+
139
+
140
+ void Init_ByteArray();
141
+ }
142
+
143
+ //namespace Rice::detail {
144
+ // template<>
145
+ // class From_Ruby<RuBLE::ByteArray> {
146
+ // public:
147
+ // static constexpr const auto supported_ruby_types =
148
+ // std::to_array({T_BIGNUM, T_FIXNUM, T_SYMBOL, T_STRING, T_NIL, T_TRUE, T_FALSE});
149
+ // static bool can_convert_from_ruby(VALUE obj);
150
+ // bool is_convertible(VALUE value) { // NOLINT(*-convert-member-functions-to-static)
151
+ // return can_convert_from_ruby(value);
152
+ // }
153
+ // RuBLE::ByteArray convert(VALUE value) { // NOLINT(*-convert-member-functions-to-static)
154
+ // return RuBLE::ByteArray::from_ruby(value);
155
+ // }
156
+ // };
157
+ //}
158
+
159
+ constexpr std::ostream &operator<<(std::ostream &os, const RuBLE::ByteArray &cba) {
160
+ return os << cba.data();
161
+ }
@@ -0,0 +1,52 @@
1
+ #pragma once
2
+ #include "types/declarations.hpp"
3
+ #include "types/ruby.hpp"
4
+ #include "utils/RubyCallbackTraits.hpp"
5
+ #include "utils/garbage_collection.hpp"
6
+
7
+ using namespace std::string_literals;
8
+ namespace RuBLE {
9
+ struct Callback {
10
+ protected:
11
+ std::size_t _arg_count;
12
+ VALUE _cb = Qnil;
13
+ public:
14
+ explicit Callback(const std::size_t &arg_count) : _arg_count(arg_count) {}
15
+
16
+ // TODO: confirm this is a proc (taking the right number of args)
17
+ constexpr void set(VALUE cb) {
18
+ Ruby::CallbackTraits::assert_accepts_n_args(cb, _arg_count, true);
19
+ _cb = cb;
20
+ }
21
+
22
+ [[maybe_unused]] [[nodiscard]] constexpr const std::size_t &arg_count() const { return _arg_count; }
23
+
24
+ [[maybe_unused]] constexpr void clear() { set(Qnil); }
25
+
26
+ template<class... Types>
27
+ Object fire(const Types& ...args) {
28
+ if constexpr (DEBUG) assert(sizeof...(Types) == arg_count());
29
+
30
+ Object cb(_cb);
31
+ if (!cb.test()) return Qnil;
32
+ const std::initializer_list<Object> argList { args... };
33
+ Rice::Array argArray(argList.begin(), argList.end());
34
+ return cb.vcall("call", argArray);
35
+ }
36
+
37
+ constexpr operator bool() const {
38
+ return _cb != Qnil && _cb != Qfalse;
39
+ }
40
+
41
+ constexpr void ruby_mark() const {
42
+ if (*this) rb_gc_mark(_cb);
43
+ }
44
+ };
45
+ }
46
+
47
+ namespace Rice {
48
+ template<>
49
+ constexpr void ruby_mark<RuBLE::Callback>(RuBLE::Callback *cb) { cb->ruby_mark(); }
50
+ }
51
+
52
+
@@ -0,0 +1,140 @@
1
+ #pragma once
2
+
3
+ #include <cstddef>
4
+ #include <map>
5
+ #include <bitset>
6
+ #include <utility>
7
+ #include <functional>
8
+ #include <variant>
9
+ #include <string_view>
10
+ #include <ranges>
11
+ #include "utils/containers.hpp"
12
+
13
+ #include "types/helpers.hpp"
14
+
15
+ namespace RuBLE {
16
+ template<const auto &FIELD_NAMES> class NamedBitSet;
17
+ }
18
+
19
+ template<const auto &FIELDS> struct std::hash<RuBLE::NamedBitSet<FIELDS>> {
20
+ constexpr std::size_t operator()(const RuBLE::NamedBitSet<FIELDS> &nbs) const noexcept;
21
+ };
22
+
23
+ namespace RuBLE {
24
+ // this namespace from https://en.cppreference.com/w/cpp/utility/variant/visit
25
+ namespace visit {
26
+ template<class... Ts>
27
+ struct overloaded : Ts... { using Ts::operator()...; };
28
+ #if !defined(__cpp_deduction_guides) || __cpp_deduction_guides < 201907L
29
+ // explicit deduction guide (not needed as of C++20)
30
+ template<class... Ts>
31
+ overloaded(Ts...) -> overloaded<Ts...>;
32
+ #endif
33
+ }
34
+
35
+ namespace FlagCheck {
36
+ using ConstFlag = bool;
37
+ using StaticFn = const std::function<bool()>;
38
+ template<class T> using ConstMemFn = std::function<bool(const std::remove_cvref_t<T>&)>;
39
+
40
+ template<class T = nullptr_t>
41
+ using Fn = std::variant<ConstFlag, StaticFn, ConstMemFn<T>>;
42
+
43
+ using MapKey = std::string_view;
44
+ template<class T = nullptr_t> using MapType = std::map<MapKey, Fn<T>>;
45
+
46
+ template<class R, class T>
47
+ concept Map = requires(const R &r, T &t) {
48
+ { std::get<0>(*r.begin()) } -> std::convertible_to<const MapKey>;
49
+ { std::get<1>(*r.begin()) } -> std::convertible_to<Fn<T>>;
50
+ };
51
+
52
+ #ifdef NBSDEBUG
53
+ template<class T = nullptr_t> using Pair = std::pair<const MapKey, Fn<T>>;
54
+ template<class T> using MapPairType = FlagCheck::Pair<T>;
55
+ template <class R> using RangeIteratorType = std::result_of_t<decltype(&R::cbegin)(R)>;
56
+ template<class R> using RangeItem = std::result_of_t<decltype(&RangeIteratorType<R>::operator*)(RangeIteratorType<R>)>;
57
+ template<class R> using RangeItemNoRef = std::remove_reference_t<RangeItem<R>>;
58
+ template<class R> using RangeItemKey = RangeItemNoRef<R>::first_type;
59
+ template<class R> using RangeItemValue = RangeItemNoRef<R>::second_type;
60
+ static_assert(std::is_same_v<MapType<int>::value_type, Pair<int>>);
61
+ static_assert(std::is_convertible_v<RangeItem<MapType<int>>, MapPairType<int>>);
62
+ static_assert(std::is_convertible_v<RangeItemKey<MapType<int>>, const MapKey&>);
63
+ static_assert(Map<MapType<int>, int>);
64
+ #endif
65
+
66
+ template<class T>
67
+ bool test_flag(const FlagCheck::Fn<T> &fn, const auto &obj = nullptr) {
68
+ bool result = std::visit(visit::overloaded{
69
+ []() -> bool { return false; },
70
+ [](nullptr_t) -> bool { return false; },
71
+ [](const FlagCheck::ConstFlag &val) -> bool { return val; },
72
+ [](const FlagCheck::StaticFn &fn) -> bool { return fn(); },
73
+ [&obj](const std::function<bool(const T&)> &fn) -> bool {
74
+ return fn(obj);
75
+ },
76
+ }, fn);
77
+ return result;
78
+ }
79
+
80
+ }
81
+ template<const auto& FIELD_NAMES>
82
+ class NamedBitSet {
83
+ public:
84
+ static constexpr auto FIELDS = std::to_array<const std::string_view>(FIELD_NAMES);
85
+ static constexpr const std::size_t N = FIELDS.size();
86
+ using BitSet = std::bitset<N>;
87
+ using BitRef = BitSet::reference;
88
+ using PairType = std::pair<std::string_view, std::size_t>;
89
+ static constexpr auto PAIRS = ([]<std::size_t... I>(std::index_sequence<I...>) -> std::array<PairType, N> {
90
+ return {std::make_pair(FIELD_NAMES[I], I)...};
91
+ })(std::make_index_sequence<N>{});
92
+
93
+ static constexpr std::size_t index_of(const std::string_view &name);
94
+
95
+ private:
96
+ BitSet _bits = 0;
97
+
98
+ public:
99
+ constexpr const BitSet &bits() const;
100
+
101
+ constexpr BitRef operator[](const std::string_view &name);
102
+
103
+ constexpr bool operator[](const std::string_view &name) const;
104
+
105
+ // Ensure T is an integral type that can hold all N bits
106
+ template<typename T> requires std::is_integral_v<T> && (std::numeric_limits<T>::max() >= (1 << N) - 1)
107
+ constexpr explicit operator T() const { return static_cast<T>(_bits.to_ullong()); }
108
+
109
+ [[nodiscard]] constexpr std::vector<std::string_view> flag_names() const;
110
+
111
+ [[nodiscard]] constexpr std::vector<std::string> flag_name_strs() const;
112
+
113
+ constexpr NamedBitSet(): _bits(0) {}
114
+
115
+ constexpr NamedBitSet(const std::initializer_list<const std::string_view> &list);
116
+
117
+ constexpr NamedBitSet(const auto &rangeList);
118
+ constexpr NamedBitSet(const BitSet &bitSet);
119
+ // Takes a map (or equivalent) of 'std::string_view's to one of: boolean literal, static fn, const mem fn, mem fn
120
+ template<typename ObjT, FlagCheck::Map<ObjT> R>
121
+ constexpr NamedBitSet(R &r, ObjT &&obj);
122
+
123
+ [[nodiscard]] constexpr std::string to_s() const;
124
+ };
125
+
126
+
127
+
128
+ #ifdef RUBLE_DEBUG
129
+ void NamedBitSetDemo();
130
+ #endif
131
+ }
132
+
133
+ template<const auto &FIELDS>
134
+ constexpr std::size_t std::hash<RuBLE::NamedBitSet<FIELDS>>::operator()(const RuBLE::NamedBitSet<FIELDS> &nbs) const noexcept {
135
+ std::size_t h1 = typeid(nbs).hash_code();
136
+ static auto hasher = std::hash<decltype(RuBLE::NamedBitSet<FIELDS>::BitSet)>{};
137
+ return h1 ^ (hasher(nbs.bits()) << 1);
138
+ }
139
+
140
+ #include "NamedBitSet.ipp"
@@ -0,0 +1,71 @@
1
+ #pragma once
2
+
3
+ #include "types/declarations.hpp"
4
+ #include "NamedBitSet.hpp"
5
+
6
+ #include <string>
7
+ #include "utils/containers.hpp"
8
+ using namespace std::string_literals;
9
+
10
+ namespace RuBLE {
11
+ template<const auto &FIELD_NAMES>
12
+ constexpr std::string NamedBitSet<FIELD_NAMES>::to_s() const { return Utils::join(flag_names(), "|"); }
13
+
14
+ template<const auto &FIELD_NAMES>
15
+ template<typename ObjT, FlagCheck::Map<ObjT> R>
16
+ [[maybe_unused]]
17
+ constexpr NamedBitSet<FIELD_NAMES>::NamedBitSet(R &r, ObjT &&obj) {
18
+ for (const auto &[name, fn] : r) (*this)[name] = FlagCheck::test_flag<ObjT>(fn, obj);
19
+ }
20
+
21
+ template<const auto &FIELD_NAMES>
22
+ constexpr NamedBitSet<FIELD_NAMES>::NamedBitSet(const NamedBitSet::BitSet &bitSet) : _bits(bitSet) {}
23
+
24
+ template<const auto &FIELD_NAMES>
25
+ constexpr NamedBitSet<FIELD_NAMES>::NamedBitSet(const auto &rangeList) {
26
+ for (const auto &sv: rangeList) (*this)[sv] = true;
27
+ }
28
+
29
+ template<const auto &FIELD_NAMES>
30
+ constexpr NamedBitSet<FIELD_NAMES>::NamedBitSet(const std::initializer_list<const std::string_view> &list) {
31
+ for (const auto &sv: list) (*this)[sv] = true;
32
+ }
33
+
34
+ template<const auto &FIELD_NAMES>
35
+ constexpr std::vector<std::string> NamedBitSet<FIELD_NAMES>::flag_name_strs() const {
36
+ const auto names = flag_names();
37
+ return { names.begin(), names.end() };
38
+ }
39
+
40
+ template<const auto &FIELD_NAMES>
41
+ constexpr std::vector<std::string_view> NamedBitSet<FIELD_NAMES>::flag_names() const {
42
+ std::vector<std::string_view> result;
43
+ for (const auto &[name, idx]: PAIRS) {
44
+ if (_bits[idx]) result.push_back(name);
45
+ }
46
+ return result;
47
+ }
48
+
49
+
50
+ template<const auto &FIELD_NAMES>
51
+ constexpr bool NamedBitSet<FIELD_NAMES>::operator[](const std::string_view &name) const {
52
+ return _bits[index_of(name)];
53
+ }
54
+
55
+ template<const auto &FIELD_NAMES>
56
+ constexpr NamedBitSet<FIELD_NAMES>::BitRef NamedBitSet<FIELD_NAMES>::operator[](const std::string_view &name) {
57
+ return _bits[index_of(name)];
58
+ }
59
+
60
+ template<const auto &FIELD_NAMES>
61
+ constexpr const NamedBitSet<FIELD_NAMES>::BitSet &NamedBitSet<FIELD_NAMES>::bits() const { return _bits; }
62
+
63
+ template<const auto &FIELD_NAMES>
64
+ constexpr std::size_t NamedBitSet<FIELD_NAMES>::index_of(const std::string_view &name) {
65
+ for (const auto &[field, idx]: PAIRS) {
66
+ if (field == name) return idx;
67
+ }
68
+ std::string errmsg = "Invalid field name "s + std::string(name.data()) + " in call to index_of";
69
+ throw std::invalid_argument(errmsg);
70
+ }
71
+ }
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # FIXME: This won't work because extensions aren't built from inside the gem dir when installed
4
+ # ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __dir__)
5
+ # require "bundler/setup" # Set up gems listed in the Gemfile.
6
+ Bundler.require(:build)
7
+ require_relative '../../lib/ruble/build'
8
+
9
+ require 'mkmf-rice'
10
+ # TODO(?): see what https://rubygems.org/gems/autobuild has to offer
11
+
12
+ # noinspection RubyMismatchedArgumentType
13
+ THIS_DIR = Pathname.new(__dir__)
14
+
15
+ @generator = RuBLE::Build::Extconf.instance
16
+ require 'debug' if @generator.debug_mode?
17
+
18
+ @generator.write_build_config(path: THIS_DIR / 'build-config.cmake')
19
+
20
+ # TODO: need to confirm the values (for install dir, compile args, etc) outputted in Makefile
21
+ # are the same values CMake gets from parsing 'build-config.json'
22
+ # TODO: confirm dummy_makefile isn't missing any needed fields
23
+ # currently, I don't see where the build dir is set
24
+
25
+ create_makefile 'ruble'
26
+ File.open(THIS_DIR / 'Makefile', 'at') do |f|
27
+ #f.puts 'include cmake.mk'
28
+ end
29
+
30
+ # TODO: does setting TARGET_ENTRY in makefile do anything? (if so, use it)
@@ -0,0 +1,63 @@
1
+ #include "types/declarations.hpp"
2
+ #include "bindings/Adapter.hpp"
3
+ #include "bindings/Peripheral.hpp"
4
+ #include "management/Registry.hpp"
5
+ #include "management/RegistryFactory.hpp"
6
+ #include "bindings/Service.hpp"
7
+ #include "bindings/Characteristic.hpp"
8
+
9
+ namespace RuBLE {
10
+
11
+ void Init_Registries() {
12
+ rb_cAdapterRegistry = define_class_under<AdapterRegistry>(rb_mRuBLE, "AdapterRegistry")
13
+ .define_method("size", &AdapterRegistry::size)
14
+ .define_method("to_s", &AdapterRegistry::to_s);
15
+ define_map_under<AdapterRegistry::Collection>(rb_cAdapterRegistry, "Map");
16
+
17
+ if (!adapterRegistryFactory) adapterRegistryFactory = AdapterRegistryFactory::instance();
18
+ if (!adapterRegistry) adapterRegistry = adapterRegistryFactory->registry();
19
+ rb_cAdapterRegistry.define_singleton_attr("registry", &*adapterRegistry, Rice::AttrAccess::Read);
20
+ rb_cAdapterRegistry.iv_set("@registry", *adapterRegistry->_registry);
21
+
22
+ rb_cPeripheralRegistry = define_class_under<PeripheralRegistry>(rb_mRuBLE, "PeripheralRegistry")
23
+ .define_method("to_s", &PeripheralRegistry::to_s)
24
+ .define_method("size", &PeripheralRegistry::size);
25
+
26
+ rb_cAdapter
27
+ .define_attr("peripheral_registry", &Adapter::_peripheral_registry, Rice::AttrAccess::Read);
28
+
29
+ if (!peripheralRegistryFactory) peripheralRegistryFactory = PeripheralRegistryFactory::instance();
30
+
31
+ rb_cServiceRegistry = define_class_under<ServiceRegistry>(rb_mRuBLE, "ServiceRegistry")
32
+ .define_method("to_s", &ServiceRegistry::to_s)
33
+ .define_method("size", &ServiceRegistry::size);
34
+
35
+ define_map_under<Peripheral::ServiceMap>(rb_cPeripheral, "ServiceMap");
36
+ rb_cPeripheral
37
+ .define_method("services", &Peripheral::services)
38
+ .define_method("[]", &Peripheral::operator[])
39
+ .define_attr("service_registry", &Peripheral::_service_registry, Rice::AttrAccess::Read)
40
+ ;
41
+ if (!serviceRegistryFactory) serviceRegistryFactory = ServiceRegistryFactory::instance();
42
+
43
+ rb_cCharacteristicRegistry = define_class_under<CharacteristicRegistry>(rb_mRuBLE, "CharacteristicRegistry")
44
+ .define_method("to_s", &ServiceRegistry::to_s)
45
+ .define_method("size", &ServiceRegistry::size);
46
+
47
+ define_map_under<CharacteristicRegistry::Collection>(rb_cService, "CharacteristicMap");
48
+ rb_cService
49
+ .define_method("characteristics", &Service::characteristics)
50
+ .define_method("[]", &Service::operator[])
51
+ .define_attr("characteristic_registry", &Service::_characteristic_registry, Rice::AttrAccess::Read);
52
+
53
+ if (!characteristicRegistryFactory) characteristicRegistryFactory = CharacteristicRegistryFactory ::instance();
54
+ define_map_under<Characteristic::DescriptorMap>(rb_cCharacteristic, "DescriptorMap");
55
+ rb_cCharacteristic
56
+ .define_method("descriptors", &Characteristic::descriptors)
57
+ .define_method("[]", &Characteristic::operator[])
58
+ .define_attr("descriptors", &Characteristic::_descriptors, Rice::AttrAccess::Read);
59
+
60
+ }
61
+
62
+ }
63
+