Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ namespace Microsoft.Macios.Generator.Availability;
/// The supported version of the platform. If null, that means that the user did not add a SupportedOSPlatform
/// attribute.
/// </summary>
public Version? SupportedVersion { get; }
public PlatformSupportVersion? SupportedVersion { get; }

readonly SortedDictionary<Version, string?> unsupported = new ();
readonly SortedDictionary<PlatformSupportVersion, string?> unsupported = new ();

/// <summary>
/// Dictionary that contains all the obsoleted versions and their optional data.
/// </summary>
public IReadOnlyDictionary<Version, string?> UnsupportedVersions => unsupported;
public IReadOnlyDictionary<PlatformSupportVersion, string?> UnsupportedVersions => unsupported;

readonly SortedDictionary<Version, (string? Message, string? Url)> obsoleted = new ();

Expand All @@ -53,21 +53,21 @@ public bool IsSupported {
// a platform is supported if:
// 1. The supported version is not null, either the default version or a specific one
// 2. The default version is not in the unsupported list
return SupportedVersion is not null && !unsupported.ContainsKey (defaultVersion);
return SupportedVersion is not null
&& !unsupported.ContainsKey (PlatformSupportVersion.ImplicitDefault)
&& !unsupported.ContainsKey (PlatformSupportVersion.ExplicitDefault);
}
}


/// <summary>
/// Returns if a version is the default version.
/// </summary>
/// <param name="version">Version being tested.</param>
/// <returns>True if the version is default.</returns>
public static bool IsDefaultVersion (Version version) => version == defaultVersion;


