/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; namespace dnSpy.Contracts.Debugger.Exceptions { /// /// Exception ID /// public readonly struct DbgExceptionId : IEquatable { readonly string category; readonly string? name; readonly int code; readonly Flags flags; [Flags] enum Flags : byte { KindMask = 3, } /// /// Gets the id kind /// public DbgExceptionIdKind Kind => (DbgExceptionIdKind)(flags & Flags.KindMask); /// /// Exception category, same as /// public string Category => category; /// /// Name of exception (case insensitive). This property is only valid if is true /// public string? Name => name; /// /// Exception code. This property is only valid if is true /// public int Code => code; /// /// true if the exception has a code, and not a name /// public bool HasCode => Kind == DbgExceptionIdKind.Code; /// /// true if the exception has a name, and not a code /// public bool HasName => Kind == DbgExceptionIdKind.Name; /// /// true if this is the default exception ID /// public bool IsDefaultId => Kind == DbgExceptionIdKind.DefaultId; /// /// Constructor for default ids /// /// Exception category, same as public DbgExceptionId(string category) { this.category = category ?? throw new ArgumentNullException(nameof(category)); name = null; code = 0; flags = (Flags)DbgExceptionIdKind.DefaultId; } /// /// Constructor /// /// Exception category, same as /// Name of exception, must not be null public DbgExceptionId(string category, string name) { this.category = category ?? throw new ArgumentNullException(nameof(category)); this.name = name ?? throw new ArgumentNullException(nameof(name)); code = 0; flags = (Flags)DbgExceptionIdKind.Name; } /// /// Constructor /// /// Exception category, same as /// Exception code public DbgExceptionId(string category, int code) { this.category = category ?? throw new ArgumentNullException(nameof(category)); name = null; this.code = code; flags = (Flags)DbgExceptionIdKind.Code; } /// /// Constructor /// /// Exception category, same as /// Exception code public DbgExceptionId(string category, uint code) : this(category, (int)code) { } #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member public static bool operator ==(DbgExceptionId left, DbgExceptionId right) => left.Equals(right); public static bool operator !=(DbgExceptionId left, DbgExceptionId right) => !left.Equals(right); #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member /// /// Equals() /// /// Other instance /// public bool Equals(DbgExceptionId other) { if (flags != other.flags) return false; if (Kind == DbgExceptionIdKind.Code) { if (code != other.code) return false; } else { if (!StringComparer.OrdinalIgnoreCase.Equals(name, other.name)) return false; } if (!StringComparer.Ordinal.Equals(category, other.category)) return false; return true; } /// /// Equals() /// /// /// public override bool Equals(object? obj) => obj is DbgExceptionId other && Equals(other); /// /// Gets the hashcode /// /// public override int GetHashCode() { int hc = (int)flags ^ StringComparer.Ordinal.GetHashCode(category ?? string.Empty); if (Kind == DbgExceptionIdKind.Code) hc ^= code; else hc ^= StringComparer.OrdinalIgnoreCase.GetHashCode(name ?? string.Empty); return hc; } /// /// ToString() /// /// public override string ToString() { if (category is null) return ""; switch (Kind) { case DbgExceptionIdKind.DefaultId: return category + " - <>"; case DbgExceptionIdKind.Code: return "0x" + code.ToString("X8"); case DbgExceptionIdKind.Name: return category + " - " + name; default: return "???"; } } } /// /// kind /// public enum DbgExceptionIdKind { /// /// Default ID /// DefaultId, /// /// Code /// Code, /// /// Name /// Name, } }