Skip to content

Commit

Permalink
udon value resolver rework
Browse files Browse the repository at this point in the history
  • Loading branch information
Xytabich committed Oct 7, 2021
1 parent f1d1eff commit fa910ad
Show file tree
Hide file tree
Showing 38 changed files with 412 additions and 270 deletions.
File renamed without changes.
214 changes: 214 additions & 0 deletions Assets/Katsudon/Builder/Converters/ArrayValueConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;

namespace Katsudon.Builder.Converters
{
[ValueConverter]
public class ArrayValueConverter : IValueConverter
{
int IValueConverter.order => 100;

private UdonValueResolver resolver;

public ArrayValueConverter(UdonValueResolver resolver)
{
this.resolver = resolver;
}

bool IValueConverter.TryConvertToUdon(object value, out object converted, out bool isAllowed)
{
var type = value.GetType();
if(type.IsArray && !Utils.IsUdonType(type))
{
var rank = type.GetArrayRank();
var inArray = (Array)value;
if(rank <= 1)
{
var arrayType = GetOneDimensionalType(type);
if(arrayType != null)
{
var outArray = Array.CreateInstance(arrayType.GetElementType(), inArray.LongLength);
for(long i = inArray.LongLength - 1; i >= 0; i--)
{
if(resolver.TryConvertToUdon(inArray.GetValue(i), out var v))
{
outArray.SetValue(v, i);
}
}
converted = outArray;
isAllowed = true;
return true;
}
}
else
{
var elementType = GetElementType(type.GetElementType());
if(Utils.IsUdonType(elementType))
{
converted = value;
isAllowed = true;
return true;
}

int[] lengths = new int[rank];
int[] indices = new int[rank];
for(int i = 0; i < rank; i++)
{
lengths[i] = inArray.GetLength(i);
indices[i] = 0;
}
var outArray = Array.CreateInstance(typeof(object), lengths);
bool fill = true;
while(fill)
{
if(resolver.TryConvertToUdon(inArray.GetValue(indices), out var v))
{
outArray.SetValue(v, indices);
}
indices[0]++;
int i = 0;
while(indices[i] >= lengths[i])
{
indices[i] = 0;
i++;
if(i >= rank)
{
fill = false;
break;
}
indices[i]++;
}
}
converted = outArray;
isAllowed = true;
return true;
}
}
converted = null;
isAllowed = false;
return false;
}

bool IValueConverter.TryConvertFromUdon(object value, Type toType, out object converted, out bool isAllowed, ref bool reserialize)
{
if(toType.IsArray && !Utils.IsUdonType(toType))
{
if(value.GetType() == toType)
{
converted = value;
isAllowed = true;
return true;
}

var elementType = toType.GetElementType();
var rank = toType.GetArrayRank();
var inArray = (Array)value;
if(rank <= 1)
{
var outArray = Array.CreateInstance(elementType, inArray.LongLength);
for(long i = inArray.LongLength - 1; i >= 0; i--)
{
if(resolver.TryConvertFromUdon(inArray.GetValue(i), elementType, out var v, out bool r))
{
outArray.SetValue(v, i);
if(r) reserialize = true;
}
else reserialize = true;
}
converted = outArray;
isAllowed = true;
return true;
}
else
{
int[] lengths = new int[rank];
int[] indices = new int[rank];
for(int i = 0; i < rank; i++)
{
lengths[i] = inArray.GetLength(i);
indices[i] = 0;
}
var outArray = Array.CreateInstance(elementType, lengths);
bool fill = true;
while(fill)
{
if(resolver.TryConvertFromUdon(inArray.GetValue(indices), elementType, out var v, out bool r))
{
outArray.SetValue(v, indices);
if(r) reserialize = true;
}
else reserialize = true;
indices[0]++;
int i = 0;
while(indices[i] >= lengths[i])
{
indices[i] = 0;
i++;
if(i >= rank)
{
fill = false;
break;
}
indices[i]++;
}
}
converted = outArray;
isAllowed = true;
return true;
}
}
converted = null;
isAllowed = false;
return false;
}

Type IValueConverter.GetUdonType(Type type)
{
if(type.IsArray && !Utils.IsUdonType(type))
{
var rank = type.GetArrayRank();
if(rank <= 1)
{
return GetOneDimensionalType(type);
}
else
{
return typeof(Array);
}
}
return null;
}

private Type GetOneDimensionalType(Type type)
{
if(resolver.TryGetUdonType(type.GetElementType(), out var elementType))
{
Type arrayType;

arrayType = elementType.MakeArrayType();
while(!Utils.IsUdonType(arrayType))
{
elementType = elementType.BaseType;
arrayType = elementType.MakeArrayType();
}

return arrayType;
}
return null;
}

private static Type GetElementType(Type elementType)
{
while(elementType.IsArray)
{
elementType = elementType.GetElementType();
}
return elementType;
}

public static void Register(UdonValueResolver resolver, ICollection<IValueConverter> container)
{
container.Add(new ArrayValueConverter(resolver));
}
}
}
11 changes: 11 additions & 0 deletions Assets/Katsudon/Builder/Converters/ArrayValueConverter.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using Katsudon.Builder;

