Skip to content

Commit

Permalink
Merge pull request #700 from Cysharp/feature/FixCodeGenerationMemoryPack
Browse files Browse the repository at this point in the history
Fix code generation for MemoryPack
  • Loading branch information
mayuki authored Oct 26, 2023
2 parents 55ea92f + c37f25b commit a2a0ecc
Show file tree
Hide file tree
Showing 12 changed files with 255 additions and 415 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ static GenerationOptions ParseClientGenerationOptions(AttributeData attr)

foreach (var namedArg in attr.NamedArguments)
{
if (namedArg.Value.Kind is TypedConstantKind.Error or not TypedConstantKind.Primitive) continue;
if (namedArg.Value.Kind is TypedConstantKind.Error or (not TypedConstantKind.Primitive and not TypedConstantKind.Enum)) continue;

switch (namedArg.Key)
{
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using MagicOnion.Client.SourceGenerator.Tests.Verifiers;

namespace MagicOnion.Client.SourceGenerator.Tests;

public class GenerateMemoryPackTest
{
[Fact]
public async Task Generic()
{
var source = """
using MagicOnion;
using MagicOnion.Client;
using MemoryPack;
namespace MyApplication1;
public interface IGreeterService : IService<IGreeterService>
{
UnaryResult<MyGenericObject<(string, int)>> HelloAsync(string name, int age);
}
[MemoryPackable]
public class MyGenericObject<T> {}
[MagicOnionClientGeneration(typeof(IGreeterService), Serializer = GenerateSerializerType.MemoryPack)]
partial class MagicOnionInitializer {}
""";

await MagicOnionSourceGeneratorVerifier.RunAsync(
source,
verifierOptions: VerifierOptions.Default with { UseMemoryPack = true }
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// <auto-generated />
namespace MagicOnion.Client
{
/// <summary>
/// Marker attribute for generating clients of MagicOnion.
/// The source generator collects the classes specified by this attribute and uses them to generate source.
/// </summary>
[global::System.Diagnostics.Conditional("__MagicOnion_Client_SourceGenerator__DesignTimeOnly__")]
[global::System.AttributeUsage(global::System.AttributeTargets.Class, AllowMultiple = false)]
internal class MagicOnionClientGenerationAttribute : global::System.Attribute
{
/// <summary>
/// Gets or sets whether to disable automatically calling `Register` during start-up. (Automatic registration requires .NET 5+ or Unity)
/// </summary>
public bool DisableAutoRegistration { get; set; }

/// <summary>
/// Gets or set the serializer used for message serialization. The default value is <see cref="GenerateSerializerType.MessagePack"/>.
/// </summary>
public global::MagicOnion.Client.GenerateSerializerType Serializer { get; set; } = global::MagicOnion.Client.GenerateSerializerType.MessagePack;

/// <summary>
/// Gets or set the namespace of pre-generated MessagePackFormatters. The default value is <c>MessagePack.Formatters</c>.
/// </summary>
public string MessagePackFormatterNamespace { get; set; } = "MessagePack.Formatters";

public global::System.Type[] TypesContainedInTargetAssembly { get; }

/// <param name="typesContainedInTargetAssembly">Types contained in the scan target assembly</param>
public MagicOnionClientGenerationAttribute(params global::System.Type[] typesContainedInTargetAssembly)
{
TypesContainedInTargetAssembly = typesContainedInTargetAssembly;
}
}

// This enum must be mirror of `SerializerType` (MagicOnionClientSourceGenerator)
internal enum GenerateSerializerType
{
MessagePack = 0,
MemoryPack = 1,
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// <auto-generated />
#pragma warning disable CS0618 // 'member' is obsolete: 'text'
#pragma warning disable CS0612 // 'member' is obsolete
#pragma warning disable CS8019 // Unnecessary using directive.

namespace MyApplication1
{
using global::System;
using global::Grpc.Core;
using global::MagicOnion;
using global::MagicOnion.Client;
using global::MessagePack;

partial class MagicOnionInitializer
{
static partial class MagicOnionGeneratedClient
{
[global::MagicOnion.Ignore]
public class MyApplication1_GreeterServiceClient : global::MagicOnion.Client.MagicOnionClientBase<global::MyApplication1.IGreeterService>, global::MyApplication1.IGreeterService
{
class ClientCore
{
public global::MagicOnion.Client.Internal.RawMethodInvoker<global::MagicOnion.DynamicArgumentTuple<global::System.String, global::System.Int32>, global::MyApplication1.MyGenericObject<global::System.ValueTuple<global::System.String, global::System.Int32>>> HelloAsync;
public ClientCore(global::MagicOnion.Serialization.IMagicOnionSerializerProvider serializerProvider)
{
this.HelloAsync = global::MagicOnion.Client.Internal.RawMethodInvoker.Create_ValueType_RefType<global::MagicOnion.DynamicArgumentTuple<global::System.String, global::System.Int32>, global::MyApplication1.MyGenericObject<global::System.ValueTuple<global::System.String, global::System.Int32>>>(global::Grpc.Core.MethodType.Unary, "IGreeterService", "HelloAsync", serializerProvider);
}
}

readonly ClientCore core;

public MyApplication1_GreeterServiceClient(global::MagicOnion.Client.MagicOnionClientOptions options, global::MagicOnion.Serialization.IMagicOnionSerializerProvider serializerProvider) : base(options)
{
this.core = new ClientCore(serializerProvider);
}

private MyApplication1_GreeterServiceClient(MagicOnionClientOptions options, ClientCore core) : base(options)
{
this.core = core;
}

protected override global::MagicOnion.Client.MagicOnionClientBase<global::MyApplication1.IGreeterService> Clone(global::MagicOnion.Client.MagicOnionClientOptions options)
=> new MyApplication1_GreeterServiceClient(options, core);

public global::MagicOnion.UnaryResult<global::MyApplication1.MyGenericObject<global::System.ValueTuple<global::System.String, global::System.Int32>>> HelloAsync(global::System.String name, global::System.Int32 age)
=> this.core.HelloAsync.InvokeUnary(this, "IGreeterService/HelloAsync", new global::MagicOnion.DynamicArgumentTuple<global::System.String, global::System.Int32>(name, age));
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// <auto-generated />
#pragma warning disable CS0618 // 'member' is obsolete: 'text'
#pragma warning disable CS0612 // 'member' is obsolete
#pragma warning disable CS8019 // Unnecessary using directive.

namespace MyApplication1
{
using global::System;
using global::MemoryPack;
partial class MagicOnionInitializer
{
/// <summary>
/// Registers the generated MemoryPackFormatters.
/// </summary>
public static void RegisterMemoryPackFormatters()
{
global::MemoryPack.MemoryPackFormatterProvider.Register(new global::MagicOnion.Serialization.MemoryPack.DynamicArgumentTupleFormatter<global::System.String, global::System.Int32>());
global::MemoryPack.MemoryPackFormatterProvider.Register(new global::MemoryPack.Formatters.ValueTupleFormatter<global::System.String, global::System.Int32>());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// <auto-generated />
#pragma warning disable CS0618 // 'member' is obsolete: 'text'
#pragma warning disable CS0612 // 'member' is obsolete
#pragma warning disable CS8019 // Unnecessary using directive.
namespace MyApplication1
{
using global::System;
using global::System.Collections.Generic;
using global::System.Linq;
using global::MagicOnion;
using global::MagicOnion.Client;

partial class PreserveAttribute : global::System.Attribute {}

partial class MagicOnionInitializer
{
static bool isRegistered = false;
readonly static MagicOnionGeneratedClientFactoryProvider provider = new();

/// <summary>
/// Gets the generated MagicOnionClientFactoryProvider.
/// </summary>
public static global::MagicOnion.Client.IMagicOnionClientFactoryProvider ClientFactoryProvider => provider;

/// <summary>
/// Gets the generated StreamingHubClientFactoryProvider.
/// </summary>
public static global::MagicOnion.Client.IStreamingHubClientFactoryProvider StreamingHubClientFactoryProvider => provider;
#if UNITY_2019_4_OR_NEWER
[global::UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.BeforeSceneLoad)]
#elif NET5_0_OR_GREATER
[global::System.Runtime.CompilerServices.ModuleInitializer]
#endif
internal static void Register() => TryRegisterProviderFactory();

/// <summary>
/// Register the generated client factory providers if it's not registered yet. This method will register only once.
/// </summary>
public static bool TryRegisterProviderFactory()
{
if (isRegistered) return false;
isRegistered = true;

global::MagicOnion.Client.MagicOnionClientFactoryProvider.Default =
(global::MagicOnion.Client.MagicOnionClientFactoryProvider.Default is global::MagicOnion.Client.ImmutableMagicOnionClientFactoryProvider immutableMagicOnionClientFactoryProvider)
? immutableMagicOnionClientFactoryProvider.Add(provider)
: new global::MagicOnion.Client.ImmutableMagicOnionClientFactoryProvider(provider);

global::MagicOnion.Client.StreamingHubClientFactoryProvider.Default =
(global::MagicOnion.Client.StreamingHubClientFactoryProvider.Default is global::MagicOnion.Client.ImmutableStreamingHubClientFactoryProvider immutableStreamingHubClientFactoryProvider)
? immutableStreamingHubClientFactoryProvider.Add(provider)
: new global::MagicOnion.Client.ImmutableStreamingHubClientFactoryProvider(provider);

return true;
}

class MagicOnionGeneratedClientFactoryProvider : global::MagicOnion.Client.IMagicOnionClientFactoryProvider, global::MagicOnion.Client.IStreamingHubClientFactoryProvider
{
bool global::MagicOnion.Client.IMagicOnionClientFactoryProvider.TryGetFactory<T>(out global::MagicOnion.Client.MagicOnionClientFactoryDelegate<T> factory)
=> (factory = MagicOnionClientFactoryCache<T>.Factory) != null;

bool global::MagicOnion.Client.IStreamingHubClientFactoryProvider.TryGetFactory<TStreamingHub, TReceiver>(out global::MagicOnion.Client.StreamingHubClientFactoryDelegate<TStreamingHub, TReceiver> factory)
=> (factory = StreamingHubClientFactoryCache<TStreamingHub, TReceiver>.Factory) != null;

static class MagicOnionClientFactoryCache<T> where T : global::MagicOnion.IService<T>
{
public readonly static global::MagicOnion.Client.MagicOnionClientFactoryDelegate<T> Factory;

static MagicOnionClientFactoryCache()
{
object factory = default(global::MagicOnion.Client.MagicOnionClientFactoryDelegate<T>);

if (typeof(T) == typeof(global::MyApplication1.IGreeterService))
{
factory = ((global::MagicOnion.Client.MagicOnionClientFactoryDelegate<global::MyApplication1.IGreeterService>)((x, y) => new MagicOnionGeneratedClient.MyApplication1_GreeterServiceClient(x, y)));
}
Factory = (global::MagicOnion.Client.MagicOnionClientFactoryDelegate<T>)factory;
}
}

static class StreamingHubClientFactoryCache<TStreamingHub, TReceiver> where TStreamingHub : global::MagicOnion.IStreamingHub<TStreamingHub, TReceiver>
{
public readonly static global::MagicOnion.Client.StreamingHubClientFactoryDelegate<TStreamingHub, TReceiver> Factory;

static StreamingHubClientFactoryCache()
{
object factory = default(global::MagicOnion.Client.StreamingHubClientFactoryDelegate<TStreamingHub, TReceiver>);


Factory = (global::MagicOnion.Client.StreamingHubClientFactoryDelegate<TStreamingHub, TReceiver>)factory;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,79 +2,19 @@
#pragma warning disable CS0618 // 'member' is obsolete: 'text'
#pragma warning disable CS0612 // 'member' is obsolete
#pragma warning disable CS8019 // Unnecessary using directive.
#pragma warning disable CS1522 // Empty switch block

namespace MyApplication1
{
using global::System;
using global::MessagePack;

using global::MemoryPack;
partial class MagicOnionInitializer
{
/// <summary>
/// Gets the generated MessagePack formatter resolver.
/// Registers the generated MemoryPackFormatters.
/// </summary>
public static global::MessagePack.IFormatterResolver Resolver => MessagePackGeneratedResolver.Instance;
class MessagePackGeneratedResolver : global::MessagePack.IFormatterResolver
{
public static readonly global::MessagePack.IFormatterResolver Instance = new MessagePackGeneratedResolver();

MessagePackGeneratedResolver() {}

public global::MessagePack.Formatters.IMessagePackFormatter<T> GetFormatter<T>()
=> FormatterCache<T>.formatter;

static class FormatterCache<T>
{
public static readonly global::MessagePack.Formatters.IMessagePackFormatter<T> formatter;

static FormatterCache()
{
var f = MessagePackGeneratedGetFormatterHelper.GetFormatter(typeof(T));
if (f != null)
{
formatter = (global::MessagePack.Formatters.IMessagePackFormatter<T>)f;
}
}
}
}
static class MessagePackGeneratedGetFormatterHelper
{
static readonly global::System.Collections.Generic.Dictionary<global::System.Type, int> lookup;

static MessagePackGeneratedGetFormatterHelper()
{
lookup = new global::System.Collections.Generic.Dictionary<global::System.Type, int>(1)
{
{typeof(global::MagicOnion.DynamicArgumentTuple<global::System.String, global::System.Int32>), 0},
};
}
internal static object GetFormatter(global::System.Type t)
{
int key;
if (!lookup.TryGetValue(t, out key))
{
return null;
}

switch (key)
{
case 0: return new global::MagicOnion.DynamicArgumentTupleFormatter<global::System.String, global::System.Int32>(default(global::System.String), default(global::System.Int32));
default: return null;
}
}
}
/// <summary>Type hints for Ahead-of-Time compilation.</summary>
[Preserve]
static class TypeHints
public static void RegisterMemoryPackFormatters()
{
[Preserve]
internal static void Register()
{
_ = MessagePackGeneratedResolver.Instance.GetFormatter<global::MagicOnion.DynamicArgumentTuple<global::System.String, global::System.Int32>>();
_ = MessagePackGeneratedResolver.Instance.GetFormatter<global::System.Int32>();
_ = MessagePackGeneratedResolver.Instance.GetFormatter<global::System.String>();
}
global::MemoryPack.MemoryPackFormatterProvider.Register(new global::MagicOnion.Serialization.MemoryPack.DynamicArgumentTupleFormatter<global::System.String, global::System.Int32>());
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\MagicOnion.Client.SourceGenerator\MagicOnion.Client.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\src\MagicOnion.Serialization.MemoryPack\MagicOnion.Serialization.MemoryPack.csproj" />
<ProjectReference Include="..\..\src\MagicOnion\MagicOnion.csproj" />
<ProjectReference Include="..\samples\MagicOnionTestServer\MagicOnionTestServer.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using MagicOnion.Client;

namespace MagicOnion.Serialization.MemoryPack.Tests;

[MagicOnionClientGeneration(typeof(MagicOnionGeneratedClientInitializer), Serializer = GenerateSerializerType.MemoryPack)]
public partial class MagicOnionGeneratedClientInitializer
{}
Loading

0 comments on commit a2a0ecc

Please sign in to comment.