Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
27 changes: 26 additions & 1 deletion Assets/Samples/TestAnySerialize.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public class TestAnySerialize : MonoBehaviour
[AnySerialize] public Lazy<Dictionary<int, long[]>> LazyDictIntLongArray { get; }

#pragma warning disable UNT0001

private void Awake()
{
Debug.Log($"{nameof(IntValue)} = {IntValue}");
Expand All @@ -42,6 +42,16 @@ private void Awake()
Debug.Log($"{nameof(DictionaryStringInt)} = {string.Join(",", DictionaryStringInt.Select(t => $"{t.Key}=>{t.Value}"))}");
Debug.Log($"{nameof(DictionaryStringDict)} = {string.Join(",", DictionaryStringDict.Select(t => $"{t.Key}=>({string.Join(",", t.Value.Select(x => $"{x.Key}=>{x.Value}"))})"))}");
Debug.Log($"{nameof(AnyStringArray2)} = {string.Join(",", AnyStringArray2.SelectMany(arr => arr))}");
Debug.Log($"{nameof(AnyIntArray3)} = {string.Join(",", AnyIntArray3.SelectMany(arr2 => arr2).SelectMany(arr => arr))}");
Debug.Log($"{nameof(AnyClassArray)} = {string.Join(",", AnyClassArray.Select(a => a.ToString()))}");
Debug.Log($"{nameof(A)} = {A}");
Debug.Log($"{nameof(B)} = {B}");
Debug.Log($"{nameof(BB)} = {BB}");
Debug.Log($"{nameof(Vector2)} = {Vector2}");
Debug.Log($"{nameof(Record)} = {Record}");
Debug.Log($"{nameof(LazyInt)} = {LazyInt.Value}");
Debug.Log($"{nameof(LazyIntArray)} = {string.Join(",", LazyIntArray.Value)}");
Debug.Log($"{nameof(LazyDictIntLongArray)} = {LazyDictIntLongArray.Value}");
}

#pragma warning restore UNT0001
Expand All @@ -56,6 +66,11 @@ public class A
public int Int;
// [AnySerialize] public string[][] StringArray { get; }
public float Float;

public override string ToString()
{
return $"{{ {nameof(Int)} = {Int}, {nameof(Float)} = {Float} }}";
}
}

[Serializable]
Expand All @@ -65,11 +80,21 @@ public class B<T> : IB<T>
public T[] TArray;
public T[][] TArrayArray;
public float ReadOnlyProperty { get; }

public override string ToString()
{
return $"{{ {nameof(ReadOnlyProperty)} = {ReadOnlyProperty}, {nameof(ReadOnlyTValue)} = {ReadOnlyTValue}, {nameof(TArray)} = {string.Join(",", TArray)}, {nameof(TArrayArray)} = {string.Join(",", TArrayArray.SelectMany(arr => arr))} }}";
}
}

[Serializable]
public record R
{
public int Int { get; } = 123;

public override string ToString()
{
return $"{{ {nameof(Int)} = {Int} }}";
}
}
}
28 changes: 18 additions & 10 deletions Packages/com.quabug.any-processor/CodeGen/Extension/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,26 @@ public static TypeReference CreateGenericTypeReference(this TypeDefinition type,
.SelectMany(t => t.Resolve()!.Methods.Select(m => (type, method: m)))
.FirstOrDefault(t => t.method!.Name == methodName)
;
logger?.Info($"{declaringType.FullName}({declaringType.HasGenericParameters})");
logger?.Debug($"[{nameof(GetMethodReference)}] {declaringType}: {method}@{method.DeclaringType}");
if (method == null) return null;

var methodReference = declaringType.Module!.ImportReference(method);
if (!declaringType.IsGenericInstance) return methodReference;
var parameters = ((GenericInstanceType)declaringType).GenericArguments;
logger?.Info($"{declaringType.FullName}({declaringType.HasGenericParameters}): {string.Join(",", parameters.Select(p => p.Name))}");
return methodReference!.CreateGenericMethodReference(parameters.ToArray()!);
if (methodReference.DeclaringType.IsConcreteType()) return methodReference;

while (!methodReference.DeclaringType.Resolve().TypeEquals(declaringType.Resolve()))
{
logger?.Debug($"[{nameof(GetMethodReference)}] find {method.DeclaringType} {declaringType.Resolve()}:{declaringType.Resolve()!.BaseType}");
declaringType = declaringType.Resolve()!.BaseType;
}

var parameters = ((GenericInstanceType)declaringType).GenericArguments.Select(argument => type.Module!.ImportReference(argument));
logger?.Debug($"[{nameof(GetMethodReference)}] {declaringType}<{string.Join(",", parameters.Select(p => p.Name))}>");
return methodReference.CreateGenericMethodReference(parameters.ToArray(), logger);
}

