fastevent 1.1.2 → 2.0.0
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/dist/devTools.js +2 -2
- package/dist/devTools.js.map +1 -1
- package/dist/devTools.mjs +2 -2
- package/dist/devTools.mjs.map +1 -1
- package/dist/index.d.mts +286 -57
- package/dist/index.d.ts +286 -57
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +64 -50
- package/readme.md +517 -50
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.github/workflows/publish.yaml +0 -50
- package/.prettierrc.js +0 -20
- package/.vscode/launch.json +0 -20
- package/.vscode/settings.json +0 -18
- package/CHANGELOG.md +0 -54
- package/LICENSE +0 -21
- package/bench.png +0 -0
- package/dist/devTools.d.mts +0 -543
- package/dist/devTools.d.ts +0 -543
- package/example/README.md +0 -54
- package/example/eslint.config.js +0 -28
- package/example/index.html +0 -13
- package/example/package.json +0 -29
- package/example/pnpm-lock.yaml +0 -2047
- package/example/public/vite.svg +0 -1
- package/example/src/App.css +0 -42
- package/example/src/App.tsx +0 -60
- package/example/src/assets/react.svg +0 -1
- package/example/src/index.css +0 -68
- package/example/src/main.tsx +0 -10
- package/example/src/myEvent.ts +0 -32
- package/example/src/vite-env.d.ts +0 -1
- package/example/tsconfig.app.json +0 -26
- package/example/tsconfig.json +0 -7
- package/example/tsconfig.node.json +0 -24
- package/example/vite.config.ts +0 -7
- package/packages/native/index.ts +0 -1
- package/packages/turbo/.zig-cache/h/271c82d991949fd7788fd5451f0ca834.txt +0 -0
- package/packages/turbo/.zig-cache/h/timestamp +0 -0
- package/packages/turbo/.zig-cache/o/ebd7ddab8ffe003267120d598aecce68/dependencies.zig +0 -2
- package/packages/turbo/.zig-cache/z/c8114b040daa461a9e2eabd0357554a4 +0 -0
- package/packages/turbo/build.zig +0 -60
- package/packages/turbo/examples/basic.zig +0 -107
- package/packages/turbo/src/event.zig +0 -251
- package/packages/turbo/src/index.zig +0 -70
- package/packages/turbo/src/scope.zig +0 -104
- package/packages/turbo/src/types.zig +0 -88
- package/packages/turbo/src/utils.zig +0 -171
- package/readme_cn.md +0 -491
- package/src/__benchmarks__/index.ts +0 -3
- package/src/__benchmarks__/multi-level.ts +0 -40
- package/src/__benchmarks__/sample.ts +0 -40
- package/src/__benchmarks__/wildcard.ts +0 -41
- package/src/__tests__/emit.test.ts +0 -106
- package/src/__tests__/emitAsync.test.ts +0 -64
- package/src/__tests__/isPathMatched.test.ts +0 -205
- package/src/__tests__/many.test.ts +0 -22
- package/src/__tests__/meta.test.ts +0 -28
- package/src/__tests__/off.test.ts +0 -214
- package/src/__tests__/onany.test.ts +0 -212
- package/src/__tests__/once.test.ts +0 -70
- package/src/__tests__/retain.test.ts +0 -66
- package/src/__tests__/scope.test.ts +0 -110
- package/src/__tests__/types.test.ts +0 -145
- package/src/__tests__/waitFor.test.ts +0 -116
- package/src/__tests__/wildcard.test.ts +0 -185
- package/src/devTools.ts +0 -166
- package/src/event.ts +0 -741
- package/src/index.ts +0 -3
- package/src/scope.ts +0 -130
- package/src/types.ts +0 -69
- package/src/utils/WeakObjectMap.ts +0 -64
- package/src/utils/isPathMatched.ts +0 -40
- package/src/utils/removeItem.ts +0 -16
- package/tsconfig.json +0 -104
- package/tsup.config.ts +0 -30
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const types = @import("types.zig");
|
|
3
|
-
const Allocator = std.mem.Allocator;
|
|
4
|
-
|
|
5
|
-
const EventListener = types.EventListener;
|
|
6
|
-
const EventMessage = types.EventMessage;
|
|
7
|
-
const ListenOptions = types.ListenOptions;
|
|
8
|
-
const Subscriber = types.Subscriber;
|
|
9
|
-
const EventOptions = types.EventOptions;
|
|
10
|
-
const ListenerNode = types.ListenerNode;
|
|
11
|
-
const ListenerEntry = types.ListenerEntry;
|
|
12
|
-
|
|
13
|
-
/// 事件发射器
|
|
14
|
-
pub const EventEmitter = struct {
|
|
15
|
-
allocator: Allocator,
|
|
16
|
-
options: EventOptions,
|
|
17
|
-
root: *ListenerNode,
|
|
18
|
-
retained_events: std.StringHashMap(std.ArrayList(EventMessage)),
|
|
19
|
-
|
|
20
|
-
pub fn init(allocator: Allocator, options: EventOptions) !*EventEmitter {
|
|
21
|
-
const emitter = try allocator.create(EventEmitter);
|
|
22
|
-
emitter.* = .{
|
|
23
|
-
.allocator = allocator,
|
|
24
|
-
.options = options,
|
|
25
|
-
.root = try ListenerNode.init(allocator),
|
|
26
|
-
.retained_events = std.StringHashMap(std.ArrayList(EventMessage)).init(allocator),
|
|
27
|
-
};
|
|
28
|
-
return emitter;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
pub fn deinit(self: *EventEmitter) void {
|
|
32
|
-
var it = self.retained_events.iterator();
|
|
33
|
-
while (it.next()) |entry| {
|
|
34
|
-
entry.value_ptr.deinit();
|
|
35
|
-
}
|
|
36
|
-
self.retained_events.deinit();
|
|
37
|
-
self.root.deinit();
|
|
38
|
-
self.allocator.destroy(self.root);
|
|
39
|
-
self.allocator.destroy(self);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/// 添加事件监听器
|
|
43
|
-
pub fn on(self: *EventEmitter, event_type: []const u8, listener: EventListener, options: ListenOptions) !*Subscriber {
|
|
44
|
-
const path = try self.splitEventPath(event_type);
|
|
45
|
-
defer self.allocator.free(path);
|
|
46
|
-
|
|
47
|
-
var node = self.root;
|
|
48
|
-
for (path) |segment| {
|
|
49
|
-
var child = node.children.get(segment) orelse {
|
|
50
|
-
const new_node = try ListenerNode.init(self.allocator);
|
|
51
|
-
try node.children.put(segment, new_node);
|
|
52
|
-
new_node;
|
|
53
|
-
};
|
|
54
|
-
node = child;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const entry = if (options.count > 0)
|
|
58
|
-
ListenerEntry{ .Counted = .{ .listener = listener, .count = options.count } }
|
|
59
|
-
else
|
|
60
|
-
ListenerEntry{ .Simple = listener };
|
|
61
|
-
|
|
62
|
-
if (options.prepend) {
|
|
63
|
-
try node.listeners.insert(0, entry);
|
|
64
|
-
} else {
|
|
65
|
-
try node.listeners.append(entry);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (self.options.on_add_listener) |callback| {
|
|
69
|
-
callback(path, listener);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// 处理保留的事件
|
|
73
|
-
if (self.retained_events.get(event_type)) |events| {
|
|
74
|
-
for (events.items) |msg| {
|
|
75
|
-
_ = try self.executeListener(listener, &msg);
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const subscriber = try self.allocator.create(Subscriber);
|
|
80
|
-
subscriber.* = .{
|
|
81
|
-
.off_fn = struct {
|
|
82
|
-
fn off(sub: *Subscriber) void {
|
|
83
|
-
self.off(event_type, listener);
|
|
84
|
-
self.allocator.destroy(sub);
|
|
85
|
-
}
|
|
86
|
-
}.off,
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return subscriber;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/// 移除事件监听器
|
|
93
|
-
pub fn off(self: *EventEmitter, event_type: []const u8, listener: ?EventListener) void {
|
|
94
|
-
const path = self.splitEventPath(event_type) catch return;
|
|
95
|
-
defer self.allocator.free(path);
|
|
96
|
-
|
|
97
|
-
if (self.options.on_remove_listener) |callback| {
|
|
98
|
-
if (listener) |l| {
|
|
99
|
-
callback(path, l);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
var node = self.root;
|
|
104
|
-
var nodes = std.ArrayList(*ListenerNode).init(self.allocator);
|
|
105
|
-
defer nodes.deinit();
|
|
106
|
-
|
|
107
|
-
// 找到目标节点
|
|
108
|
-
for (path) |segment| {
|
|
109
|
-
if (node.children.get(segment)) |child| {
|
|
110
|
-
try nodes.append(node);
|
|
111
|
-
node = child;
|
|
112
|
-
} else {
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// 移除监听器
|
|
118
|
-
if (listener) |l| {
|
|
119
|
-
var i: usize = 0;
|
|
120
|
-
while (i < node.listeners.items.len) {
|
|
121
|
-
const entry = node.listeners.items[i];
|
|
122
|
-
const current = switch (entry) {
|
|
123
|
-
.Simple => |simple| simple,
|
|
124
|
-
.Counted => |counted| counted.listener,
|
|
125
|
-
};
|
|
126
|
-
if (current == l) {
|
|
127
|
-
_ = node.listeners.orderedRemove(i);
|
|
128
|
-
} else {
|
|
129
|
-
i += 1;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
} else {
|
|
133
|
-
node.listeners.clearRetainingCapacity();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// 清理空节点
|
|
137
|
-
if (node.listeners.items.len == 0 and node.children.count() == 0) {
|
|
138
|
-
var i: usize = nodes.items.len;
|
|
139
|
-
while (i > 0) : (i -= 1) {
|
|
140
|
-
const parent = nodes.items[i - 1];
|
|
141
|
-
const segment = path[i - 1];
|
|
142
|
-
_ = parent.children.remove(segment);
|
|
143
|
-
if (parent.listeners.items.len > 0 or parent.children.count() > 0) {
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/// 触发事件
|
|
151
|
-
pub fn emit(self: *EventEmitter, event_type: []const u8, payload: ?*anyopaque, meta: ?std.StringHashMap([]const u8)) !void {
|
|
152
|
-
var message = EventMessage.init(event_type, payload, meta);
|
|
153
|
-
const path = try self.splitEventPath(event_type);
|
|
154
|
-
defer self.allocator.free(path);
|
|
155
|
-
|
|
156
|
-
var results = std.ArrayList(anyerror!void).init(self.allocator);
|
|
157
|
-
defer results.deinit();
|
|
158
|
-
|
|
159
|
-
var listeners = std.ArrayList(EventListener).init(self.allocator);
|
|
160
|
-
defer listeners.deinit();
|
|
161
|
-
|
|
162
|
-
try self.collectListeners(self.root, path, 0, &listeners);
|
|
163
|
-
|
|
164
|
-
for (listeners.items) |listener| {
|
|
165
|
-
const result = self.executeListener(listener, &message);
|
|
166
|
-
try results.append(result);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (self.options.on_execute_listener) |callback| {
|
|
170
|
-
callback(&message, results.items, listeners.items);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/// 保留事件
|
|
175
|
-
pub fn retain(self: *EventEmitter, event_type: []const u8, payload: ?*anyopaque, meta: ?std.StringHashMap([]const u8)) !void {
|
|
176
|
-
var events = self.retained_events.get(event_type) orelse {
|
|
177
|
-
var list = std.ArrayList(EventMessage).init(self.allocator);
|
|
178
|
-
try self.retained_events.put(event_type, list);
|
|
179
|
-
list;
|
|
180
|
-
};
|
|
181
|
-
try events.append(EventMessage.init(event_type, payload, meta));
|
|
182
|
-
try self.emit(event_type, payload, meta);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/// 释放保留的事件
|
|
186
|
-
pub fn release(self: *EventEmitter, event_type: []const u8) void {
|
|
187
|
-
if (self.retained_events.get(event_type)) |events| {
|
|
188
|
-
events.deinit();
|
|
189
|
-
_ = self.retained_events.remove(event_type);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// 内部辅助函数
|
|
194
|
-
|
|
195
|
-
fn splitEventPath(self: *EventEmitter, event_type: []const u8) ![][]const u8 {
|
|
196
|
-
var list = std.ArrayList([]const u8).init(self.allocator);
|
|
197
|
-
var it = std.mem.split(u8, event_type, self.options.delimiter);
|
|
198
|
-
while (it.next()) |segment| {
|
|
199
|
-
try list.append(segment);
|
|
200
|
-
}
|
|
201
|
-
return list.toOwnedSlice();
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
fn executeListener(self: *EventEmitter, listener: EventListener, message: *EventMessage) anyerror!void {
|
|
205
|
-
if (self.options.ignore_errors) {
|
|
206
|
-
listener(message) catch |err| {
|
|
207
|
-
if (self.options.on_listener_error) |callback| {
|
|
208
|
-
callback(message.type, err);
|
|
209
|
-
}
|
|
210
|
-
};
|
|
211
|
-
} else {
|
|
212
|
-
try listener(message);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
fn collectListeners(self: *EventEmitter, node: *ListenerNode, path: [][]const u8, depth: usize, result: *std.ArrayList(EventListener)) !void {
|
|
217
|
-
// 添加当前节点的监听器
|
|
218
|
-
for (node.listeners.items) |*entry| {
|
|
219
|
-
switch (entry.*) {
|
|
220
|
-
.Simple => |listener| try result.append(listener),
|
|
221
|
-
.Counted => |*counted| {
|
|
222
|
-
if (counted.count > 0) {
|
|
223
|
-
try result.append(counted.listener);
|
|
224
|
-
counted.count -= 1;
|
|
225
|
-
if (counted.count == 0) {
|
|
226
|
-
// 移除用完的监听器
|
|
227
|
-
for (node.listeners.items, 0..) |e, i| {
|
|
228
|
-
if (std.meta.activeTag(e) == .Counted and &e.Counted == counted) {
|
|
229
|
-
_ = node.listeners.orderedRemove(i);
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
if (depth >= path.len) return;
|
|
240
|
-
|
|
241
|
-
// 处理通配符
|
|
242
|
-
if (node.children.get("*")) |wildcard| {
|
|
243
|
-
try self.collectListeners(wildcard, path, depth + 1, result);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// 处理具体路径
|
|
247
|
-
if (node.children.get(path[depth])) |child| {
|
|
248
|
-
try self.collectListeners(child, path, depth + 1, result);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
//! FastEvent是一个高性能的事件系统,支持事件监听、触发、作用域管理和通配符匹配等功能。
|
|
2
|
-
//! 它使用Zig语言实现,提供了类型安全和内存安全的事件处理机制。
|
|
3
|
-
|
|
4
|
-
pub const types = @import("types.zig");
|
|
5
|
-
pub const event = @import("event.zig");
|
|
6
|
-
pub const scope = @import("scope.zig");
|
|
7
|
-
pub const utils = @import("utils.zig");
|
|
8
|
-
|
|
9
|
-
// 重导出常用类型
|
|
10
|
-
pub const EventEmitter = event.EventEmitter;
|
|
11
|
-
pub const EventScope = scope.EventScope;
|
|
12
|
-
pub const EventMessage = types.EventMessage;
|
|
13
|
-
pub const EventListener = types.EventListener;
|
|
14
|
-
pub const ListenOptions = types.ListenOptions;
|
|
15
|
-
pub const Subscriber = types.Subscriber;
|
|
16
|
-
pub const EventOptions = types.EventOptions;
|
|
17
|
-
|
|
18
|
-
// 重导出常用函数
|
|
19
|
-
pub const createRootScope = scope.createRootScope;
|
|
20
|
-
|
|
21
|
-
/// 创建一个新的事件发射器
|
|
22
|
-
pub fn createEmitter(allocator: @import("std").mem.Allocator, options: EventOptions) !*EventEmitter {
|
|
23
|
-
return EventEmitter.init(allocator, options);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
test {
|
|
27
|
-
// 运行所有测试
|
|
28
|
-
@import("std").testing.refAllDecls(@This());
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/// 使用示例
|
|
32
|
-
const example = @"
|
|
33
|
-
// 创建事件发射器
|
|
34
|
-
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
35
|
-
defer _ = gpa.deinit();
|
|
36
|
-
const allocator = gpa.allocator();
|
|
37
|
-
|
|
38
|
-
// 配置选项
|
|
39
|
-
const options = EventOptions{
|
|
40
|
-
.debug = true,
|
|
41
|
-
.delimiter = '/',
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
// 创建发射器
|
|
45
|
-
var emitter = try createEmitter(allocator, options);
|
|
46
|
-
defer emitter.deinit();
|
|
47
|
-
|
|
48
|
-
// 创建根作用域
|
|
49
|
-
var root_scope = try createRootScope(allocator, emitter);
|
|
50
|
-
defer root_scope.deinit();
|
|
51
|
-
|
|
52
|
-
// 添加事件监听器
|
|
53
|
-
try root_scope.on('user/login', userLoginHandler, .{});
|
|
54
|
-
|
|
55
|
-
// 触发事件
|
|
56
|
-
try emitter.emit('user/login', userInfo, null);
|
|
57
|
-
|
|
58
|
-
// 使用通配符监听
|
|
59
|
-
try root_scope.on('user/*', anyUserEventHandler, .{});
|
|
60
|
-
|
|
61
|
-
// 创建子作用域
|
|
62
|
-
var sub_scope = try root_scope.createScope();
|
|
63
|
-
defer sub_scope.deinit();
|
|
64
|
-
|
|
65
|
-
// 在子作用域中添加监听器
|
|
66
|
-
try sub_scope.on('chat/message', chatMessageHandler, .{});
|
|
67
|
-
|
|
68
|
-
// 当不再需要时,dispose()会自动清理所有监听器
|
|
69
|
-
sub_scope.dispose();
|
|
70
|
-
";
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const types = @import("types.zig");
|
|
3
|
-
const event = @import("event.zig");
|
|
4
|
-
|
|
5
|
-
const Allocator = std.mem.Allocator;
|
|
6
|
-
const EventEmitter = event.EventEmitter;
|
|
7
|
-
const Subscriber = types.Subscriber;
|
|
8
|
-
const EventListener = types.EventListener;
|
|
9
|
-
const ListenOptions = types.ListenOptions;
|
|
10
|
-
|
|
11
|
-
/// 事件作用域,用于管理一组相关的事件监听器
|
|
12
|
-
pub const EventScope = struct {
|
|
13
|
-
allocator: Allocator,
|
|
14
|
-
emitter: *EventEmitter,
|
|
15
|
-
subscribers: std.ArrayList(*Subscriber),
|
|
16
|
-
is_disposed: bool,
|
|
17
|
-
|
|
18
|
-
pub fn init(allocator: Allocator, emitter: *EventEmitter) !*EventScope {
|
|
19
|
-
const scope = try allocator.create(EventScope);
|
|
20
|
-
scope.* = .{
|
|
21
|
-
.allocator = allocator,
|
|
22
|
-
.emitter = emitter,
|
|
23
|
-
.subscribers = std.ArrayList(*Subscriber).init(allocator),
|
|
24
|
-
.is_disposed = false,
|
|
25
|
-
};
|
|
26
|
-
return scope;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
pub fn deinit(self: *EventScope) void {
|
|
30
|
-
self.dispose();
|
|
31
|
-
self.subscribers.deinit();
|
|
32
|
-
self.allocator.destroy(self);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/// 在作用域中添加事件监听器
|
|
36
|
-
pub fn on(self: *EventScope, event_type: []const u8, listener: EventListener, options: ListenOptions) !void {
|
|
37
|
-
if (self.is_disposed) return error.ScopeDisposed;
|
|
38
|
-
|
|
39
|
-
const subscriber = try self.emitter.on(event_type, listener, options);
|
|
40
|
-
try self.subscribers.append(subscriber);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/// 移除作用域中的特定事件监听器
|
|
44
|
-
pub fn off(self: *EventScope, event_type: []const u8, listener: EventListener) void {
|
|
45
|
-
if (self.is_disposed) return;
|
|
46
|
-
|
|
47
|
-
self.emitter.off(event_type, listener);
|
|
48
|
-
|
|
49
|
-
// 移除对应的订阅者
|
|
50
|
-
var i: usize = 0;
|
|
51
|
-
while (i < self.subscribers.items.len) {
|
|
52
|
-
const subscriber = self.subscribers.items[i];
|
|
53
|
-
// 注意:这里的比较可能不够准确,因为我们无法直接比较函数指针
|
|
54
|
-
// 在实际应用中可能需要更复杂的机制来匹配订阅者
|
|
55
|
-
if (@ptrToInt(subscriber.off_fn) == @ptrToInt(listener)) {
|
|
56
|
-
_ = self.subscribers.orderedRemove(i);
|
|
57
|
-
self.allocator.destroy(subscriber);
|
|
58
|
-
} else {
|
|
59
|
-
i += 1;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/// 清理作用域中的所有事件监听器
|
|
65
|
-
pub fn dispose(self: *EventScope) void {
|
|
66
|
-
if (self.is_disposed) return;
|
|
67
|
-
self.is_disposed = true;
|
|
68
|
-
|
|
69
|
-
// 移除所有订阅者
|
|
70
|
-
for (self.subscribers.items) |subscriber| {
|
|
71
|
-
subscriber.off();
|
|
72
|
-
self.allocator.destroy(subscriber);
|
|
73
|
-
}
|
|
74
|
-
self.subscribers.clearRetainingCapacity();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/// 创建子作用域
|
|
78
|
-
pub fn createScope(self: *EventScope) !*EventScope {
|
|
79
|
-
if (self.is_disposed) return error.ScopeDisposed;
|
|
80
|
-
|
|
81
|
-
const child_scope = try EventScope.init(self.allocator, self.emitter);
|
|
82
|
-
const subscriber = try self.allocator.create(Subscriber);
|
|
83
|
-
subscriber.* = .{
|
|
84
|
-
.off_fn = struct {
|
|
85
|
-
fn off(sub: *Subscriber) void {
|
|
86
|
-
child_scope.dispose();
|
|
87
|
-
child_scope.allocator.destroy(sub);
|
|
88
|
-
}
|
|
89
|
-
}.off,
|
|
90
|
-
};
|
|
91
|
-
try self.subscribers.append(subscriber);
|
|
92
|
-
return child_scope;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/// 检查作用域是否已被清理
|
|
96
|
-
pub fn isDisposed(self: *const EventScope) bool {
|
|
97
|
-
return self.is_disposed;
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
/// 创建根作用域
|
|
102
|
-
pub fn createRootScope(allocator: Allocator, emitter: *EventEmitter) !*EventScope {
|
|
103
|
-
return EventScope.init(allocator, emitter);
|
|
104
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const Allocator = std.mem.Allocator;
|
|
3
|
-
|
|
4
|
-
/// 事件监听器函数类型
|
|
5
|
-
pub const EventListener = *const fn (message: *EventMessage) anyerror!void;
|
|
6
|
-
|
|
7
|
-
/// 事件消息结构
|
|
8
|
-
pub const EventMessage = struct {
|
|
9
|
-
type: []const u8,
|
|
10
|
-
payload: ?*anyopaque,
|
|
11
|
-
meta: ?std.StringHashMap([]const u8),
|
|
12
|
-
|
|
13
|
-
pub fn init(type: []const u8, payload: ?*anyopaque, meta: ?std.StringHashMap([]const u8)) EventMessage {
|
|
14
|
-
return .{
|
|
15
|
-
.type = type,
|
|
16
|
-
.payload = payload,
|
|
17
|
-
.meta = meta,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/// 事件监听选项
|
|
23
|
-
pub const ListenOptions = struct {
|
|
24
|
-
count: usize = 0, // 0表示无限次数
|
|
25
|
-
prepend: bool = false,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/// 事件订阅者接口
|
|
29
|
-
pub const Subscriber = struct {
|
|
30
|
-
off_fn: *const fn () void,
|
|
31
|
-
|
|
32
|
-
pub fn off(self: *const Subscriber) void {
|
|
33
|
-
self.off_fn();
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/// 事件选项
|
|
38
|
-
pub const EventOptions = struct {
|
|
39
|
-
debug: bool = false,
|
|
40
|
-
id: []const u8 = undefined,
|
|
41
|
-
delimiter: []const u8 = "/",
|
|
42
|
-
context: ?*anyopaque = null,
|
|
43
|
-
ignore_errors: bool = true,
|
|
44
|
-
meta: ?std.StringHashMap([]const u8) = null,
|
|
45
|
-
|
|
46
|
-
// 回调函数
|
|
47
|
-
on_add_listener: ?*const fn (path: []const []const u8, listener: EventListener) void = null,
|
|
48
|
-
on_remove_listener: ?*const fn (path: []const []const u8, listener: EventListener) void = null,
|
|
49
|
-
on_clear_listeners: ?*const fn () void = null,
|
|
50
|
-
on_listener_error: ?*const fn (event_type: []const u8, err: anyerror) void = null,
|
|
51
|
-
on_execute_listener: ?*const fn (message: *EventMessage, results: []const anyerror!void, listeners: []const EventListener) void = null,
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
/// 监听器节点结构
|
|
55
|
-
pub const ListenerNode = struct {
|
|
56
|
-
listeners: std.ArrayList(ListenerEntry),
|
|
57
|
-
children: std.StringHashMap(*ListenerNode),
|
|
58
|
-
allocator: Allocator,
|
|
59
|
-
|
|
60
|
-
pub fn init(allocator: Allocator) !*ListenerNode {
|
|
61
|
-
const node = try allocator.create(ListenerNode);
|
|
62
|
-
node.* = .{
|
|
63
|
-
.listeners = std.ArrayList(ListenerEntry).init(allocator),
|
|
64
|
-
.children = std.StringHashMap(*ListenerNode).init(allocator),
|
|
65
|
-
.allocator = allocator,
|
|
66
|
-
};
|
|
67
|
-
return node;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
pub fn deinit(self: *ListenerNode) void {
|
|
71
|
-
var it = self.children.iterator();
|
|
72
|
-
while (it.next()) |entry| {
|
|
73
|
-
entry.value_ptr.*.deinit();
|
|
74
|
-
self.allocator.destroy(entry.value_ptr.*);
|
|
75
|
-
}
|
|
76
|
-
self.children.deinit();
|
|
77
|
-
self.listeners.deinit();
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
/// 监听器条目,可以是普通监听器或带计数的监听器
|
|
82
|
-
pub const ListenerEntry = union(enum) {
|
|
83
|
-
Simple: EventListener,
|
|
84
|
-
Counted: struct {
|
|
85
|
-
listener: EventListener,
|
|
86
|
-
count: usize,
|
|
87
|
-
},
|
|
88
|
-
};
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
const std = @import("std");
|
|
2
|
-
const Allocator = std.mem.Allocator;
|
|
3
|
-
|
|
4
|
-
/// 检查字符串是否包含通配符
|
|
5
|
-
pub fn hasWildcard(str: []const u8) bool {
|
|
6
|
-
return std.mem.indexOf(u8, str, "*") != null;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/// 将事件类型字符串分割为路径段
|
|
10
|
-
pub fn splitEventPath(allocator: Allocator, event_type: []const u8, delimiter: []const u8) ![][]const u8 {
|
|
11
|
-
var list = std.ArrayList([]const u8).init(allocator);
|
|
12
|
-
errdefer list.deinit();
|
|
13
|
-
|
|
14
|
-
var it = std.mem.split(u8, event_type, delimiter);
|
|
15
|
-
while (it.next()) |segment| {
|
|
16
|
-
const owned_segment = try allocator.dupe(u8, segment);
|
|
17
|
-
errdefer allocator.free(owned_segment);
|
|
18
|
-
try list.append(owned_segment);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
return list.toOwnedSlice();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/// 释放splitEventPath返回的路径段数组
|
|
25
|
-
pub fn freeEventPath(allocator: Allocator, path: [][]const u8) void {
|
|
26
|
-
for (path) |segment| {
|
|
27
|
-
allocator.free(segment);
|
|
28
|
-
}
|
|
29
|
-
allocator.free(path);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/// 将路径段合并为事件类型字符串
|
|
33
|
-
pub fn joinEventPath(allocator: Allocator, path: []const []const u8, delimiter: []const u8) ![]u8 {
|
|
34
|
-
if (path.len == 0) return allocator.dupe(u8, "");
|
|
35
|
-
|
|
36
|
-
// 计算所需的总长度
|
|
37
|
-
var total_len: usize = 0;
|
|
38
|
-
for (path) |segment| {
|
|
39
|
-
total_len += segment.len;
|
|
40
|
-
}
|
|
41
|
-
total_len += delimiter.len * (path.len - 1);
|
|
42
|
-
|
|
43
|
-
// 分配内存并构建结果
|
|
44
|
-
const result = try allocator.alloc(u8, total_len);
|
|
45
|
-
errdefer allocator.free(result);
|
|
46
|
-
|
|
47
|
-
var pos: usize = 0;
|
|
48
|
-
for (path, 0..) |segment, i| {
|
|
49
|
-
std.mem.copy(u8, result[pos..], segment);
|
|
50
|
-
pos += segment.len;
|
|
51
|
-
if (i < path.len - 1) {
|
|
52
|
-
std.mem.copy(u8, result[pos..], delimiter);
|
|
53
|
-
pos += delimiter.len;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return result;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/// 检查事件类型是否匹配模式
|
|
61
|
-
pub fn matchEventType(event_type: []const u8, pattern: []const u8, delimiter: []const u8) bool {
|
|
62
|
-
// 如果模式中没有通配符,直接比较字符串
|
|
63
|
-
if (!hasWildcard(pattern)) {
|
|
64
|
-
return std.mem.eql(u8, event_type, pattern);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
var event_it = std.mem.split(u8, event_type, delimiter);
|
|
68
|
-
var pattern_it = std.mem.split(u8, pattern, delimiter);
|
|
69
|
-
|
|
70
|
-
// 逐段比较
|
|
71
|
-
while (true) {
|
|
72
|
-
const event_segment = event_it.next();
|
|
73
|
-
const pattern_segment = pattern_it.next();
|
|
74
|
-
|
|
75
|
-
// 如果两个迭代器都结束了,说明完全匹配
|
|
76
|
-
if (event_segment == null and pattern_segment == null) {
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// 如果其中一个迭代器结束了但另一个没有,说明不匹配
|
|
81
|
-
if (event_segment == null or pattern_segment == null) {
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// 如果当前段是通配符,继续下一段
|
|
86
|
-
if (std.mem.eql(u8, pattern_segment.?, "*")) {
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// 比较当前段
|
|
91
|
-
if (!std.mem.eql(u8, event_segment.?, pattern_segment.?)) {
|
|
92
|
-
return false;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/// 创建调试信息
|
|
98
|
-
pub fn createDebugInfo(allocator: Allocator, event_type: []const u8, payload: ?*anyopaque) ![]u8 {
|
|
99
|
-
var debug_info = std.ArrayList(u8).init(allocator);
|
|
100
|
-
errdefer debug_info.deinit();
|
|
101
|
-
|
|
102
|
-
try debug_info.writer().print("Event: {s}\n", .{event_type});
|
|
103
|
-
if (payload) |p| {
|
|
104
|
-
try debug_info.writer().print("Payload: {*}\n", .{p});
|
|
105
|
-
} else {
|
|
106
|
-
try debug_info.appendSlice("Payload: null\n");
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return debug_info.toOwnedSlice();
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
/// 检查路径是否有效
|
|
113
|
-
pub fn isValidPath(path: []const []const u8) bool {
|
|
114
|
-
if (path.len == 0) return false;
|
|
115
|
-
|
|
116
|
-
for (path) |segment| {
|
|
117
|
-
if (segment.len == 0) return false;
|
|
118
|
-
if (std.mem.indexOf(u8, segment, "/") != null) return false;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
test "utils - hasWildcard" {
|
|
125
|
-
try std.testing.expect(hasWildcard("foo*"));
|
|
126
|
-
try std.testing.expect(hasWildcard("foo/*/bar"));
|
|
127
|
-
try std.testing.expect(!hasWildcard("foo/bar"));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
test "utils - splitEventPath" {
|
|
131
|
-
const allocator = std.testing.allocator;
|
|
132
|
-
|
|
133
|
-
const path = try splitEventPath(allocator, "foo/bar/baz", "/");
|
|
134
|
-
defer freeEventPath(allocator, path);
|
|
135
|
-
|
|
136
|
-
try std.testing.expectEqual(@as(usize, 3), path.len);
|
|
137
|
-
try std.testing.expectEqualStrings("foo", path[0]);
|
|
138
|
-
try std.testing.expectEqualStrings("bar", path[1]);
|
|
139
|
-
try std.testing.expectEqualStrings("baz", path[2]);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
test "utils - joinEventPath" {
|
|
143
|
-
const allocator = std.testing.allocator;
|
|
144
|
-
|
|
145
|
-
const segments = [_][]const u8{ "foo", "bar", "baz" };
|
|
146
|
-
const result = try joinEventPath(allocator, &segments, "/");
|
|
147
|
-
defer allocator.free(result);
|
|
148
|
-
|
|
149
|
-
try std.testing.expectEqualStrings("foo/bar/baz", result);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
test "utils - matchEventType" {
|
|
153
|
-
try std.testing.expect(matchEventType("foo/bar/baz", "foo/*/baz", "/"));
|
|
154
|
-
try std.testing.expect(matchEventType("foo/bar/baz", "foo/bar/baz", "/"));
|
|
155
|
-
try std.testing.expect(!matchEventType("foo/bar/baz", "foo/bar", "/"));
|
|
156
|
-
try std.testing.expect(!matchEventType("foo/bar", "foo/bar/baz", "/"));
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
test "utils - isValidPath" {
|
|
160
|
-
const segments1 = [_][]const u8{ "foo", "bar", "baz" };
|
|
161
|
-
try std.testing.expect(isValidPath(&segments1));
|
|
162
|
-
|
|
163
|
-
const segments2 = [_][]const u8{ "foo", "", "baz" };
|
|
164
|
-
try std.testing.expect(!isValidPath(&segments2));
|
|
165
|
-
|
|
166
|
-
const segments3 = [_][]const u8{ "foo", "bar/baz" };
|
|
167
|
-
try std.testing.expect(!isValidPath(&segments3));
|
|
168
|
-
|
|
169
|
-
const segments4 = [_][]const u8{};
|
|
170
|
-
try std.testing.expect(!isValidPath(&segments4));
|
|
171
|
-
}
|