Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
59 changed files
with
1,059 additions
and
206 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
#region Copyright notice and license | ||
|
||
// Copyright 2019 The gRPC Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
#endregion | ||
|
||
using System.Diagnostics; | ||
|
||
#if NETSTANDARD2_0 | ||
|
||
// Copied with permission from https://github.com/dotnet/runtime/blob/589d0dc326bf0699149f76033fa66d4b22b9a7fd/src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs | ||
// This copy of ArrayBufferWriter is only used with .NET Stardard 2.0. Later versions of .NET ship with this type. | ||
namespace System.Buffers | ||
{ | ||
/// <summary> | ||
/// Represents a heap-based, array-backed output sink into which <typeparam name="T"/> data can be written. | ||
/// </summary> | ||
internal sealed class ArrayBufferWriter<T> : IBufferWriter<T> | ||
{ | ||
// Copy of Array.MaxArrayLength. For byte arrays the limit is slightly larger | ||
private const int MaxArrayLength = 0X7FEFFFFF; | ||
|
||
private const int DefaultInitialBufferSize = 256; | ||
|
||
private T[] _buffer; | ||
private int _index; | ||
|
||
|
||
/// <summary> | ||
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to, | ||
/// with the default initial capacity. | ||
/// </summary> | ||
public ArrayBufferWriter() | ||
{ | ||
_buffer = Array.Empty<T>(); | ||
_index = 0; | ||
} | ||
|
||
/// <summary> | ||
/// Creates an instance of an <see cref="ArrayBufferWriter{T}"/>, in which data can be written to, | ||
/// with an initial capacity specified. | ||
/// </summary> | ||
/// <param name="initialCapacity">The minimum capacity with which to initialize the underlying buffer.</param> | ||
/// <exception cref="ArgumentException"> | ||
/// Thrown when <paramref name="initialCapacity"/> is not positive (i.e. less than or equal to 0). | ||
/// </exception> | ||
public ArrayBufferWriter(int initialCapacity) | ||
{ | ||
if (initialCapacity <= 0) | ||
throw new ArgumentException(null, nameof(initialCapacity)); | ||
|
||
_buffer = new T[initialCapacity]; | ||
_index = 0; | ||
} | ||
|
||
/// <summary> | ||
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlyMemory{T}"/>. | ||
/// </summary> | ||
public ReadOnlyMemory<T> WrittenMemory => _buffer.AsMemory(0, _index); | ||
|
||
/// <summary> | ||
/// Returns the data written to the underlying buffer so far, as a <see cref="ReadOnlySpan{T}"/>. | ||
/// </summary> | ||
public ReadOnlySpan<T> WrittenSpan => _buffer.AsSpan(0, _index); | ||
|
||
/// <summary> | ||
/// Returns the amount of data written to the underlying buffer so far. | ||
/// </summary> | ||
public int WrittenCount => _index; | ||
|
||
/// <summary> | ||
/// Returns the total amount of space within the underlying buffer. | ||
/// </summary> | ||
public int Capacity => _buffer.Length; | ||
|
||
/// <summary> | ||
/// Returns the amount of space available that can still be written into without forcing the underlying buffer to grow. | ||
/// </summary> | ||
public int FreeCapacity => _buffer.Length - _index; | ||
|
||
/// <summary> | ||
/// Clears the data written to the underlying buffer. | ||
/// </summary> | ||
/// <remarks> | ||
/// You must clear the <see cref="ArrayBufferWriter{T}"/> before trying to re-use it. | ||
/// </remarks> | ||
public void Clear() | ||
{ | ||
Debug.Assert(_buffer.Length >= _index); | ||
_buffer.AsSpan(0, _index).Clear(); | ||
_index = 0; | ||
} | ||
|
||
/// <summary> | ||
/// Notifies <see cref="IBufferWriter{T}"/> that <paramref name="count"/> amount of data was written to the output <see cref="Span{T}"/>/<see cref="Memory{T}"/> | ||
/// </summary> | ||
/// <exception cref="ArgumentException"> | ||
/// Thrown when <paramref name="count"/> is negative. | ||
/// </exception> | ||
/// <exception cref="InvalidOperationException"> | ||
/// Thrown when attempting to advance past the end of the underlying buffer. | ||
/// </exception> | ||
/// <remarks> | ||
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer. | ||
/// </remarks> | ||
public void Advance(int count) | ||
{ | ||
if (count < 0) | ||
throw new ArgumentException(null, nameof(count)); | ||
|
||
if (_index > _buffer.Length - count) | ||
ThrowInvalidOperationException_AdvancedTooFar(_buffer.Length); | ||
|
||
_index += count; | ||
} | ||
|
||
/// <summary> | ||
/// Returns a <see cref="Memory{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>). | ||
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned. | ||
/// </summary> | ||
/// <exception cref="ArgumentException"> | ||
/// Thrown when <paramref name="sizeHint"/> is negative. | ||
/// </exception> | ||
/// <remarks> | ||
/// This will never return an empty <see cref="Memory{T}"/>. | ||
/// </remarks> | ||
/// <remarks> | ||
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer. | ||
/// </remarks> | ||
/// <remarks> | ||
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer. | ||
/// </remarks> | ||
public Memory<T> GetMemory(int sizeHint = 0) | ||
{ | ||
CheckAndResizeBuffer(sizeHint); | ||
Debug.Assert(_buffer.Length > _index); | ||
return _buffer.AsMemory(_index); | ||
} | ||
|
||
/// <summary> | ||
/// Returns a <see cref="Span{T}"/> to write to that is at least the requested length (specified by <paramref name="sizeHint"/>). | ||
/// If no <paramref name="sizeHint"/> is provided (or it's equal to <code>0</code>), some non-empty buffer is returned. | ||
/// </summary> | ||
/// <exception cref="ArgumentException"> | ||
/// Thrown when <paramref name="sizeHint"/> is negative. | ||
/// </exception> | ||
/// <remarks> | ||
/// This will never return an empty <see cref="Span{T}"/>. | ||
/// </remarks> | ||
/// <remarks> | ||
/// There is no guarantee that successive calls will return the same buffer or the same-sized buffer. | ||
/// </remarks> | ||
/// <remarks> | ||
/// You must request a new buffer after calling Advance to continue writing more data and cannot write to a previously acquired buffer. | ||
/// </remarks> | ||
public Span<T> GetSpan(int sizeHint = 0) | ||
{ | ||
CheckAndResizeBuffer(sizeHint); | ||
Debug.Assert(_buffer.Length > _index); | ||
return _buffer.AsSpan(_index); | ||
} | ||
|
||
private void CheckAndResizeBuffer(int sizeHint) | ||
{ | ||
if (sizeHint < 0) | ||
throw new ArgumentException(nameof(sizeHint)); | ||
|
||
if (sizeHint == 0) | ||
{ | ||
sizeHint = 1; | ||
} | ||
|
||
if (sizeHint > FreeCapacity) | ||
{ | ||
int currentLength = _buffer.Length; | ||
|
||
// Attempt to grow by the larger of the sizeHint and double the current size. | ||
int growBy = Math.Max(sizeHint, currentLength); | ||
|
||
if (currentLength == 0) | ||
{ | ||
growBy = Math.Max(growBy, DefaultInitialBufferSize); | ||
} | ||
|
||
int newSize = currentLength + growBy; | ||
|
||
if ((uint)newSize > int.MaxValue) | ||
{ | ||
// Attempt to grow to MaxArrayLength. | ||
uint needed = (uint)(currentLength - FreeCapacity + sizeHint); | ||
Debug.Assert(needed > currentLength); | ||
|
||
if (needed > MaxArrayLength) | ||
{ | ||
ThrowOutOfMemoryException(needed); | ||
} | ||
|
||
newSize = MaxArrayLength; | ||
} | ||
|
||
Array.Resize(ref _buffer, newSize); | ||
} | ||
|
||
Debug.Assert(FreeCapacity > 0 && FreeCapacity >= sizeHint); | ||
} | ||
|
||
private static void ThrowInvalidOperationException_AdvancedTooFar(int capacity) | ||
{ | ||
throw new InvalidOperationException($"Cannot advance past the end of the buffer, which has a size of {capacity}."); | ||
} | ||
|
||
private static void ThrowOutOfMemoryException(uint capacity) | ||
{ | ||
throw new OutOfMemoryException($"Cannot allocate a buffer of size {capacity}."); | ||
} | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Net; | ||
using System.Net.Http; | ||
using System.Net.Http.Headers; | ||
using System.Threading.Tasks; | ||
|
||
namespace Grpc.Net.Client.Internal | ||
{ | ||
internal static class CompatibilityExtensions | ||
{ | ||
#if !NETSTANDARD2_0 | ||
public static readonly Version Version20 = HttpVersion.Version20; | ||
#else | ||
public static readonly Version Version20 = new Version(2, 0); | ||
public static readonly string ResponseTrailersKey = "__ResponseTrailers"; | ||
#endif | ||
|
||
public static HttpHeaders GetTrailingHeaders(this HttpResponseMessage responseMessage) | ||
{ | ||
#if !NETSTANDARD2_0 | ||
return responseMessage.TrailingHeaders; | ||
#else | ||
if (!responseMessage.RequestMessage.Properties.TryGetValue(ResponseTrailersKey, out var headers)) | ||
{ | ||
throw new InvalidOperationException(); | ||
} | ||
return (HttpHeaders)headers; | ||
#endif | ||
} | ||
|
||
[Conditional("DEBUG")] | ||
public static void Assert([DoesNotReturnIf(false)] bool condition, string? message = null) | ||
{ | ||
Debug.Assert(condition, message); | ||
} | ||
|
||
public static bool IsCompletedSuccessfully(this Task task) | ||
{ | ||
// IsCompletedSuccessfully is the faster method, but only currently exposed on .NET Core 2.0+ | ||
#if !NETSTANDARD2_0 | ||
return task.IsCompletedSuccessfully; | ||
#else | ||
return task.Status == TaskStatus.RanToCompletion; | ||
#endif | ||
} | ||
|
||
#if !NETSTANDARD2_0 | ||
public static bool IsCompletedSuccessfully(this ValueTask task) | ||
{ | ||
return task.IsCompletedSuccessfully; | ||
} | ||
|
||
public static bool IsCompletedSuccessfully<T>(this ValueTask<T> task) | ||
{ | ||
return task.IsCompletedSuccessfully; | ||
} | ||
#endif | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.