// Copyright Epic Games, Inc. All Rights Reserved. using System; using System.Collections.Generic; using System.Reflection; using System.Text; using EpicGames.Core; using EpicGames.UHT.Tokenizer; using EpicGames.UHT.Types; using EpicGames.UHT.Utils; namespace EpicGames.UHT.Tables { /// /// Delegate for invoking structure default value sanitizer /// /// /// /// /// public delegate bool UhtStructDefaultValueDelegate(UhtStructProperty property, IUhtTokenReader defaultValueReader, StringBuilder innerDefaultValue); /// /// Options for structure default value sanitizer /// [Flags] public enum UhtStructDefaultValueOptions { /// /// No options /// None = 0, /// /// This method is to be invoked when there are no keyword matches found /// Default = 1 << 2, } /// /// Helper methods for testing flags. These methods perform better than the generic HasFlag which hits /// the GC and stalls. /// public static class UhtStructDefaultValueOptionsExtensions { /// /// Test to see if any of the specified flags are set /// /// Current flags /// Flags to test for /// True if any of the flags are set public static bool HasAnyFlags(this UhtStructDefaultValueOptions inFlags, UhtStructDefaultValueOptions testFlags) { return (inFlags & testFlags) != 0; } /// /// Test to see if all of the specified flags are set /// /// Current flags /// Flags to test for /// True if all the flags are set public static bool HasAllFlags(this UhtStructDefaultValueOptions inFlags, UhtStructDefaultValueOptions testFlags) { return (inFlags & testFlags) == testFlags; } /// /// Test to see if a specific set of flags have a specific value. /// /// Current flags /// Flags to test for /// Expected value of the tested flags /// True if the given flags have a specific value. public static bool HasExactFlags(this UhtStructDefaultValueOptions inFlags, UhtStructDefaultValueOptions testFlags, UhtStructDefaultValueOptions matchFlags) { return (inFlags & testFlags) == matchFlags; } } /// /// Structure default value sanitizer attribute /// [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public sealed class UhtStructDefaultValueAttribute : Attribute { /// /// Name of the structure. Not required for default processor. /// public string? Name { get; set; } /// /// Options /// public UhtStructDefaultValueOptions Options { get; set; } = UhtStructDefaultValueOptions.None; } /// /// Structure default value sanitizer /// public struct UhtStructDefaultValue { /// /// The delegate to invoke /// public UhtStructDefaultValueDelegate Delegate { get; set; } } /// /// Table of all structure default value specifiers /// public class UhtStructDefaultValueTable { private readonly Dictionary _structDefaultValues = new(); private UhtStructDefaultValue? _default = null; /// /// Fetch the default sanitizer /// public UhtStructDefaultValue Default { get { if (_default == null) { throw new UhtIceException("No struct default value has been marked as default"); } return (UhtStructDefaultValue)_default; } } /// /// Return the structure default value associated with the given name /// /// /// Structure default value handler /// public bool TryGet(StringView name, out UhtStructDefaultValue structDefaultValue) { return _structDefaultValues.TryGetValue(name, out structDefaultValue); } /// /// Handle a structure default value sanitizer attribute /// /// Method information /// Found attribute /// Thrown if the attribute isn't property defined public void OnStructDefaultValueAttribute(MethodInfo methodInfo, UhtStructDefaultValueAttribute structDefaultValueAttribute) { if (String.IsNullOrEmpty(structDefaultValueAttribute.Name) && !structDefaultValueAttribute.Options.HasAnyFlags(UhtStructDefaultValueOptions.Default)) { throw new UhtIceException("A struct default value attribute must have a name or be marked as default"); } UhtStructDefaultValue structDefaultValue = new() { Delegate = (UhtStructDefaultValueDelegate)Delegate.CreateDelegate(typeof(UhtStructDefaultValueDelegate), methodInfo) }; if (structDefaultValueAttribute.Options.HasAnyFlags(UhtStructDefaultValueOptions.Default)) { if (_default != null) { throw new UhtIceException("Only one struct default value attribute dispatcher can be marked as default"); } _default = structDefaultValue; } else if (!String.IsNullOrEmpty(structDefaultValueAttribute.Name)) { _structDefaultValues.Add(new StringView(structDefaultValueAttribute.Name), structDefaultValue); } } } }