MotorSignal-App/lib/features/performance/services/monotonic_clock.dart

71 lines
2.1 KiB
Dart

/// Authoritative monotonic clock interface for performance timing.
///
/// Decouples time-delta calculations from system wall-clock mutations
/// (e.g. NTP updates, time zone changes, manual clock edits).
abstract class MonotonicClock {
/// Monotonic elapsed time in milliseconds from clock baseline.
int get elapsedMilliseconds;
/// Monotonic elapsed time in microseconds from clock baseline.
int get elapsedMicroseconds;
/// Current wall-clock time for metadata recording only.
DateTime get now;
}
/// Standard production monotonic clock powered by a high-resolution [Stopwatch].
class SystemMonotonicClock implements MonotonicClock {
final Stopwatch _stopwatch;
SystemMonotonicClock([Stopwatch? stopwatch])
: _stopwatch = stopwatch ?? (Stopwatch()..start());
@override
int get elapsedMilliseconds => _stopwatch.elapsedMilliseconds;
@override
int get elapsedMicroseconds => _stopwatch.elapsedMicroseconds;
@override
DateTime get now => DateTime.now();
}
/// Deterministic fake monotonic clock for hermetic unit testing.
class FakeMonotonicClock implements MonotonicClock {
int _elapsedMilliseconds;
DateTime _wallClockTime;
FakeMonotonicClock({
int initialElapsedMs = 0,
DateTime? initialDateTime,
}) : _elapsedMilliseconds = initialElapsedMs,
_wallClockTime = initialDateTime ?? DateTime(2026, 9, 5, 12, 0, 0);
@override
int get elapsedMilliseconds => _elapsedMilliseconds;
@override
int get elapsedMicroseconds => _elapsedMilliseconds * 1000;
@override
DateTime get now => _wallClockTime;
/// Advance monotonic time and optionally wall clock time.
void advance(Duration duration, {bool advanceWallClock = true}) {
_elapsedMilliseconds += duration.inMilliseconds;
if (advanceWallClock) {
_wallClockTime = _wallClockTime.add(duration);
}
}
/// Explicitly set elapsed milliseconds.
void setElapsedMs(int ms) {
_elapsedMilliseconds = ms;
}
/// Simulate a sudden wall-clock jump (e.g. NTP sync / time travel) without affecting monotonic time.
void setWallClock(DateTime time) {
_wallClockTime = time;
}
}