Skip to content

Commit d90ecd4

Browse files
authored
Implement Stream api support (#341)
* client-to-server spike logic; not tested * server bindings (and binding tests, no integration test yet) * most basic of basic integration tests * optimize TryFastParse; needs tests * verify behaviour in all expected scenarios * for compat: don't demand the trailer Signed-off-by: Marc Gravell <[email protected]> * nit * marshaller validation * release notes * fix StreamRewriteBasicTest (timing brittleness) --------- Signed-off-by: Marc Gravell <[email protected]>
1 parent bd09eed commit d90ecd4

29 files changed

+1749
-120
lines changed

Directory.Packages.props

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
<PackageVersion Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3" />
2222
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
2323
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.6.143" />
24+
<PackageVersion Include="System.IO.Pipelines" Version="8.0.0" />
25+
<PackageVersion Include="System.Memory" Version="4.5.5" />
2426
<PackageVersion Include="System.Reactive" Version="6.0.1" />
25-
<PackageVersion Include="System.Threading.Channels" Version="8.0.0" />
26-
<PackageVersion Include="System.ServiceModel.Primitives" Version="8.0.0" />
2727
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
28+
<PackageVersion Include="System.ServiceModel.Primitives" Version="8.0.0" />
29+
<PackageVersion Include="System.Threading.Channels" Version="8.0.0" />
30+
<PackageVersion Include="System.ValueTuple" Version="4.5.0" />
2831
<PackageVersion Include="xunit" Version="2.9.2" />
2932
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
3033
<PackageVersion Include="TaskBuilder.fs" Version="2.1.0" />

docs/releasenotes.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22

33
## unreleased
44

5+
## 1.2.0
6+
7+
- support `[Value]Task<Stream>` as a return value, rewriting via [`stream BytesValue`](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/wrappers.proto) - first
8+
step in [#340](https://github.com/protobuf-net/protobuf-net.Grpc/issues/340)
9+
- update library references and TFMs
510
- improve handling of `IAsyncDisposable`
11+
- improve error message when binding methods ([#331](https://github.com/protobuf-net/protobuf-net.Grpc/pull/331) via BasConijn)
612

713
## 1.1.1
814

examples/pb-net/JustProtos/SomeType.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ static void Foo()
1212
{
1313
// the point here being: these types *exist*, despite
1414
// not appearing as local .cs files
15-
Type[] types = {
15+
Type[] types = [
1616
typeof(DescriptorProto),
1717
typeof(TimeResult),
1818
typeof(MultiplyRequest),
19-
};
19+
];
2020
_ = types;
2121
}
2222
}

src/protobuf-net.Grpc.Reflection/SchemaGenerator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public string GetSchema<TService>()
4141
/// this method need to remain for backward compatibility for client which will get this updated version, without recompilation.
4242
/// Thus, this method mustn't be deleted.</remarks>
4343
public string GetSchema(Type contractType)
44-
=> GetSchema(new [] {contractType});
44+
=> GetSchema([contractType]);
4545

4646
/// <summary>
4747
/// Get the .proto schema associated with multiple service contracts

src/protobuf-net.Grpc/Configuration/BinderConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace ProtoBuf.Grpc.Configuration
1212
public sealed class BinderConfiguration
1313
{
1414
// this *must* stay above Default - .cctor order is file order
15-
static readonly MarshallerFactory[] s_defaultFactories = new MarshallerFactory[] { ProtoBufMarshallerFactory.Default, ProtoBufMarshallerFactory.GoogleProtobuf };
15+
static readonly MarshallerFactory[] s_defaultFactories = [ProtoBufMarshallerFactory.Default, ProtoBufMarshallerFactory.GoogleProtobuf];
1616

1717
/// <summary>
1818
/// Use the default MarshallerFactory and ServiceBinder

src/protobuf-net.Grpc/Configuration/ClientFactory.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,22 +46,17 @@ public virtual GrpcClient CreateClient(CallInvoker channel, Type contractType)
4646
=> new GrpcClient(channel, contractType, BinderConfiguration);
4747

4848

49-
private sealed class ConfiguredClientFactory : ClientFactory
49+
private sealed class ConfiguredClientFactory(BinderConfiguration? binderConfiguration) : ClientFactory
5050
{
51-
protected override BinderConfiguration BinderConfiguration { get; }
52-
53-
public ConfiguredClientFactory(BinderConfiguration? binderConfiguration)
54-
{
55-
BinderConfiguration = binderConfiguration ?? BinderConfiguration.Default;
56-
}
51+
protected override BinderConfiguration BinderConfiguration { get; } = binderConfiguration ?? BinderConfiguration.Default;
5752

5853
private readonly ConcurrentDictionary<Type, object> _proxyCache = new ConcurrentDictionary<Type, object>();
5954

6055
[MethodImpl(MethodImplOptions.NoInlining)]
6156
private TService SlowCreateClient<TService>(CallInvoker channel)
6257
where TService : class
6358
{
64-
var factory = ProxyEmitter.CreateFactory<TService>(BinderConfiguration);
59+
var factory = ProxyEmitter.CreateFactory<TService>(BinderConfiguration, null);
6560
var key = typeof(TService);
6661

6762
if (!_proxyCache.TryAdd(key, factory)) factory = (Func<CallInvoker, TService>)_proxyCache[key];
@@ -78,7 +73,7 @@ public override TService CreateClient<TService>(CallInvoker channel)
7873

7974
internal static class DefaultProxyCache<TService> where TService : class
8075
{
81-
internal static readonly Func<CallInvoker, TService> Create = ProxyEmitter.CreateFactory<TService>(BinderConfiguration.Default);
76+
internal static readonly Func<CallInvoker, TService> Create = ProxyEmitter.CreateFactory<TService>(BinderConfiguration.Default, null);
8277
}
8378

8479
private sealed class DefaultClientFactory : ClientFactory

src/protobuf-net.Grpc/Configuration/GoogleProtobufMarshallerFactory.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,16 @@ protected internal override Marshaller<T> CreateMarshaller<T>()
6464
parser.ParseFrom(context.PayloadAsReadOnlySequence()
6565
*/
6666
var context = Expression.Parameter(typeof(global::Grpc.Core.DeserializationContext), "context");
67-
var parseFrom = parser.PropertyType.GetMethod("ParseFrom", new Type[] { typeof(ReadOnlySequence<byte>) })!;
67+
var parseFrom = parser.PropertyType.GetMethod("ParseFrom", [typeof(ReadOnlySequence<byte>)])!;
6868
Expression body = Expression.Call(Expression.Constant(parser.GetValue(null), parser.PropertyType),
6969
parseFrom, Expression.Call(context, nameof(DeserializationContext.PayloadAsReadOnlySequence), Type.EmptyTypes));
7070
deserializer = Expression.Lambda<Func<DeserializationContext, T>>(body, context).Compile();
7171

7272
var message = Expression.Parameter(typeof(T), "message");
7373
context = Expression.Parameter(typeof(global::Grpc.Core.SerializationContext), "context");
74-
var setPayloadLength = typeof(global::Grpc.Core.SerializationContext).GetMethod(nameof(global::Grpc.Core.SerializationContext.SetPayloadLength), new Type[] { typeof(int) })!;
74+
var setPayloadLength = typeof(global::Grpc.Core.SerializationContext).GetMethod(nameof(global::Grpc.Core.SerializationContext.SetPayloadLength), [typeof(int)])!;
7575
var calculateSize = iMessage.GetMethod("CalculateSize", Type.EmptyTypes)!;
76-
var writeTo = me.GetMethod("WriteTo", new Type[] { iMessage, typeof(IBufferWriter<byte>) })!;
76+
var writeTo = me.GetMethod("WriteTo", [iMessage, typeof(IBufferWriter<byte>)])!;
7777
body = Expression.Block(
7878
Expression.Call(context, setPayloadLength, Expression.Call(message, calculateSize)),
7979
Expression.Call(writeTo, message, Expression.Call(context, "GetBufferWriter", Type.EmptyTypes)),
@@ -92,16 +92,16 @@ protected internal override Marshaller<T> CreateMarshaller<T>()
9292
*/
9393

9494
var context = Expression.Parameter(typeof(global::Grpc.Core.DeserializationContext), "context");
95-
var parseFrom = parser.PropertyType.GetMethod("ParseFrom", new Type[] { typeof(byte[]) })!;
95+
var parseFrom = parser.PropertyType.GetMethod("ParseFrom", [typeof(byte[])])!;
9696
Expression body = Expression.Call(Expression.Constant(parser.GetValue(null), parser.PropertyType),
9797
parseFrom, Expression.Call(context, nameof(DeserializationContext.PayloadAsNewBuffer), Type.EmptyTypes));
9898
deserializer = Expression.Lambda<Func<DeserializationContext, T>>(body, context).Compile();
9999

100100
var message = Expression.Parameter(typeof(T), "message");
101101
context = Expression.Parameter(typeof(global::Grpc.Core.SerializationContext), "context");
102-
var toByteArray = me.GetMethod("ToByteArray", new Type[] { iMessage })!;
102+
var toByteArray = me.GetMethod("ToByteArray", [iMessage])!;
103103
var complete = typeof(global::Grpc.Core.SerializationContext).GetMethod(
104-
nameof(global::Grpc.Core.SerializationContext.Complete), new Type[] { typeof(byte[]) })!;
104+
nameof(global::Grpc.Core.SerializationContext.Complete), [typeof(byte[])])!;
105105
body = Expression.Call(context, complete, Expression.Call(toByteArray, message));
106106
serializer = Expression.Lambda<Action<T, global::Grpc.Core.SerializationContext>>(body, message, context).Compile();
107107
}

src/protobuf-net.Grpc/Configuration/ProtoBufMarshallerFactory.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ public enum Options
5555
// note: these are the same *object*, but pre-checked for optional API support, for efficiency
5656
// (the minimum .NET object size means that the extra fields don't cost anything)
5757
private readonly IMeasuredProtoOutput<IBufferWriter<byte>>? _measuredWriterModel;
58+
#pragma warning disable CA1859 // change type of field for performance - but actually this is a speculative test
5859
private readonly IProtoInput<ReadOnlySequence<byte>>? _squenceReaderModel;
60+
#pragma warning restore CA1859
5961

6062
/// <summary>
6163
/// Create a new factory using a specific protobuf-net model

src/protobuf-net.Grpc/Configuration/ServerBinder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public int Bind(object state, Type serviceType, BinderConfiguration? binderConfi
3737
{
3838
int totalCount = 0;
3939
object?[]? argsBuffer = null;
40-
Type[] typesBuffer = Array.Empty<Type>();
40+
Type[] typesBuffer = [];
4141
binderConfiguration ??= BinderConfiguration.Default;
4242
var potentialServiceContracts = typeof(IGrpcService).IsAssignableFrom(serviceType)
4343
? new HashSet<Type> {serviceType}
@@ -92,7 +92,7 @@ bool AddMethod(string? serviceName, Type @in, Type @out, string on, MethodInfo m
9292
{
9393
if (typesBuffer.Length == 0)
9494
{
95-
typesBuffer = new Type[] {serviceType, typeof(void), typeof(void)};
95+
typesBuffer = [serviceType, typeof(void), typeof(void)];
9696
}
9797

9898
typesBuffer[1] = @in;

0 commit comments

Comments
 (0)