Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix code generation for MemoryPack #700

Merged
merged 2 commits into from
Oct 26, 2023
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
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
Loading