// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using EpicGames.UHT.Utils;
namespace EpicGames.UHT.Tables
{
///
/// Delegate to invoke to run exporter
///
/// Factory used to generate export tasks and outputs
public delegate void UhtExporterDelegate(IUhtExportFactory factory);
///
/// Export options
///
[Flags]
public enum UhtExporterOptions
{
///
/// No options
///
None = 0,
///
/// The exporter should be run by default
///
Default = 1 << 0,
///
/// Generated CPP files that match any filter in the CppFilters property of this UhtExporter will be included in the compilation process.
/// For this option, all custom generated files should be placed into the same folder as the default unreal generated files.
/// Make sure the CppFilters property is set up properly and does not conflict with other exporters (including the default).
/// Header files should be included as normal in code.
///
CompileOutput = 1 << 1,
}
///
/// Helper methods for testing flags. These methods perform better than the generic HasFlag which hits
/// the GC and stalls.
///
public static class UhtExporterOptionsExtensions
{
///
/// 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 UhtExporterOptions inFlags, UhtExporterOptions 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 UhtExporterOptions inFlags, UhtExporterOptions 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 UhtExporterOptions inFlags, UhtExporterOptions testFlags, UhtExporterOptions matchFlags)
{
return (inFlags & testFlags) == matchFlags;
}
}
///
/// Defines an exporter
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class UhtExporterAttribute : Attribute
{
///
/// Name of the exporter
///
public string Name { get; set; } = String.Empty;
///
/// Description of the export. Used to display help
///
public string Description { get; set; } = String.Empty;
///
/// Exporters in plugins need to specify a module name
///
public string ModuleName { get; set; } = String.Empty;
///
/// Exporter options
///
public UhtExporterOptions Options { get; set; } = UhtExporterOptions.None;
///
/// Collection of filters used to delete old cpp files
///
public string[]? CppFilters { get; set; }
///
/// Collection of filters used to delete old h files
///
public string[]? HeaderFilters { get; set; }
///
/// Collection of filters for other file types
///
public string[]? OtherFilters { get; set; }
}
///
/// Defines an exporter in the table
///
public readonly struct UhtExporter
{
///
/// Name of the exporter
///
public string Name { get; }
///
/// Description of the export. Used to display help
///
public string Description { get; }
///
/// Exporters in plugins need to specify a module name
///
public string ModuleName { get; }
///
/// Exporter options
///
public UhtExporterOptions Options { get; }
///
/// Delegate to invoke to start export
///
public UhtExporterDelegate Delegate { get; }
///
/// Collection of filters used to delete old cpp files
///
public IReadOnlyList CppFilters { get; }
///
/// Collection of filters used to delete old h files
///
public IReadOnlyList HeaderFilters { get; }
///
/// Collection of filters for other file types
///
public IReadOnlyList OtherFilters { get; }
///
/// Construct an exporter table instance
///
/// Source attribute
/// Delegate to invoke
public UhtExporter(UhtExporterAttribute attribute, UhtExporterDelegate exporterDelegate)
{
Name = attribute.Name;
Description = attribute.Description;
ModuleName = attribute.ModuleName;
Options = attribute.Options;
Delegate = exporterDelegate;
CppFilters = attribute.CppFilters != null ? new List(attribute.CppFilters) : new List();
HeaderFilters = attribute.HeaderFilters != null ? new List(attribute.HeaderFilters) : new List();
OtherFilters = attribute.OtherFilters != null ? new List(attribute.OtherFilters) : new List();
}
}
///
/// Exporter table
///
public class UhtExporterTable : IEnumerable
{
private readonly Dictionary _exporterValues = new(StringComparer.OrdinalIgnoreCase);
///
/// Return the exporter associated with the given name
///
///
/// Exporter associated with the name
///
public bool TryGet(string name, out UhtExporter value)
{
return _exporterValues.TryGetValue(name, out value);
}
///
/// Handle an exporter attribute
///
/// Containing type
/// Method info
/// Defining attribute
/// Thrown if the attribute doesn't properly define an exporter.
public void OnExporterAttribute(Type type, MethodInfo methodInfo, UhtExporterAttribute exporterAttribute)
{
if (String.IsNullOrEmpty(exporterAttribute.Name))
{
throw new UhtIceException("An exporter must have a name");
}
if (Assembly.GetExecutingAssembly() != type.Assembly)
{
if (String.IsNullOrEmpty(exporterAttribute.ModuleName))
{
throw new UhtIceException("An exporter in a UBT plugin must specify a ModuleName");
}
}
UhtExporter exporterValue = new(exporterAttribute, (UhtExporterDelegate)Delegate.CreateDelegate(typeof(UhtExporterDelegate), methodInfo));
_exporterValues.Add(exporterAttribute.Name, exporterValue);
}
///
/// Return an enumerator for all the defined exporters
///
/// Enumerator
public IEnumerator GetEnumerator()
{
foreach (KeyValuePair kvp in _exporterValues)
{
yield return kvp.Value;
}
}
///
/// Return an enumerator for all the defined exporters
///
/// Enumerator
IEnumerator IEnumerable.GetEnumerator()
{
foreach (KeyValuePair kvp in _exporterValues)
{
yield return kvp.Value;
}
}
}
}