blob: 9ff680cb5295b901a207c1fd611b14b680643267 [file] [log] [blame] [edit]
// Copyright (c) 2025, 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:io';
import 'package:pub_semver/pub_semver.dart';
import 'c_bindings_generated.dart' as c;
/// Returns the current MacOS/iOS version.
Version get osVersion => _osVersion;
Version _osVersion = () {
final ver = c.getOsVesion();
return Version(ver.major, ver.minor, ver.patch);
}();
/// Returns whether the current MacOS/iOS version is greater than or equal to
/// the given version.
///
/// Designed to replace Objective-C's `@available` check.
///
/// The each platform's version is optional, and the function returns false if
/// no version is provided for the current platform.
bool checkOSVersion({Version? iOS, Version? macOS}) {
if (Platform.isIOS) return _checkOSVersionImpl(iOS);
if (Platform.isMacOS) return _checkOSVersionImpl(macOS);
throw UnsupportedError('Only supported on iOS and macOS');
}
bool _checkOSVersionImpl(Version? version) {
if (version == null) return false;
return osVersion >= version;
}
final class OsVersionError implements Exception {
final String apiName;
final String message;
OsVersionError(this.apiName, this.message);
@override
String toString() => '$runtimeType: $apiName $message.';
}
typedef PlatformAvailability = (bool unavailable, (int, int, int)? introduced);
/// Only for use by ffigen bindings.
void checkOsVersionInternal(
String apiName, {
PlatformAvailability? iOS,
PlatformAvailability? macOS,
}) {
if (Platform.isIOS) _checkOsVersionInternalImpl(apiName, 'iOS', iOS);
if (Platform.isMacOS) _checkOsVersionInternalImpl(apiName, 'macOS', macOS);
}
void _checkOsVersionInternalImpl(
String apiName,
String osName,
PlatformAvailability? availability,
) {
if (availability == null) return;
final (bool unavailable, (int, int, int)? introduced) = availability;
if (unavailable) {
throw OsVersionError(apiName, 'is not supported on $osName');
}
if (introduced != null && osVersion < _toVersion(introduced)) {
throw OsVersionError(
apiName,
'is not supported on $osName before version $introduced.'
'The current version is $osVersion',
);
}
}
Version _toVersion((int, int, int) record) {
final (int major, int minor, int patch) = record;
return Version(major, minor, patch);
}