@reactiive/ennio 0.0.1
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.
- package/EnnioCore.podspec +61 -0
- package/LICENSE +21 -0
- package/README.md +50 -0
- package/android/CMakeLists.txt +40 -0
- package/android/build.gradle +64 -0
- package/cpp/ElementMatcher.cpp +661 -0
- package/cpp/ElementMatcher.hpp +244 -0
- package/cpp/EnnioLog.hpp +182 -0
- package/cpp/HybridEnnio.cpp +1161 -0
- package/cpp/HybridEnnio.hpp +174 -0
- package/cpp/IdleMonitor.hpp +277 -0
- package/cpp/Protocol.cpp +135 -0
- package/cpp/Protocol.hpp +47 -0
- package/cpp/SelectorCriteria.hpp +281 -0
- package/cpp/SelectorParser.cpp +649 -0
- package/cpp/SelectorParser.hpp +94 -0
- package/cpp/ShadowTreeTraverser.cpp +305 -0
- package/cpp/ShadowTreeTraverser.hpp +142 -0
- package/cpp/TestIDRegistry.cpp +109 -0
- package/cpp/TestIDRegistry.hpp +84 -0
- package/dist/cli.js +16221 -0
- package/ios/EnnioAutoInit.mm +338 -0
- package/ios/EnnioDebugBanner.h +19 -0
- package/ios/EnnioDebugBanner.mm +178 -0
- package/ios/EnnioRuntimeHelper.h +264 -0
- package/ios/EnnioRuntimeHelper.mm +2443 -0
- package/lib/Ennio.nitro.d.ts +263 -0
- package/lib/Ennio.nitro.d.ts.map +1 -0
- package/lib/Ennio.nitro.js +2 -0
- package/lib/Ennio.nitro.js.map +1 -0
- package/lib/index.d.ts +16 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +45 -0
- package/lib/index.js.map +1 -0
- package/nitro.json +24 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/android/EnnioCore+autolinking.cmake +81 -0
- package/nitrogen/generated/android/EnnioCore+autolinking.gradle +27 -0
- package/nitrogen/generated/android/EnnioCoreOnLoad.cpp +49 -0
- package/nitrogen/generated/android/EnnioCoreOnLoad.hpp +34 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/ennio/EnnioCoreOnLoad.kt +35 -0
- package/nitrogen/generated/ios/EnnioCore+autolinking.rb +62 -0
- package/nitrogen/generated/ios/EnnioCore-Swift-Cxx-Bridge.cpp +17 -0
- package/nitrogen/generated/ios/EnnioCore-Swift-Cxx-Bridge.hpp +27 -0
- package/nitrogen/generated/ios/EnnioCore-Swift-Cxx-Umbrella.hpp +38 -0
- package/nitrogen/generated/ios/EnnioCoreAutolinking.mm +35 -0
- package/nitrogen/generated/ios/EnnioCoreAutolinking.swift +16 -0
- package/nitrogen/generated/shared/c++/ExtendedElementInfo.hpp +118 -0
- package/nitrogen/generated/shared/c++/HybridEnnioSpec.cpp +44 -0
- package/nitrogen/generated/shared/c++/HybridEnnioSpec.hpp +93 -0
- package/nitrogen/generated/shared/c++/LayoutMetrics.hpp +103 -0
- package/nitrogen/generated/shared/c++/ScrollDirection.hpp +84 -0
- package/package.json +78 -0
- package/react-native.config.js +14 -0
- package/src/Ennio.nitro.ts +363 -0
- package/src/cli/hid-daemon.py +129 -0
- package/src/index.ts +72 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "SelectorCriteria.hpp"
|
|
4
|
+
#include "ShadowTreeTraverser.hpp"
|
|
5
|
+
#include "TestIDRegistry.hpp"
|
|
6
|
+
|
|
7
|
+
#include <memory>
|
|
8
|
+
#include <optional>
|
|
9
|
+
#include <regex>
|
|
10
|
+
#include <string>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
#include <react/renderer/core/ShadowNode.h>
|
|
14
|
+
|
|
15
|
+
namespace ennio {
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Extended element info with additional state properties
|
|
19
|
+
*/
|
|
20
|
+
struct ExtendedElementInfo : public ElementInfo {
|
|
21
|
+
bool checked = false;
|
|
22
|
+
bool focused = false;
|
|
23
|
+
bool selected = false;
|
|
24
|
+
|
|
25
|
+
// Parent tracking for childOf queries
|
|
26
|
+
const facebook::react::ShadowNode* parent = nullptr;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* ElementMatcher - Multi-criteria element matching engine
|
|
31
|
+
*
|
|
32
|
+
* Optimized matching with:
|
|
33
|
+
* - O(1) fast path for id-only selectors via TestIDRegistry
|
|
34
|
+
* - Efficient spatial matching using pre-computed reference positions
|
|
35
|
+
* - Parent chain tracking for hierarchical queries
|
|
36
|
+
*/
|
|
37
|
+
class ElementMatcher {
|
|
38
|
+
public:
|
|
39
|
+
using ShadowNodePtr = std::shared_ptr<const facebook::react::ShadowNode>;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Find the first element matching the criteria
|
|
43
|
+
*
|
|
44
|
+
* @param root - Shadow tree root
|
|
45
|
+
* @param criteria - Selection criteria
|
|
46
|
+
* @return Matching node or nullptr
|
|
47
|
+
*/
|
|
48
|
+
static ShadowNodePtr findFirst(
|
|
49
|
+
ShadowNodePtr root,
|
|
50
|
+
const SelectorCriteria& criteria
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Find all elements matching the criteria
|
|
55
|
+
*
|
|
56
|
+
* @param root - Shadow tree root
|
|
57
|
+
* @param criteria - Selection criteria
|
|
58
|
+
* @return Vector of matching nodes
|
|
59
|
+
*/
|
|
60
|
+
static std::vector<ShadowNodePtr> findAll(
|
|
61
|
+
ShadowNodePtr root,
|
|
62
|
+
const SelectorCriteria& criteria
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get extended element info including state properties
|
|
67
|
+
*/
|
|
68
|
+
static std::optional<ExtendedElementInfo> getExtendedElementInfo(
|
|
69
|
+
ShadowNodePtr root,
|
|
70
|
+
ShadowNodePtr node
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
private:
|
|
74
|
+
/**
|
|
75
|
+
* Context for matching operations
|
|
76
|
+
*/
|
|
77
|
+
struct MatchContext {
|
|
78
|
+
ShadowNodePtr root;
|
|
79
|
+
float screenWidth = 430.0f;
|
|
80
|
+
float screenHeight = 932.0f;
|
|
81
|
+
|
|
82
|
+
// Resolved reference elements for spatial queries
|
|
83
|
+
std::optional<LayoutMetrics> belowRef;
|
|
84
|
+
std::optional<LayoutMetrics> aboveRef;
|
|
85
|
+
std::optional<LayoutMetrics> leftOfRef;
|
|
86
|
+
std::optional<LayoutMetrics> rightOfRef;
|
|
87
|
+
|
|
88
|
+
// Parent tracking
|
|
89
|
+
std::vector<const facebook::react::ShadowNode*> parentChain;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Resolve spatial reference elements
|
|
94
|
+
*/
|
|
95
|
+
static void resolveSpatialRefs(
|
|
96
|
+
const SelectorCriteria& criteria,
|
|
97
|
+
MatchContext& ctx
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Check if a node matches all criteria
|
|
102
|
+
*/
|
|
103
|
+
static bool matches(
|
|
104
|
+
ShadowNodePtr node,
|
|
105
|
+
const SelectorCriteria& criteria,
|
|
106
|
+
const MatchContext& ctx
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Match primary criteria (id, text, point)
|
|
111
|
+
*/
|
|
112
|
+
static bool matchesPrimary(
|
|
113
|
+
ShadowNodePtr node,
|
|
114
|
+
const SelectorCriteria& criteria
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Match text with different modes
|
|
119
|
+
*/
|
|
120
|
+
static bool matchesText(
|
|
121
|
+
const std::string& actual,
|
|
122
|
+
const TextMatcher& matcher
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Match state criteria (enabled, checked, focused, selected)
|
|
127
|
+
*/
|
|
128
|
+
static bool matchesState(
|
|
129
|
+
ShadowNodePtr node,
|
|
130
|
+
const SelectorCriteria& criteria
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Match spatial criteria (below, above, leftOf, rightOf)
|
|
135
|
+
*/
|
|
136
|
+
static bool matchesSpatial(
|
|
137
|
+
ShadowNodePtr node,
|
|
138
|
+
const LayoutMetrics& nodeMetrics,
|
|
139
|
+
const MatchContext& ctx
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Check if candidate is below reference
|
|
144
|
+
*/
|
|
145
|
+
static bool isBelow(const LayoutMetrics& candidate, const LayoutMetrics& reference);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if candidate is above reference
|
|
149
|
+
*/
|
|
150
|
+
static bool isAbove(const LayoutMetrics& candidate, const LayoutMetrics& reference);
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Check if candidate is left of reference
|
|
154
|
+
*/
|
|
155
|
+
static bool isLeftOf(const LayoutMetrics& candidate, const LayoutMetrics& reference);
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Check if candidate is right of reference
|
|
159
|
+
*/
|
|
160
|
+
static bool isRightOf(const LayoutMetrics& candidate, const LayoutMetrics& reference);
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Match hierarchical criteria (containsChild, childOf, containsDescendants)
|
|
164
|
+
*/
|
|
165
|
+
static bool matchesHierarchical(
|
|
166
|
+
ShadowNodePtr node,
|
|
167
|
+
const SelectorCriteria& criteria,
|
|
168
|
+
const MatchContext& ctx
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Check if node contains a direct child matching criteria
|
|
173
|
+
*/
|
|
174
|
+
static bool containsChild(
|
|
175
|
+
ShadowNodePtr node,
|
|
176
|
+
const SelectorCriteria& criteria,
|
|
177
|
+
const MatchContext& ctx
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Check if node is a child of an element matching criteria
|
|
182
|
+
*/
|
|
183
|
+
static bool isChildOf(
|
|
184
|
+
const std::vector<const facebook::react::ShadowNode*>& parentChain,
|
|
185
|
+
const SelectorCriteria& criteria,
|
|
186
|
+
const MatchContext& ctx
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Check if node contains all descendants matching each criteria
|
|
191
|
+
*/
|
|
192
|
+
static bool containsDescendants(
|
|
193
|
+
ShadowNodePtr node,
|
|
194
|
+
const std::vector<SelectorCriteriaPtr>& criteria,
|
|
195
|
+
const MatchContext& ctx
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Match dimension criteria (width, height with tolerance)
|
|
200
|
+
*/
|
|
201
|
+
static bool matchesDimensions(
|
|
202
|
+
const LayoutMetrics& metrics,
|
|
203
|
+
const SelectorCriteria& criteria
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Match trait criteria
|
|
208
|
+
*/
|
|
209
|
+
static bool matchesTraits(
|
|
210
|
+
ShadowNodePtr node,
|
|
211
|
+
const LayoutMetrics& metrics,
|
|
212
|
+
const std::vector<Trait>& traits
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Get the layout metrics for a node
|
|
217
|
+
*/
|
|
218
|
+
static std::optional<LayoutMetrics> getNodeMetrics(
|
|
219
|
+
ShadowNodePtr root,
|
|
220
|
+
ShadowNodePtr node
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Extract state properties from node props
|
|
225
|
+
*/
|
|
226
|
+
static void extractStateProps(
|
|
227
|
+
ShadowNodePtr node,
|
|
228
|
+
bool& outChecked,
|
|
229
|
+
bool& outFocused,
|
|
230
|
+
bool& outSelected
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Collect all matching nodes via tree traversal
|
|
235
|
+
*/
|
|
236
|
+
static void collectMatches(
|
|
237
|
+
ShadowNodePtr node,
|
|
238
|
+
const SelectorCriteria& criteria,
|
|
239
|
+
MatchContext& ctx,
|
|
240
|
+
std::vector<ShadowNodePtr>& results
|
|
241
|
+
);
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
} // namespace ennio
|
package/cpp/EnnioLog.hpp
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <sstream>
|
|
5
|
+
#include <iostream>
|
|
6
|
+
#include <chrono>
|
|
7
|
+
#include <iomanip>
|
|
8
|
+
|
|
9
|
+
namespace ennio {
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Log levels for Ennio debugging
|
|
13
|
+
*/
|
|
14
|
+
enum class LogLevel {
|
|
15
|
+
Error = 0,
|
|
16
|
+
Warn = 1,
|
|
17
|
+
Info = 2,
|
|
18
|
+
Debug = 3,
|
|
19
|
+
Trace = 4
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* EnnioLog provides structured logging for the native module.
|
|
24
|
+
*
|
|
25
|
+
* Logging is controlled by the ENNIO_DEBUG environment variable:
|
|
26
|
+
* - Not set or "0": No logging
|
|
27
|
+
* - "1": Error and Warn only
|
|
28
|
+
* - "2": Info level
|
|
29
|
+
* - "3": Debug level
|
|
30
|
+
* - "4": Trace level (verbose)
|
|
31
|
+
*
|
|
32
|
+
* In a compiled app, use ENNIO_DEBUG preprocessor flag.
|
|
33
|
+
*/
|
|
34
|
+
class EnnioLog {
|
|
35
|
+
public:
|
|
36
|
+
/**
|
|
37
|
+
* Get the current log level
|
|
38
|
+
*/
|
|
39
|
+
static LogLevel getLevel() {
|
|
40
|
+
#ifdef ENNIO_DEBUG
|
|
41
|
+
#if ENNIO_DEBUG >= 4
|
|
42
|
+
return LogLevel::Trace;
|
|
43
|
+
#elif ENNIO_DEBUG >= 3
|
|
44
|
+
return LogLevel::Debug;
|
|
45
|
+
#elif ENNIO_DEBUG >= 2
|
|
46
|
+
return LogLevel::Info;
|
|
47
|
+
#elif ENNIO_DEBUG >= 1
|
|
48
|
+
return LogLevel::Warn;
|
|
49
|
+
#else
|
|
50
|
+
return LogLevel::Error;
|
|
51
|
+
#endif
|
|
52
|
+
#else
|
|
53
|
+
// In release builds, default to no logging
|
|
54
|
+
return LogLevel::Error;
|
|
55
|
+
#endif
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check if a log level is enabled
|
|
60
|
+
*/
|
|
61
|
+
static bool isEnabled(LogLevel level) {
|
|
62
|
+
return static_cast<int>(level) <= static_cast<int>(getLevel());
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Log a message at the given level
|
|
67
|
+
*/
|
|
68
|
+
static void log(LogLevel level, const std::string& tag, const std::string& message) {
|
|
69
|
+
if (!isEnabled(level)) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Get timestamp
|
|
74
|
+
auto now = std::chrono::system_clock::now();
|
|
75
|
+
auto time = std::chrono::system_clock::to_time_t(now);
|
|
76
|
+
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
77
|
+
now.time_since_epoch()
|
|
78
|
+
).count() % 1000;
|
|
79
|
+
|
|
80
|
+
// Get level string
|
|
81
|
+
const char* levelStr = "???";
|
|
82
|
+
switch (level) {
|
|
83
|
+
case LogLevel::Error: levelStr = "ERR"; break;
|
|
84
|
+
case LogLevel::Warn: levelStr = "WRN"; break;
|
|
85
|
+
case LogLevel::Info: levelStr = "INF"; break;
|
|
86
|
+
case LogLevel::Debug: levelStr = "DBG"; break;
|
|
87
|
+
case LogLevel::Trace: levelStr = "TRC"; break;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Format: [HH:MM:SS.mmm] [LEVEL] [TAG] Message
|
|
91
|
+
std::ostringstream oss;
|
|
92
|
+
oss << std::put_time(std::localtime(&time), "%H:%M:%S");
|
|
93
|
+
oss << "." << std::setfill('0') << std::setw(3) << ms;
|
|
94
|
+
oss << " [" << levelStr << "] [" << tag << "] " << message;
|
|
95
|
+
|
|
96
|
+
// Output to stderr (always available)
|
|
97
|
+
std::cerr << oss.str() << std::endl;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Convenience methods
|
|
101
|
+
static void error(const std::string& tag, const std::string& message) {
|
|
102
|
+
log(LogLevel::Error, tag, message);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static void warn(const std::string& tag, const std::string& message) {
|
|
106
|
+
log(LogLevel::Warn, tag, message);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static void info(const std::string& tag, const std::string& message) {
|
|
110
|
+
log(LogLevel::Info, tag, message);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static void debug(const std::string& tag, const std::string& message) {
|
|
114
|
+
log(LogLevel::Debug, tag, message);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
static void trace(const std::string& tag, const std::string& message) {
|
|
118
|
+
log(LogLevel::Trace, tag, message);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// ============================================
|
|
123
|
+
// Logging Macros
|
|
124
|
+
// ============================================
|
|
125
|
+
|
|
126
|
+
// These macros are completely compiled out when ENNIO_DEBUG is not defined
|
|
127
|
+
// or when the level is higher than the configured level
|
|
128
|
+
|
|
129
|
+
#ifdef ENNIO_DEBUG
|
|
130
|
+
|
|
131
|
+
#define ENNIO_LOG_ERROR(tag, msg) ::ennio::EnnioLog::error(tag, msg)
|
|
132
|
+
#define ENNIO_LOG_WARN(tag, msg) ::ennio::EnnioLog::warn(tag, msg)
|
|
133
|
+
|
|
134
|
+
#if ENNIO_DEBUG >= 2
|
|
135
|
+
#define ENNIO_LOG_INFO(tag, msg) ::ennio::EnnioLog::info(tag, msg)
|
|
136
|
+
#else
|
|
137
|
+
#define ENNIO_LOG_INFO(tag, msg) do {} while(0)
|
|
138
|
+
#endif
|
|
139
|
+
|
|
140
|
+
#if ENNIO_DEBUG >= 3
|
|
141
|
+
#define ENNIO_LOG_DEBUG(tag, msg) ::ennio::EnnioLog::debug(tag, msg)
|
|
142
|
+
#else
|
|
143
|
+
#define ENNIO_LOG_DEBUG(tag, msg) do {} while(0)
|
|
144
|
+
#endif
|
|
145
|
+
|
|
146
|
+
#if ENNIO_DEBUG >= 4
|
|
147
|
+
#define ENNIO_LOG_TRACE(tag, msg) ::ennio::EnnioLog::trace(tag, msg)
|
|
148
|
+
#else
|
|
149
|
+
#define ENNIO_LOG_TRACE(tag, msg) do {} while(0)
|
|
150
|
+
#endif
|
|
151
|
+
|
|
152
|
+
// Format helper for building messages with stream syntax
|
|
153
|
+
#define ENNIO_LOG_FMT(...) ([]() { \
|
|
154
|
+
std::ostringstream _oss; \
|
|
155
|
+
_oss << __VA_ARGS__; \
|
|
156
|
+
return _oss.str(); \
|
|
157
|
+
}())
|
|
158
|
+
|
|
159
|
+
// Printf-style format helper for DEBUG level (used by legacy code)
|
|
160
|
+
#if ENNIO_DEBUG >= 3
|
|
161
|
+
#define ENNIO_LOG_DEBUG_F(tag, fmt, ...) do { \
|
|
162
|
+
char _buf[512]; \
|
|
163
|
+
snprintf(_buf, sizeof(_buf), fmt, ##__VA_ARGS__); \
|
|
164
|
+
::ennio::EnnioLog::debug(tag, _buf); \
|
|
165
|
+
} while(0)
|
|
166
|
+
#else
|
|
167
|
+
#define ENNIO_LOG_DEBUG_F(tag, fmt, ...) do {} while(0)
|
|
168
|
+
#endif
|
|
169
|
+
|
|
170
|
+
#else // ENNIO_DEBUG not defined
|
|
171
|
+
|
|
172
|
+
#define ENNIO_LOG_ERROR(tag, msg) do {} while(0)
|
|
173
|
+
#define ENNIO_LOG_WARN(tag, msg) do {} while(0)
|
|
174
|
+
#define ENNIO_LOG_INFO(tag, msg) do {} while(0)
|
|
175
|
+
#define ENNIO_LOG_DEBUG(tag, msg) do {} while(0)
|
|
176
|
+
#define ENNIO_LOG_TRACE(tag, msg) do {} while(0)
|
|
177
|
+
#define ENNIO_LOG_FMT(...) std::string()
|
|
178
|
+
#define ENNIO_LOG_DEBUG_F(tag, fmt, ...) do {} while(0)
|
|
179
|
+
|
|
180
|
+
#endif // ENNIO_DEBUG
|
|
181
|
+
|
|
182
|
+
} // namespace ennio
|