blob: 5759b5e65f7e005e1bd02c42905f32d8fd3c8d61 [file] [log] [blame]
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
/**
* The status of analysis.
*/
class AnalysisStatus {
static const IDLE = const AnalysisStatus._(false);
static const ANALYZING = const AnalysisStatus._(true);
final bool _analyzing;
const AnalysisStatus._(this._analyzing);
/**
* Return `true` if the scheduler is analyzing.
*/
bool get isAnalyzing => _analyzing;
/**
* Return `true` if the scheduler is idle.
*/
bool get isIdle => !_analyzing;
@override
String toString() => _analyzing ? 'analyzing' : 'idle';
}
/**
* [Monitor] can be used to wait for a signal.
*
* Signals are not queued, the client will receive exactly one signal
* regardless of the number of [notify] invocations. The [signal] is reset
* after completion and will not complete until [notify] is called next time.
*/
class Monitor {
Completer<Null> _completer = new Completer<Null>();
/**
* Return a [Future] that completes when [notify] is called at least once.
*/
Future<Null> get signal async {
await _completer.future;
_completer = new Completer<Null>();
}
/**
* Complete the [signal] future if it is not completed yet. It is safe to
* call this method multiple times, but the [signal] will complete only once.
*/
void notify() {
if (!_completer.isCompleted) {
_completer.complete(null);
}
}
}
/**
* Helper for managing transitioning [AnalysisStatus].
*/
class StatusSupport {
/**
* The controller for the [stream].
*/
final _statusController = new StreamController<AnalysisStatus>();
/**
* The last status sent to the [stream].
*/
AnalysisStatus _currentStatus = AnalysisStatus.IDLE;
/**
* If non-null, a completer which should be completed on the next transition
* to idle.
*/
Completer<Null> _idleCompleter;
/**
* Return the last status sent to the [stream].
*/
AnalysisStatus get currentStatus => _currentStatus;
/**
* Return the stream that produces [AnalysisStatus] events.
*/
Stream<AnalysisStatus> get stream => _statusController.stream;
/**
* Prepare for the scheduler to start analyzing, but do not notify the
* [stream] yet.
*
* A call to [preTransitionToAnalyzing] has the same effect on [waitForIdle]
* as a call to [transitionToAnalyzing], but it has no effect on the [stream].
*/
void preTransitionToAnalyzing() {
_idleCompleter ??= new Completer<Null>();
}
/**
* Send a notification to the [stream] that the scheduler started analyzing.
*/
void transitionToAnalyzing() {
if (_currentStatus != AnalysisStatus.ANALYZING) {
preTransitionToAnalyzing();
_currentStatus = AnalysisStatus.ANALYZING;
_statusController.add(AnalysisStatus.ANALYZING);
}
}
/**
* Send a notification to the [stream] stream that the scheduler is idle.
*/
void transitionToIdle() {
if (_currentStatus != AnalysisStatus.IDLE) {
_currentStatus = AnalysisStatus.IDLE;
_statusController.add(AnalysisStatus.IDLE);
}
_idleCompleter?.complete();
_idleCompleter = null;
}
/**
* Return a future that will be completed the next time the status is idle.
*
* If the status is currently idle, the returned future will be signaled
* immediately.
*/
Future<Null> waitForIdle() {
return _idleCompleter?.future ?? new Future.value();
}
}