public static MethodReference CreateGenericMethodReference(this MethodReference method, TypeReference[] genericArguments)
public static MethodReference CreateGenericMethodReference(this MethodReference method, TypeReference[] genericArguments, ILPostProcessorLogger? logger = null)
{
logger?.Debug($"[{nameof(CreateGenericMethodReference)}] {method.Name}: {method.DeclaringType}");
var reference = new MethodReference(method.Name!, method.ReturnType!) {
DeclaringType = method.DeclaringType!.MakeGenericInstanceType(genericArguments),
HasThis = method.HasThis,
Expand Down Expand Up @@ -171,13 +179,13 @@ public static FieldDefinition CreateOrReplaceBackingField(this PropertyDefinitio
{
var backingFieldName = property.GetBackingFieldName();
var backingField = property.DeclaringType!.Fields!.FirstOrDefault(field => field.Name == backingFieldName)
?? property.CreateSerializeReferenceField(fieldType);
?? property.CreateBackingField(fieldType);
backingField.FieldType = fieldType;
backingField.IsInitOnly = false;
return backingField;
}

public static FieldDefinition CreateSerializeReferenceField(this PropertyDefinition property, TypeReference fieldType)
public static FieldDefinition CreateBackingField(this PropertyDefinition property, TypeReference fieldType)
{
//.field private class AnySerialize.Tests.TestMonoBehavior/__generic_serialize_reference_GenericInterface__/IBase _GenericInterface
// .custom instance void [UnityEngine.CoreModule]UnityEngine.SerializeReference::.ctor()
Expand All @@ -191,7 +199,7 @@ public static FieldDefinition CreateSerializeReferenceField(this PropertyDefinit
return serializedField;
}

public static void ReplacePropertyGetterByFieldMethod(this PropertyDefinition property, FieldDefinition serializedField, string fieldMethodName)
public static void ReplacePropertyGetterByFieldMethod(this PropertyDefinition property, FieldDefinition serializedField, string fieldMethodName, ILPostProcessorLogger? logger = null)
{
// before
// IL_0000: ldarg.0 // this
Expand All @@ -204,7 +212,7 @@ public static void ReplacePropertyGetterByFieldMethod(this PropertyDefinition pr
// IL_0006: callvirt instance !0/*object*/ class [AnySerialize]AnySerialize.AnyValue`1<object>::get_Value()
// IL_000b: ret
var instructions = property.GetMethod!.Body!.Instructions;
var getValueMethod = serializedField.FieldType!.GetMethodReference(fieldMethodName);
var getValueMethod = serializedField.FieldType!.GetMethodReference(fieldMethodName, logger);
getValueMethod = property.Module!.ImportReference(getValueMethod!);
instructions!.Clear();
instructions.Add(Instruction.Create(OpCodes.Ldarg_0));
Expand Down
2 changes: 1 addition & 1 deletion Packages/com.quabug.any-processor/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "com.quabug.any-processor",
"version": "0.2.0",
"version": "0.1.0",
"unity": "2021.3",
"displayName": "AnyProcessor",
"type": "library",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Linq;
using AnyProcessor.CodeGen;
using JetBrains.Annotations;
using Mono.Cecil;
using Mono.Cecil.Rocks;
using OneShot;
Expand All @@ -10,6 +11,7 @@

namespace AnySerialize.CodeGen
{
[UsedImplicitly]
public class AnySerializePostProcessor : ILPostProcessor
{
public override ILPostProcessor GetInstance()
Expand Down Expand Up @@ -58,12 +60,12 @@ void GenerateField(PropertyDefinition property, CustomAttribute attribute)
attribute,
(propertyType, typeof(TargetLabel<>))
);
processor.Logger.Debug($"field type: {fieldType?.FullName}");
processor.Logger.Debug($"field type: {fieldType.FullName}");
fieldType = processor.Module.ImportReference(fieldType);
var serializedField = property.CreateOrReplaceBackingField(fieldType);
serializedField.AddCustomAttribute<SerializeField>(property.Module);
processor.Logger.Info($"serialize field type: {serializedField.FullName}");
property.ReplacePropertyGetterByFieldMethod(serializedField, "get_Value");
property.ReplacePropertyGetterByFieldMethod(serializedField, "get_Value", processor.Logger);
if (property.SetMethod != null) property.ReplacePropertySetterByFieldMethod(serializedField, "set_Value");

TypeReference CreatePropertyType()
Expand Down
37 changes: 18 additions & 19 deletions Packages/com.quabug.any-serialize/CodeGen/ITypeSearcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
using System.Collections.Generic;
using System.Linq;
using AnyProcessor.CodeGen;
using JetBrains.Annotations;
using Mono.Cecil;
using OneShot;

namespace AnySerialize.CodeGen
{
public interface ITypeSearcher
{
[CanBeNull] TypeReference Search();
TypeReference? Search();
}

public interface ITypeSearcher<T> : ITypeSearcher where T : Attribute, IAnyTypeSearcherAttribute {}
Expand All @@ -29,55 +28,55 @@ from @interface in @base.GetInterfaces()
where @interface.IsGenericType && @interface.GetGenericTypeDefinition() == typeof(ITypeSearcher<>)
select (searcher: type, attribute: @interface.GenericTypeArguments[0])
;
_value = searchers.ToDictionary(t => t.attribute.FullName, t => t.searcher);
_value = searchers.ToDictionary(t => t.attribute!.FullName, t => t.searcher);
}

public static TypeReference Search(this Container container, CustomAttribute attribute, params object[] instances)
public static TypeReference? Search(this Container container, CustomAttribute attribute, params object[] instances)
{
return container.CreateSearcher(attribute, instances.Select(instance => (instance, (Type)null))).Search();
return container.CreateSearcher(attribute, instances.Select(instance => (instance, (Type?)null))).Search();
}

public static TypeReference Search(this Container container, CustomAttribute attribute, params (object instance, Type label)[] instances)
public static TypeReference? Search(this Container container, CustomAttribute attribute, params (object instance, Type? label)[] instances)
{
return container.CreateSearcher(attribute, instances).Search();
}

public static TypeReference Search<T>(this Container container) where T : ITypeSearcher
public static TypeReference? Search<T>(this Container container) where T : ITypeSearcher
{
return container.CreateSearcher(typeof(T), Enumerable.Empty<(object instance, Type label)>()).Search();
}

public static TypeReference Search<T>(this Container container, params object[] instances) where T : ITypeSearcher
public static TypeReference? Search<T>(this Container container, params object[] instances) where T : ITypeSearcher
{
return container.CreateSearcher(typeof(T), instances.Select(instance => (instance, (Type)null))).Search();
return container.CreateSearcher(typeof(T), instances.Select(instance => (instance, (Type?)null))!).Search();
}

public static TypeReference Search<T>(this Container container, params (object instance, Type label)[] instances) where T : ITypeSearcher
public static TypeReference? Search<T>(this Container container, params (object instance, Type? label)[] instances) where T : ITypeSearcher
{
return container.CreateSearcher(typeof(T), instances).Search();
return container.CreateSearcher(typeof(T), instances!).Search();
}

private static ITypeSearcher CreateSearcher(this Container container, CustomAttribute attribute, IEnumerable<(object instance, Type label)> instances)
private static ITypeSearcher CreateSearcher(this Container container, CustomAttribute attribute, IEnumerable<(object instance, Type? label)> instances)
{
var searcher = _value[attribute.AttributeType.FullName];
var searcher = _value[attribute.AttributeType!.FullName];
container = container.CreateChildContainer();
container.RegisterInstance(container).AsSelf();
container.RegisterInstance(container)!.AsSelf();

foreach (var attributeArgument in attribute.ConstructorArguments) container.RegisterInstance(attributeArgument.Value)
foreach (var attributeArgument in attribute.ConstructorArguments!) container.RegisterInstance(attributeArgument.Value)!
.AsSelf(typeof(AttributeLabel<>))
.AsBases(typeof(AttributeLabel<>))
.AsInterfaces(typeof(AttributeLabel<>))
;

foreach (var (instance, label) in instances) container.RegisterInstance(instance).AsSelf(label).AsBases(label).AsInterfaces(label);
return (ITypeSearcher)container.Instantiate(searcher);
foreach (var (instance, label) in instances) container.RegisterInstance(instance)!.AsSelf(label).AsBases(label).AsInterfaces(label);
return (ITypeSearcher)container.Instantiate(searcher!)!;
}

private static ITypeSearcher CreateSearcher(this Container container, Type searcherType, IEnumerable<(object instance, Type label)> instances)
{
container = container.CreateChildContainer();
foreach (var (instance, label) in instances) container.RegisterInstance(instance).AsSelf(label).AsBases().AsInterfaces();
return (ITypeSearcher)container.Instantiate(searcherType);
foreach (var (instance, label) in instances) container.RegisterInstance(instance)!.AsSelf(label).AsBases().AsInterfaces();
return (ITypeSearcher)container.Instantiate(searcherType)!;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="C:/Program Files/Unity/Hub/Editor/2021.3.6f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll" #>
<#@ assembly name="C:/Program Files/Unity/Hub/Editor/2021.3.9f1/Editor/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll" #>
<#@ assembly name="$(SolutionDir)/Library/ScriptAssemblies/Unity.Mathematics.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="Unity.Mathematics" #>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public Dictionary<TKey, TValue> Value
if (_cache != null) return _cache;
#endif
_cache ??= new Dictionary<TKey, TValue>();
_cache.Clear();
foreach (var pair in _pairs) _cache.Add(pair.Value.Key, pair.Value.Value);
return _cache;
}
Expand Down
4 changes: 2 additions & 2 deletions Packages/com.quabug.any-serialize/package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "com.quabug.any-serialize",
"description": "Generate serializable code of any properties for Unity3D serializer",
"version": "0.3.0",
"version": "0.1.0",
"unity": "2021.3",
"displayName": "AnySerialize",
"type": "library",
"dependencies": {
"com.unity.nuget.mono-cecil": "1.11.4",
"com.quabug.any-processor": "0.2.0",
"com.quabug.any-processor": "0.1.0",
"com.quabug.one-shot-injection": "2.2.0"
}
}
2 changes: 1 addition & 1 deletion Packages/packages-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"source": "embedded",
"dependencies": {
"com.unity.nuget.mono-cecil": "1.11.4",
"com.quabug.any-processor": "0.2.0",
"com.quabug.any-processor": "0.1.0",
"com.quabug.one-shot-injection": "2.2.0"
}
},
Expand Down