namespace Katsudon.Editor.Converters
namespace Katsudon.Builder.Converters
{
public interface IValueConverter
{
int order { get; }

Type GetUdonType(Type type);

bool TryConvertToUdon(object value, out object converted, out bool isAllowed);

bool TryConvertFromUdon(object value, Type toType, out object converted, out bool isAllowed, ref bool reserialize);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
using System;
using System.Collections.Generic;
using Katsudon.Builder;
using Katsudon.Utility;
using UnityEngine.Assertions;

namespace Katsudon.Editor.Converters
namespace Katsudon.Builder.Converters
{
public class UdonValueResolver : IComparer<IValueConverter>
{
private static UdonValueResolver _instance = null;
public static UdonValueResolver instance => _instance ?? (_instance = new UdonValueResolver());

private SortedSet<IValueConverter> resolvers;

public UdonValueResolver()
private UdonValueResolver()
{
resolvers = new SortedSet<IValueConverter>(this);

Expand All @@ -24,6 +26,52 @@ public UdonValueResolver()
}
}

public bool TryGetUdonType(Type type, out Type udonType)//FIX: cache
{
var types = CollectionCache.GetList<Type>();
foreach(var resolver in resolvers)
{
var outType = resolver.GetUdonType(type);
if(outType != null) types.Add(outType);
}
if(types.Count == 0)
{
if(Utils.IsUdonType(type))
{
udonType = type;
}
else
{
udonType = null;
}
}
else
{
if(Utils.IsUdonType(type)) types.Add(type);// The "default" resolver is also involved

udonType = types[0];
for(int i = 1; i < types.Count; i++)
{
var t = types[i];
if(t.IsAssignableFrom(udonType))
{
udonType = t;
continue;
}
while(!udonType.IsAssignableFrom(t))
{
udonType = udonType.BaseType;
}
}
while(!Utils.IsUdonType(udonType))
{
udonType = udonType.BaseType;
}
}
CollectionCache.Release(types);
return udonType != null;
}

public bool TryConvertToUdon(object value, out object outValue)//TODO: recursion check
{
outValue = value;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,6 @@ bool IVariableBuilder.TryBuildVariable(IVariable variable, VariablesTable table)
return false;
}

bool IVariableBuilder.TryConvert(Type toType, ref object value)
{
return false;
}

public static void Register(VariableBuildersCollection container, IModulesContainer modules)
{
container.AddBuilder(new DelegateVariableBuilder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ bool IVariableBuilder.TryBuildVariable(IVariable variable, VariablesTable table)
return false;
}

bool IVariableBuilder.TryConvert(Type toType, ref object value)
{
return false;
}

public static void Register(VariableBuildersCollection container, IModulesContainer modules)
{
container.AddBuilder(new ExternMethodPatternBuilder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ bool IVariableBuilder.TryBuildVariable(IVariable variable, VariablesTable table)
return false;
}

bool IVariableBuilder.TryConvert(Type toType, ref object value)
{
return false;
}

public static void Register(VariableBuildersCollection container, IModulesContainer modules)
{
container.AddBuilder(new UdonMethodPatternBuilder());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using Katsudon.Editor.Converters;
using Katsudon.Builder.Converters;

namespace Katsudon.Editor.Extensions.EnumExtension
namespace Katsudon.Builder.Extensions.EnumExtension
{
[ValueConverter]
public class CustomEnumValueConverter : IValueConverter
Expand Down Expand Up @@ -35,6 +35,15 @@ bool IValueConverter.TryConvertFromUdon(object value, Type toType, out object co
return false;
}

Type IValueConverter.GetUdonType(Type type)
{
if(type.IsEnum && !Utils.IsUdonType(type))
{
return Enum.GetUnderlyingType(type);
}
return null;
}

public static void Register(UdonValueResolver resolver, ICollection<IValueConverter> container)
{
container.Add(new CustomEnumValueConverter());
Expand Down
Loading

0 comments on commit fa910ad

Please sign in to comment.