// Copyright Epic Games, Inc. All Rights Reserved.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace EpicGames.BuildGraph
{
///
/// Value of an object
///
public class BgObjectDef
{
///
/// Deserialized object value
///
private object? _value;
///
/// Properties for the object
///
public ImmutableDictionary Properties { get; }
///
/// Constructor
///
public BgObjectDef()
{
Properties = ImmutableDictionary.Empty.WithComparers(StringComparer.Ordinal);
}
///
/// Constructor
///
public BgObjectDef(ImmutableDictionary properties)
{
Properties = properties;
}
///
/// Sets a property value
///
/// Name of the property
/// New value for the property
/// Object definition with the new properties
public BgObjectDef Set(string name, object? value)
{
return new BgObjectDef(Properties.SetItem(name, value));
}
///
/// Gets a property value
///
/// Name of the property
/// Default value to return if the property is not set
///
public object? Get(string name, object? defaultValue)
{
object? value;
if (!Properties.TryGetValue(name, out value))
{
value = defaultValue;
}
return value;
}
///
/// Creates a strongly typed object instance
///
/// Type of the object
///
public BgObjectDef WithType() => new BgObjectDef(Properties);
///
/// Cache of serializer instances
///
static readonly ConcurrentDictionary s_typeToSerializer = new ConcurrentDictionary();
///
/// Deserialize an object of the given type, using the default serializer
///
/// Type of the object to create
/// Deserialized instance of the type
public object Deserialize(Type type)
{
if (_value == null)
{
BgObjectSerializer? serializer;
if (!s_typeToSerializer.TryGetValue(type, out serializer))
{
Type serializerType = type.GetCustomAttribute()?.SerializerType ?? typeof(BgDefaultObjectSerializer<>).MakeGenericType(type);
serializer = (BgObjectSerializer)Activator.CreateInstance(serializerType)!;
serializer = s_typeToSerializer.GetOrAdd(type, serializer);
}
_value = serializer.Deserialize(this);
}
return _value;
}
///
/// Deserialize an object of the given type
///
/// Type to deserialize
/// Deserialized instance of the type
public T Deserialize() => (T)Deserialize(typeof(T));
}
///
/// Strongly typed instance of
///
///
public class BgObjectDef : BgObjectDef
{
class PropertySetter
{
protected PropertyInfo Property { get; }
public PropertySetter(PropertyInfo property) => Property = property;
public virtual void SetValue(object instance, object? value) => Property.SetValue(instance, ConvertValue(value, Property.PropertyType));
}
class CollectionPropertySetter : PropertySetter
{
public CollectionPropertySetter(PropertyInfo property)
: base(property)
{
}
public override void SetValue(object instance, object? value)
{
ICollection? list = (ICollection?)Property.GetValue(instance)!;
if (list == null)
{
list = (ICollection)Activator.CreateInstance(Property.PropertyType)!;
Property.SetValue(instance, list);
}
IEnumerable