Skip to content

Commit a01741f

Browse files
committed
refactor: update Emitter architecture and implement Stream directly
Refactors `SharedEmitter` and `StateEmitter` to implement `Stream<T>` directly, removing the need for a separate `.stream` getter. This allows emitters to be used natively as streams while maintaining their specific emitter functionality. Key changes: - `SharedEmitter` and `StateEmitter` now implement `Stream<T>`. - Moved `EventEmitter` to a generic utility implementation in `src/utils/event_emitter.dart`. - Introduced `StreamEvent` base interface and `EventResolver` for type-safe event transformations. - Added `asSharedEmitter()` and `asStateEmitter()` extension methods to provide read-only views. - Added state manipulation helpers: `update`, `getAndUpdate`, and `updateAndGet` to `MutableStateEmitter`. - Added `hasListener` and `isClosed` properties to the emitter interfaces. - Updated `WsEvent` to implement `StreamEvent`.
1 parent c632cb0 commit a01741f

File tree

8 files changed

+292
-344
lines changed

8 files changed

+292
-344
lines changed

packages/stream_core/lib/src/utils.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export 'utils/comparable_extensions.dart';
22
export 'utils/comparable_field.dart';
33
export 'utils/disposable.dart';
4+
export 'utils/event_emitter.dart';
45
export 'utils/lifecycle_state_provider.dart';
56
export 'utils/list_extensions.dart';
67
export 'utils/network_state_provider.dart';
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import 'shared_emitter.dart';
2+
3+
/// Base interface for events that can be emitted through an [EventEmitter].
4+
///
5+
/// Implement this interface to create custom event types:
6+
///
7+
/// ```dart
8+
/// class UserLoggedIn implements StreamEvent {
9+
/// final String userId;
10+
/// UserLoggedIn(this.userId);
11+
/// }
12+
/// ```
13+
abstract interface class StreamEvent {}
14+
15+
/// A function that inspects an [event] and optionally transforms it.
16+
///
17+
/// Returns a transformed event if the resolver handles it, or `null` to
18+
/// pass the event to the next resolver in the chain.
19+
///
20+
/// ```dart
21+
/// final resolver = (event) {
22+
/// if (event is GenericEvent) return SpecificEvent(event.data);
23+
/// return null; // Let other resolvers handle it
24+
/// };
25+
/// ```
26+
typedef EventResolver<T extends StreamEvent> = T? Function(T event);
27+
28+
/// A read-only event emitter constrained to [StreamEvent] subtypes.
29+
///
30+
/// Type alias for [SharedEmitter] that enforces event type safety.
31+
///
32+
/// See also:
33+
/// - [MutableEventEmitter] for the mutable variant with resolver support.
34+
typedef EventEmitter<T extends StreamEvent> = SharedEmitter<T>;
35+
36+
/// A mutable event emitter with resolver support for event transformation.
37+
///
38+
/// Extends [SharedEmitterImpl] to apply a chain of [EventResolver]s before
39+
/// emitting events. Each resolver inspects the event and can transform it
40+
/// into a more specific type. The first resolver to return a non-null result
41+
/// determines the final emitted event.
42+
///
43+
/// ```dart
44+
/// final emitter = MutableEventEmitter<WsEvent>(
45+
/// resolvers: [
46+
/// (event) => event is RawEvent ? ParsedEvent(event.data) : null,
47+
/// ],
48+
/// );
49+
///
50+
/// emitter.on<ParsedEvent>((event) {
51+
/// print('Received parsed: ${event.data}');
52+
/// });
53+
///
54+
/// emitter.emit(RawEvent(data)); // Transformed and emitted as ParsedEvent
55+
/// ```
56+
///
57+
/// See also:
58+
/// - [EventEmitter] for the read-only interface.
59+
/// - [EventResolver] for the resolver function signature.
60+
final class MutableEventEmitter<T extends StreamEvent>
61+
extends SharedEmitterImpl<T> implements MutableSharedEmitter<T> {
62+
/// Creates a [MutableEventEmitter] with optional event [resolvers].
63+
///
64+
/// Resolvers are applied in order to each emitted event until one returns
65+
/// a non-null result. Supports synchronous or asynchronous emission via
66+
/// [sync], and can replay the last [replay] events to new subscribers.
67+
MutableEventEmitter({
68+
super.replay = 0,
69+
super.sync = false,
70+
Iterable<EventResolver<T>>? resolvers,
71+
}) : _resolvers = resolvers ?? const {};
72+
73+
final Iterable<EventResolver<T>> _resolvers;
74+
75+
@override
76+
void emit(T value) {
77+
for (final resolver in _resolvers) {
78+
final result = resolver(value);
79+
if (result != null) return super.emit(result);
80+
}
81+
82+
// No resolver matched — emit the event as-is.
83+
return super.emit(value);
84+
}
85+
}

0 commit comments

Comments
 (0)