PlatformAvailability (ApplePlatform platform, Version? supportedVersion,
SortedDictionary<Version, string?> unsupportedVersions,
PlatformAvailability (ApplePlatform platform, PlatformSupportVersion? supportedVersion,
SortedDictionary<PlatformSupportVersion, string?> unsupportedVersions,
SortedDictionary<Version, (string? Message, string? Url)> obsoletedVersions)
{
Platform = platform;
Expand Down Expand Up @@ -126,11 +126,9 @@ public PlatformAvailability MergeWithParent (PlatformAvailability? parent)
// 2. if supported in the platform, we will always pick the larges version between
// the two. Now, because we might be unsupported

var supportedVersion = (parent.Value.SupportedVersion > SupportedVersion)
? parent.Value.SupportedVersion
: SupportedVersion;
var supportedVersion = PlatformSupportVersion.Max (parent.Value.SupportedVersion, SupportedVersion);
if (supportedVersion is not null)
builder.AddSupportedVersion (supportedVersion);
builder.AddSupportedVersion (supportedVersion.Value);

// similar to the unsupported versions, if the parent has obsolete ones, we will add them
foreach (var (version, obsoleteInfo) in parent.Value.obsoleted) {
Expand All @@ -148,7 +146,7 @@ public PlatformAvailability MergeWithParent (PlatformAvailability? parent)
public bool Equals (PlatformAvailability other)
{
var obsoleteComparer = new DictionaryComparer<Version, (string?, string?)> ();
var unsupportedComparer = new DictionaryComparer<Version, string?> ();
var unsupportedComparer = new DictionaryComparer<PlatformSupportVersion, string?> ();

var x = Equals (SupportedVersion, other.SupportedVersion);
return Platform == other.Platform &&
Expand Down Expand Up @@ -184,9 +182,9 @@ public override string ToString ()
{
var sb = new StringBuilder ("{ ");
sb.Append ($"Platform: '{Platform}', ");
sb.Append ($"Supported: '{SupportedVersion?.ToString ()}', ");
sb.Append ($"Supported: '{SupportedVersion?.Version.ToString ()}', ");
sb.Append ("Unsupported: [");
sb.AppendJoin (", ", unsupported.Select (v => $"'{v.Key}': '{v.Value?.ToString () ?? "null"}'"));
sb.AppendJoin (", ", unsupported.Select (v => $"'{v.Key.Version}': '{v.Value?.ToString () ?? "null"}'"));
sb.Append ("], Obsoleted: [");
sb.AppendJoin (", ", obsoleted.Select (v => $"'{v.Key}': ('{v.Value.Message?.ToString () ?? "null"}', '{v.Value.Url?.ToString () ?? "null"}')"));
sb.Append ("] }");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ readonly partial struct PlatformAvailability {
/// A writable PlatformAvailability accessor.
/// </summary>
public sealed class Builder {
static readonly PlatformSupportVersionComparer versionComparer = new ();
readonly ApplePlatform platform;
Version? supportedVersion;
readonly SortedDictionary<Version, string?> unsupported = new ();
PlatformSupportVersion? supportedVersion;
readonly SortedDictionary<PlatformSupportVersion, string?> unsupported = new (versionComparer);
readonly SortedDictionary<Version, (string? Message, string? Url)> obsoleted = new ();

/// <summary>
Expand All @@ -36,15 +37,16 @@ public sealed class Builder {
/// else the version is ignored.
/// </summary>
/// <param name="version">A new supported version.</param>
internal void AddSupportedVersion (Version version)
internal void AddSupportedVersion (PlatformSupportVersion version)
{
if (unsupported.ContainsKey (defaultVersion))
// platform is unsupported, do nothing
if (unsupported.ContainsKey (PlatformSupportVersion.ExplicitDefault))
// platform is explicitly unsupported, do nothing
return;

// update the supported version to the larges of the two
if (supportedVersion is null || version > supportedVersion)
supportedVersion = version;
supportedVersion = supportedVersion is null
? version
: PlatformSupportVersion.Max (version, supportedVersion.Value);
}

/// <summary>
Expand All @@ -57,32 +59,35 @@ public void Add (SupportedOSPlatformData supportedPlatform)
if (supportedPlatform.Platform != platform)
return;
// no version is present, therefore try to set the default one
AddSupportedVersion (supportedPlatform.Version);
AddSupportedVersion (new (supportedPlatform.Version, SupportKind.Explicit));
}

/// <summary>
/// Adds a new version to the list of unsupported versions. If the platform is unsupported, the version is ignored.
/// </summary>
/// <param name="version">The new unsupported version.</param>
/// <param name="message">The optional message of the unsupported version.</param>
internal void AddUnsupportedVersion (Version version, string? message)
internal void AddUnsupportedVersion (PlatformSupportVersion version, string? message)
{
// adding an unsupported version, due to the way the API is designed is more complicated. It can be
// that a selector/member is unsupported in more than one version, so we need to keep track of that
// the only time in which we make an exception is when we unsupported a platform (no version number)
// if that is the case, we will remove all unsupported versions and just un-support the platform
// ignore data from platforms that we do not care
if (version == defaultVersion) {
if (version == PlatformSupportVersion.ExplicitDefault) {
unsupported.Clear ();
unsupported [defaultVersion] = message;
unsupported [PlatformSupportVersion.ExplicitDefault] = message;
// we are unsupporting the platform! that means if we supported it or any version, that should be
// set back to null
supportedVersion = null;
} else {
// we have a version, that does not mean we do care about that data, first we want to check
// that we did not fully unsupported the platform, if that is the case, we ignore this version
if (unsupported.ContainsKey (defaultVersion))
if (unsupported.ContainsKey (PlatformSupportVersion.ExplicitDefault))
return;

// we implicitly unsupported the platform, remove that entry since we are adding a version
unsupported.Remove (PlatformSupportVersion.ImplicitDefault);
unsupported [version] = message;
}
}
Expand All @@ -95,7 +100,7 @@ public void Add (UnsupportedOSPlatformData unsupportedPlatform)
{
if (unsupportedPlatform.Platform != platform)
return;
AddUnsupportedVersion (unsupportedPlatform.Version, unsupportedPlatform.Message);
AddUnsupportedVersion (new (unsupportedPlatform.Version, SupportKind.Explicit), unsupportedPlatform.Message);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;

namespace Microsoft.Macios.Generator.Availability;

/// <summary>
/// Represents a platform support version, combining a version number and a support kind.
/// </summary>
public readonly record struct PlatformSupportVersion : IComparable<PlatformSupportVersion> {
/// <summary>
/// Gets the version number.
/// </summary>
public Version Version { get; init; }
/// <summary>
/// Gets the kind of support (e.g., explicit, implicit).
/// </summary>
public SupportKind Kind { get; init; }

/// <summary>
/// Gets a default platform support version with an implicit kind.
/// </summary>
public static PlatformSupportVersion ImplicitDefault { get; } = new () {
Version = new (),
Kind = SupportKind.Implicit
};

/// <summary>
/// Gets a default platform support version with an explicit kind.
/// </summary>
public static PlatformSupportVersion ExplicitDefault { get; } = new () {
Version = new (),
Kind = SupportKind.Explicit
};

/// <summary>
/// Initializes a new instance of the <see cref="PlatformSupportVersion"/> struct.
/// </summary>
/// <param name="version">The version number.</param>
/// <param name="kind">The kind of support.</param>
public PlatformSupportVersion (Version version, SupportKind kind)
{
Version = version;
Kind = kind;
}

/// <summary>
/// Initializes a new instance of the <see cref="PlatformSupportVersion"/> struct with an explicit support kind.
/// </summary>
/// <param name="version">The version number.</param>
public PlatformSupportVersion (Version version) : this (version, SupportKind.Explicit) { }

/// <summary>
/// Returns the platform support version with the highest precedence.
/// </summary>
/// <param name="v1">The first platform support version to compare.</param>
/// <param name="v2">The second platform support version to compare.</param>
/// <returns>
/// The platform support version with the highest precedence. If the kinds are the same, it returns the one with the greater version.
/// If the kinds are different, it returns the one with the higher kind value.
/// </returns>
public static PlatformSupportVersion? Max (PlatformSupportVersion? v1, PlatformSupportVersion? v2)
{
if (v1 is null)
return v2;
if (v2 is null)
return v1;

if (v1.Value.Kind == v2.Value.Kind) {
return v1.Value.Version >= v2.Value.Version ? v1 : v2;
}
return (int) v1.Value.Kind > (int) v2.Value.Kind ? v1 : v2;
}

/// <summary>
/// Returns the platform support version with the lowest version if the kinds are the same, otherwise returns the one with the highest precedence kind.
/// </summary>
/// <param name="v1">The first platform support version to compare.</param>
/// <param name="v2">The second platform support version to compare.</param>
/// <returns>
/// The platform support version with the lowest version if the kinds are the same.
/// If the kinds are different, it returns the one with the higher kind value.
/// </returns>
public static PlatformSupportVersion? Min (PlatformSupportVersion? v1, PlatformSupportVersion? v2)
{
if (v1 is null)
return v2;
if (v2 is null)
return v1;
if (v1.Value.Kind == v2.Value.Kind) {
return v1.Value.Version <= v2.Value.Version ? v1 : v2;
}
return (int) v1.Value.Kind > (int) v2.Value.Kind ? v1 : v2;
}

/// <inheritdoc />
public int CompareTo (PlatformSupportVersion other)
{
var versionComparison = Version.CompareTo (other.Version);
if (versionComparison != 0)
return versionComparison;
return Kind.CompareTo (other.Kind);
}

/// <summary>
/// Compares two <see cref="PlatformSupportVersion"/> instances to determine if the left is less than the right.
/// </summary>
/// <param name="left">The first <see cref="PlatformSupportVersion"/> to compare.</param>
/// <param name="right">The second <see cref="PlatformSupportVersion"/> to compare.</param>
/// <returns><c>true</c> if the left instance is less than the right instance; otherwise, <c>false</c>.</returns>
public static bool operator < (PlatformSupportVersion left, PlatformSupportVersion right)
{
return left.CompareTo (right) < 0;
}

/// <summary>
/// Compares two <see cref="PlatformSupportVersion"/> instances to determine if the left is greater than the right.
/// </summary>
/// <param name="left">The first <see cref="PlatformSupportVersion"/> to compare.</param>
/// <param name="right">The second <see cref="PlatformSupportVersion"/> to compare.</param>
/// <returns><c>true</c> if the left instance is greater than the right instance; otherwise, <c>false</c>.</returns>
public static bool operator > (PlatformSupportVersion left, PlatformSupportVersion right)
{
return left.CompareTo (right) > 0;
}

/// <summary>
/// Compares two <see cref="PlatformSupportVersion"/> instances to determine if the left is less than or equal to the right.
/// </summary>
/// <param name="left">The first <see cref="PlatformSupportVersion"/> to compare.</param>
/// <param name="right">The second <see cref="PlatformSupportVersion"/> to compare.</param>
/// <returns><c>true</c> if the left instance is less than or equal to the right instance; otherwise, <c>false</c>.</returns>
public static bool operator <= (PlatformSupportVersion left, PlatformSupportVersion right)
{
return left.CompareTo (right) <= 0;
}

/// <summary>
/// Compares two <see cref="PlatformSupportVersion"/> instances to determine if the left is greater than or equal to the right.
/// </summary>
/// <param name="left">The first <see cref="PlatformSupportVersion"/> to compare.</param>
/// <param name="right">The second <see cref="PlatformSupportVersion"/> to compare.</param>
/// <returns><c>true</c> if the left instance is greater than or equal to the right instance; otherwise, <c>false</c>.</returns>
public static bool operator >= (PlatformSupportVersion left, PlatformSupportVersion right)
{
return left.CompareTo (right) >= 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections.Generic;

namespace Microsoft.Macios.Generator.Availability;

/// <summary>
/// Compares two <see cref="PlatformSupportVersion"/> instances for sorting.
/// </summary>
public class PlatformSupportVersionComparer : IComparer<PlatformSupportVersion> {

/// <summary>
/// Compares two platform support versions and returns a value indicating whether one is less than, equal to, or greater than the other.
/// </summary>
/// <param name="x">The first object to compare.</param>
/// <param name="y">The second object to compare.</param>
/// <returns>A signed integer that indicates the relative values of x and y.</returns>
public int Compare (PlatformSupportVersion x, PlatformSupportVersion y)
{
int versionComparison = x.Version.CompareTo (y.Version);
if (versionComparison != 0) return versionComparison;
return x.Kind.CompareTo (y.Kind);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

namespace Microsoft.Macios.Generator.Availability;

public enum SupportKind {
Implicit,
Explicit
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ internal void AddSupportedVersion (ApplePlatform platform, Version version)
if (!supportedPlatforms.Contains (platform))
return;
var builder = GetBuilder (platform);
builder.AddSupportedVersion (version);
builder.AddSupportedVersion (new (version, SupportKind.Explicit));
}

/// <summary>
Expand Down Expand Up @@ -118,7 +118,7 @@ internal void AddUnsupportedVersion (ApplePlatform platform, Version version, st
return;

var builder = GetBuilder (platform);
builder.AddUnsupportedVersion (version, message);
builder.AddUnsupportedVersion (new (version, SupportKind.Explicit), message);
}

/// <summary>
Expand Down
Loading
Loading