LCOV - code coverage report
Current view: top level - src - stream.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 87 93 93.5 %
Date: 2022-04-26 21:04:14 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : 
       3             : import 'package:meta/meta.dart';
       4             : 
       5             : /// {@template stream.stream_extensions}
       6             : /// Stream extension methods.
       7             : /// {@endtemplate}
       8             : extension BatteriesStreamX<A> on Stream<A> {
       9             :   /// {@macro stream.relieve_stream_transformer}
      10           1 :   Stream<A> relieve([
      11             :     Duration duration = const Duration(milliseconds: 4),
      12             :   ]) =>
      13           2 :       transform<A>(RelieveStreamTransformer<A>(duration));
      14             : 
      15             :   /// {@macro stream.calm_stream_transformer}
      16           1 :   Stream<A> calm(Duration duration) =>
      17           2 :       transform<A>(CalmStreamTransformer<A>(duration));
      18             : 
      19             :   /// {@macro stream.transform_on_type.transformer}
      20           1 :   Stream<A> transformOnType<B extends A>(
      21             :     Stream<B> Function(Stream<B> selected) transform,
      22             :   ) =>
      23           2 :       this.transform(TransformOnTypeTransformer<A, B>(transform));
      24             : }
      25             : 
      26             : /// {@template stream.relieve_stream_transformer}
      27             : /// Allow relieve impact on event loop on large collections.
      28             : /// Parallelize the event queue and free up time for processing animation,
      29             : /// user gestures without using isolates.
      30             : ///
      31             : /// Thats transformer makes stream low priority.
      32             : ///
      33             : /// [duration] - elapsed time of iterations before releasing
      34             : /// the event queue and microtasks.
      35             : /// {@endtemplate}
      36             : @immutable
      37             : class RelieveStreamTransformer<T> extends StreamTransformerBase<T, T> {
      38             :   /// {@macro stream.relieve_stream_transformer}
      39           1 :   const RelieveStreamTransformer([
      40             :     this.duration = const Duration(milliseconds: 4),
      41             :   ]);
      42             : 
      43             :   /// Elapsed time of iterations before releasing
      44             :   /// the event queue and microtasks.
      45             :   final Duration duration;
      46             : 
      47           1 :   @override
      48             :   Stream<T> bind(Stream<T> stream) {
      49             :     /* 
      50             :     final sw = Stopwatch()..start();
      51             :     StreamSubscription<A>? sub;
      52             :     final sc = stream.isBroadcast
      53             :         ? StreamController<A>.broadcast(
      54             :             onCancel: () => sub?.cancel(),
      55             :             sync: true,
      56             :           )
      57             :         : StreamController<A>(
      58             :             onCancel: () => sub?.cancel(),
      59             :             sync: true,
      60             :           );
      61             :     sub = stream.listen(
      62             :       (A value) {
      63             :         if (sw.elapsed > duration) {
      64             :           sub?.pause();
      65             :           Future<void>.delayed(Duration.zero).then<void>(
      66             :             (_) {
      67             :               sc.add(value);
      68             :               sw.reset();
      69             :               sub?.resume();
      70             :             },
      71             :             onError: sc.addError,
      72             :           );
      73             :         } else {
      74             :           sc.add(value);
      75             :         }
      76             :       },
      77             :       onDone: () {
      78             :         sw.stop();
      79             :         sc.close();
      80             :       },
      81             :       onError: sc.addError,
      82             :       cancelOnError: false,
      83             :     );
      84             :     return sc.stream;
      85             :     */
      86           1 :     final controller = stream.isBroadcast
      87           1 :         ? StreamController<T>.broadcast(
      88             :             onListen: null,
      89             :             onCancel: null,
      90             :             sync: false,
      91             :           )
      92           1 :         : StreamController<T>(
      93             :             onListen: null,
      94             :             onCancel: null,
      95             :             onPause: null,
      96             :             onResume: null,
      97             :             sync: false,
      98             :           );
      99           1 :     final add = controller.add;
     100           1 :     final addError = controller.addError;
     101           1 :     final close = controller.close;
     102           2 :     controller.onListen = () {
     103           2 :       final stopwatch = Stopwatch()..start();
     104           1 :       final subscription = stream.listen(
     105             :         null,
     106             :         onError: addError,
     107           1 :         onDone: () {
     108           1 :           stopwatch.stop();
     109           1 :           close();
     110             :         },
     111             :       );
     112           1 :       final resume = subscription.resume;
     113           2 :       subscription.onData((T event) {
     114           3 :         if (stopwatch.elapsed > duration) {
     115           1 :           subscription.pause();
     116           2 :           Future<void>.delayed(Duration.zero).then<void>(
     117           1 :             (_) {
     118           1 :               add(event);
     119           1 :               stopwatch.reset();
     120           1 :               resume();
     121             :             },
     122             :             onError: addError,
     123             :           );
     124             :         } else {
     125           1 :           add(event);
     126             :         }
     127             :       });
     128           2 :       controller.onCancel = () {
     129           1 :         stopwatch.stop();
     130           1 :         subscription.cancel();
     131             :       };
     132           1 :       if (!stream.isBroadcast) {
     133             :         controller
     134           2 :           ..onPause = subscription.pause
     135           1 :           ..onResume = resume;
     136             :       }
     137             :     };
     138           1 :     return controller.stream;
     139             :   }
     140             : }
     141             : 
     142             : /// {@template stream.transform_on_type.transformer}
     143             : /// Allows to transform a stream on a specific subtype of events.
     144             : ///
     145             : /// The transformer performs the transformation on the events of the specified
     146             : /// type, while merging the rest of the stream in the output stream.
     147             : ///
     148             : /// The following set of actions are performed:
     149             : ///   1) The stream that contains only the specified subtype of events is
     150             : ///   filtered out from the rest.
     151             : ///   2) The newly filtered stream is passed to the specified [transform]
     152             : ///   callback.
     153             : ///   3) The rest of the stream is filtered out.
     154             : ///   4) Two stream are merged into one.
     155             : ///
     156             : /// [transform] –
     157             : ///   {@template stream.transform_on_type.transform}
     158             : ///   Callback that performs an endomorphic transformation on the
     159             : ///   stream of specified subtype.
     160             : ///   {@endtemplate}
     161             : /// {@endtemplate}
     162             : @immutable
     163             : class TransformOnTypeTransformer<A, B extends A>
     164             :     extends StreamTransformerBase<A, A> {
     165             :   /// {@macro stream.transform_on_type.transform}
     166             :   final Stream<B> Function(Stream<B> selected) transform;
     167             : 
     168             :   /// {@macro stream.transform_on_type.transformer}
     169           1 :   const TransformOnTypeTransformer(this.transform);
     170             : 
     171           1 :   @override
     172             :   Stream<A> bind(Stream<A> stream) {
     173           1 :     final source = stream.asBroadcastStream();
     174             : 
     175             :     StreamSubscription<A>? remainingSubscription;
     176             :     StreamSubscription<A>? transformedSubscription;
     177             : 
     178           0 :     void pauseSubscriptions() {
     179           0 :       remainingSubscription?.pause();
     180           0 :       transformedSubscription?.pause();
     181             :     }
     182             : 
     183           0 :     void resumeSubscriptions() {
     184           0 :       remainingSubscription?.resume();
     185           0 :       transformedSubscription?.resume();
     186             :     }
     187             : 
     188           1 :     final controller = stream.isBroadcast
     189           1 :         ? StreamController<A>.broadcast(sync: true)
     190           1 :         : StreamController<A>(
     191             :             onPause: pauseSubscriptions,
     192             :             onResume: resumeSubscriptions,
     193             :             sync: true,
     194             :           );
     195             : 
     196           1 :     void subscribe({
     197             :       required Stream<A> stream,
     198             :       required void Function(StreamSubscription<A> subscription) store,
     199             :       void Function()? onDone,
     200             :     }) {
     201           1 :       store(
     202           1 :         stream.listen(
     203           1 :           controller.add,
     204           1 :           onError: controller.addError,
     205             :           onDone: onDone,
     206             :           cancelOnError: false,
     207             :         ),
     208             :       );
     209             :     }
     210             : 
     211           1 :     void cancelSubscriptions() {
     212           1 :       remainingSubscription?.cancel();
     213           1 :       transformedSubscription?.cancel();
     214             :     }
     215             : 
     216           1 :     void wrapUp() {
     217           1 :       cancelSubscriptions();
     218           1 :       controller.close();
     219             :     }
     220             : 
     221           1 :     void startListening() {
     222           1 :       subscribe(
     223           3 :         stream: source.where((event) => event is! B),
     224           1 :         store: (subscription) => remainingSubscription = subscription,
     225             :         onDone: wrapUp,
     226             :       );
     227           1 :       subscribe(
     228           6 :         stream: transform(source.where((event) => event is B).cast<B>()),
     229           1 :         store: (subscription) => transformedSubscription = subscription,
     230             :       );
     231             :     }
     232             : 
     233             :     controller
     234           1 :       ..onListen = startListening
     235           1 :       ..onCancel = cancelSubscriptions;
     236             : 
     237           1 :     return controller.stream;
     238             :   }
     239             : }
     240             : 
     241             : /// {@template stream.calm_stream_transformer}
     242             : /// Calm stream transformer.
     243             : /// For example, when you need a pause between events no less than specified.
     244             : /// e.g sending messages to the messenger with intervals and pauses,
     245             : /// in order not to be banned for spam.
     246             : /// {@endtemplate}
     247             : @immutable
     248             : class CalmStreamTransformer<T> extends StreamTransformerBase<T, T> {
     249             :   /// {@macro stream.calm_stream_transformer}
     250           1 :   const CalmStreamTransformer(this.duration);
     251             : 
     252             :   /// Elapsed time of iterations before releasing next event.
     253             :   final Duration duration;
     254             : 
     255           1 :   @override
     256             :   Stream<T> bind(Stream<T> stream) {
     257           1 :     final controller = stream.isBroadcast
     258           1 :         ? StreamController<T>.broadcast(
     259             :             onListen: null,
     260             :             onCancel: null,
     261             :             sync: false,
     262             :           )
     263           1 :         : StreamController<T>(
     264             :             onListen: null,
     265             :             onCancel: null,
     266             :             onPause: null,
     267             :             onResume: null,
     268             :             sync: false,
     269             :           );
     270           1 :     final add = controller.add;
     271           1 :     final addError = controller.addError;
     272           1 :     final close = controller.close;
     273           2 :     controller.onListen = () {
     274           1 :       final subscription = stream.listen(
     275             :         null,
     276             :         onError: addError,
     277             :         onDone: close,
     278             :       );
     279           1 :       final pause = subscription.pause;
     280           1 :       final resume = subscription.resume;
     281           2 :       subscription.onData((T event) {
     282           1 :         add(event);
     283           1 :         pause();
     284           2 :         Future<void>.delayed(duration)
     285           1 :             .catchError(addError)
     286           1 :             .whenComplete(resume);
     287             :       });
     288           2 :       controller.onCancel = subscription.cancel;
     289           1 :       if (!stream.isBroadcast) {
     290             :         controller
     291           1 :           ..onPause = pause
     292           1 :           ..onResume = resume;
     293             :       }
     294             :     };
     295           1 :     return controller.stream;
     296             :   }
     297             : }

Generated by: LCOV version 1.15