From 696c6a6bed0cf59bc13e0979edccc770b5643722 Mon Sep 17 00:00:00 2001 From: hadashiA Date: Mon, 21 Oct 2024 18:44:38 +0900 Subject: [PATCH] [mruby] Support custom formatter --- README.md | 37 ++++++++++++++++++ ...alRouterMRubyIncrementalSourceGenerator.cs | 17 +------- .../VitalRouter.MRuby/Runtime/MRubyContext.cs | 12 +++--- .../Runtime/NativeMethods.cs | 6 ++- .../Runtime/Serialization/FixnumFormatters.cs | 18 ++++----- .../Runtime/Serialization/FloatFormatter.cs | 12 +++--- .../Serialization/MrbValueSerializer.cs | 2 +- .../Serialization/PrimitiveObjectFormatter.cs | 4 +- .../VitalRouter.SourceGenerator.MRuby.dll | Bin 73216 -> 73216 bytes 9 files changed, 66 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 9d28f75..59cd8ad 100644 --- a/README.md +++ b/README.md @@ -1179,6 +1179,43 @@ See the table below for the support status of mutually convertible types. | `[Int, Int, Int, Int]` | `RectInt`, `BoundsInt`, `Color32` | | `nil` | `T?`, `Nullable` | +If you want to customize the formatting behavior, implement `IMrbValueFormatter` . + +```csharp +// Example type... +public struct UserId +{ + public int Value; +} + +public class UserIdFormatter : IMrbValueFormatter +{ + public static readonly UserIdFormatter Instance = new(); + + public UserId Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerializerOptions options) + { + if (mrbValue.IsNil) return default; + retun new UserId { Value = mrbValue.IntValue }; + } +} +``` + +To enable the custom formatter, set MrbValueSerializerOptions as follows. + +```csharp +StaticCompositeResolver.Instance + .AddFormatters(UserIdFormatter.Instance) // < Yoru custom formatters + .AddResolvers(StandardResolver.Instance); // < Default behaviours + +// Set serializer options to context. +var context = MRubyContext.Create(...); +context.SerializerOptions = new MrbValueSerializerOptions +{ + Resolver = StaticCompositeResolver +}; +``` + + ### MRubyContext `MRubyContext` provides several APIs for executing mruby scripts. diff --git a/src/VitalRouter.SourceGenerator.MRuby/VitalRouterMRubyIncrementalSourceGenerator.cs b/src/VitalRouter.SourceGenerator.MRuby/VitalRouterMRubyIncrementalSourceGenerator.cs index 347f666..2e8a892 100644 --- a/src/VitalRouter.SourceGenerator.MRuby/VitalRouterMRubyIncrementalSourceGenerator.cs +++ b/src/VitalRouter.SourceGenerator.MRuby/VitalRouterMRubyIncrementalSourceGenerator.cs @@ -11,21 +11,6 @@ namespace VitalRouter.SourceGenerator.MRuby; [Generator] public class VitalRouterMRubyIncrementalSourceGenerator : IIncrementalGenerator { - class Comparer : IEqualityComparer - { - public static readonly Comparer Instance = new(); - - public bool Equals(GeneratorAttributeSyntaxContext x, GeneratorAttributeSyntaxContext y) - { - return x.TargetNode.Equals(y.TargetNode); - } - - public int GetHashCode(GeneratorAttributeSyntaxContext obj) - { - return obj.TargetNode.GetHashCode(); - } - } - public void Initialize(IncrementalGeneratorInitializationContext context) { var commandPresetProvider = context.SyntaxProvider @@ -536,7 +521,7 @@ partial class {{commandPresetTypeMeta.TypeName}} { if (!__Names.TryGetValue(commandName, out var index)) { - script.Fail(new ArgumentOutOfRangeException(nameof(commandName), $"No such command {commandName} in {GetType().Name}. Please use `[MRubyCommand(...)]` attribute and register it.")); + script.Fail(new ArgumentOutOfRangeException(nameof(commandName), $"No such command `{commandName}` in {GetType().Name}. Please use `[MRubyCommand(...)]` attribute and register it.")); return; } diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/MRubyContext.cs b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/MRubyContext.cs index 666d54d..b818c9f 100644 --- a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/MRubyContext.cs +++ b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/MRubyContext.cs @@ -1,6 +1,5 @@ using System; using System.Runtime.CompilerServices; -using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using AOT; using Unity.Collections; @@ -102,6 +101,9 @@ public class MRubyContext : SafeHandle [ThreadStatic] static bool captureScriptErrors; + public static Action GlobalErrorHandler { get; set; } = OnScriptError; + public static Action GlobalLogHandler { get; set; } = UnityEngine.Debug.Log; + public static unsafe MRubyContext Create() { NativeMethods.MrbAllocfSet(MRubyAllocator.AllocPersistent); @@ -120,9 +122,6 @@ public static MRubyContext Create(Router router, MRubyCommandPreset commandPrese return context; } - public static Action GlobalErrorHandler { get; set; } = OnScriptError; - public static Action GlobalLogHandler { get; set; } = UnityEngine.Debug.Log; - static void OnScriptError(Exception ex) { if (captureScriptErrors) @@ -136,6 +135,7 @@ static void OnScriptError(Exception ex) } public MRubySharedState SharedState { get; } + public MrbValueSerializerOptions SerializerOptions { get; set; } = MrbValueSerializerOptions.Default; public Router Router { @@ -187,13 +187,13 @@ public void Load(ReadOnlySpan rubySource) public T? Evaluate(string rubySource, MrbValueSerializerOptions? options = null) { var bytes = System.Text.Encoding.UTF8.GetBytes(rubySource); - return Evaluate(bytes); + return Evaluate(bytes, options); } public T? Evaluate(ReadOnlySpan rubySource, MrbValueSerializerOptions? options = null) { using var result = EvaluateUnsafe(rubySource); - return MrbValueSerializer.Deserialize(result.RawValue, this, options); + return MrbValueSerializer.Deserialize(result.RawValue, this, options ?? SerializerOptions); } public MrbValueHandle EvaluateUnsafe(string rubySource) diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/NativeMethods.cs b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/NativeMethods.cs index fd70538..4041311 100644 --- a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/NativeMethods.cs +++ b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/NativeMethods.cs @@ -61,10 +61,12 @@ public struct MrbValueUnion [StructLayout(LayoutKind.Sequential)] public struct MrbValue { - public MrbValueUnion Value; + MrbValueUnion value; public MrbVtype TT; - public bool IsNil => TT == MrbVtype.MRB_TT_FALSE && Value.I == 0; + public bool IsNil => TT == MrbVtype.MRB_TT_FALSE && value.I == 0; + public long IntValue => value.I; + public double FlaotValue => value.F; public unsafe string ToString(MRubyContext context) { diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FixnumFormatters.cs b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FixnumFormatters.cs index 0a22ac7..b6887ee 100644 --- a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FixnumFormatters.cs +++ b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FixnumFormatters.cs @@ -10,7 +10,7 @@ public byte Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeriali { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((byte)mrbValue.Value.I); + return checked((byte)mrbValue.IntValue); } } @@ -24,7 +24,7 @@ public sbyte Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerial { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((sbyte)mrbValue.Value.I); + return checked((sbyte)mrbValue.IntValue); } } @@ -38,7 +38,7 @@ public char Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeriali { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((char)mrbValue.Value.I); + return checked((char)mrbValue.IntValue); } } @@ -52,7 +52,7 @@ public short Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerial { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((short)mrbValue.Value.I); + return checked((short)mrbValue.IntValue); } } @@ -66,7 +66,7 @@ public int Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerializ { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((int)mrbValue.Value.I); + return checked((int)mrbValue.IntValue); } } @@ -80,7 +80,7 @@ public long Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeriali { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((long)mrbValue.Value.I); + return checked((long)mrbValue.IntValue); } } @@ -94,7 +94,7 @@ public ushort Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeria { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((ushort)mrbValue.Value.I); + return checked((ushort)mrbValue.IntValue); } } @@ -108,7 +108,7 @@ public uint Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeriali { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((uint)mrbValue.Value.I); + return checked((uint)mrbValue.IntValue); } } @@ -122,7 +122,7 @@ public ulong Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerial { throw new MRubySerializationException($"value is not a Integer. {mrbValue.TT}"); } - return checked((ulong)mrbValue.Value.I); + return checked((ulong)mrbValue.IntValue); } } } \ No newline at end of file diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FloatFormatter.cs b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FloatFormatter.cs index 9acd784..0d2537e 100644 --- a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FloatFormatter.cs +++ b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/FloatFormatter.cs @@ -8,8 +8,8 @@ public float Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerial { return mrbValue.TT switch { - MrbVtype.MRB_TT_FLOAT => (float)mrbValue.Value.F, - MrbVtype.MRB_TT_INTEGER => mrbValue.Value.I, + MrbVtype.MRB_TT_FLOAT => (float)mrbValue.FlaotValue, + MrbVtype.MRB_TT_INTEGER => mrbValue.IntValue, _ => throw new MRubySerializationException($"mrb_value cannot deserialize as float: {mrbValue.TT}") }; } @@ -23,8 +23,8 @@ public double Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeria { return mrbValue.TT switch { - MrbVtype.MRB_TT_FLOAT => (float)mrbValue.Value.F, - MrbVtype.MRB_TT_INTEGER => mrbValue.Value.I, + MrbVtype.MRB_TT_FLOAT => (float)mrbValue.FlaotValue, + MrbVtype.MRB_TT_INTEGER => mrbValue.IntValue, _ => throw new MRubySerializationException($"mrb_value cannot deserialize as double: {mrbValue.TT}") }; } @@ -38,8 +38,8 @@ public decimal Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSeri { return mrbValue.TT switch { - MrbVtype.MRB_TT_FLOAT => (decimal)mrbValue.Value.F, - MrbVtype.MRB_TT_INTEGER => mrbValue.Value.I, + MrbVtype.MRB_TT_FLOAT => (decimal)mrbValue.FlaotValue, + MrbVtype.MRB_TT_INTEGER => mrbValue.IntValue, _ => throw new MRubySerializationException($"mrb_value cannot deserialize as decimal: {mrbValue.TT}") }; } diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/MrbValueSerializer.cs b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/MrbValueSerializer.cs index e2cb731..995537b 100644 --- a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/MrbValueSerializer.cs +++ b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/MrbValueSerializer.cs @@ -4,7 +4,7 @@ public static class MrbValueSerializer { public static T? Deserialize(MrbValue mrbValue, MRubyContext context, MrbValueSerializerOptions? options = null) { - options ??= MrbValueSerializerOptions.Default; + options ??= context.SerializerOptions; return options.Resolver.GetFormatterWithVerify() .Deserialize(mrbValue, context, options); } diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/PrimitiveObjectFormatter.cs b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/PrimitiveObjectFormatter.cs index 58c0c1c..e8307b6 100644 --- a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/PrimitiveObjectFormatter.cs +++ b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/Serialization/PrimitiveObjectFormatter.cs @@ -20,9 +20,9 @@ public class PrimitiveObjectFormatter : IMrbValueFormatter case MrbVtype.MRB_TT_TRUE: return true; case MrbVtype.MRB_TT_INTEGER: - return (long)value.Value.I; + return value.IntValue; case MrbVtype.MRB_TT_FLOAT: - return value.Value.F; + return value.FlaotValue; case MrbVtype.MRB_TT_SYMBOL: case MrbVtype.MRB_TT_STRING: return value.ToString(context); diff --git a/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/VitalRouter.SourceGenerator.MRuby.dll b/src/VitalRouter.Unity/Assets/VitalRouter.MRuby/Runtime/VitalRouter.SourceGenerator.MRuby.dll index 850dfea438d80e878452575c065c6ebe5a43b300..a7174bc4ca5c931d020161c28deec7c348daec05 100644 GIT binary patch delta 19188 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 p@O>JpHQ1sE^6