/// <summary> /// Initializes a new instance of the <see cref="Sequence{T}"/> class. /// </summary> /// <param name="arrayPool">The pool to use for recycling backing arrays.</param> public Sequence(ArrayPool <T> arrayPool) { Requires.NotNull(arrayPool, nameof(arrayPool)); this.arrayPool = arrayPool; }
/// <summary> /// Apply channel options to this channel, including setting up or migrating to an user-supplied pipe writer/reader pair. /// </summary> /// <param name="channelOptions">The channel options to apply.</param> private void ApplyChannelOptions(ChannelOptions channelOptions) { Requires.NotNull(channelOptions, nameof(channelOptions)); Assumes.Null(this.TraceSource); // We've already applied options try { this.TraceSource = channelOptions.TraceSource ?? this.MultiplexingStream.DefaultChannelTraceSourceFactory?.Invoke(this.Id, this.Name) ?? new TraceSource($"{nameof(Streams.MultiplexingStream)}.{nameof(Channel)} {this.Id} ({this.Name})", SourceLevels.Critical); if (channelOptions.ExistingPipe != null) { lock (this.SyncObject) { Verify.NotDisposed(this); if (this.mxStreamIOWriter != null) { // A Pipe was already created (because data has been coming in for this channel even before it was accepted). // To be most efficient, we need to: // 1. Start forwarding all bytes written with this.mxStreamIOWriter to channelOptions.ExistingPipe.Output // 2. Arrange for the *next* call to GetReceivedMessagePipeWriterAsync to: // call this.mxStreamIOWriter.Complete() // wait for our forwarding code to finish (without propagating copmletion to channel.ExistingPipe.Output) // return channel.ExistingPipe.Output // From then on, GetReceivedMessagePipeWriterAsync should simply return channel.ExistingPipe.Output // Since this channel hasn't yet been exposed to the local owner, we can just replace the PipeWriter they use to transmit. // Take ownership of reading bytes that the MultiplexingStream may have already written to this channel. var mxStreamIncomingBytesReader = this.channelIO.Input; this.channelIO = null; // Forward any bytes written by the MultiplexingStream to the ExistingPipe.Output writer, // and make that ExistingPipe.Output writer available only after the old Pipe-based writer has completed. // First, capture the ExistingPipe as a local since ChannelOptions is a mutable type, and we're going to need // its current value later on. var existingPipe = channelOptions.ExistingPipe; this.switchingToExistingPipe = Task.Run(async delegate { // Await propagation of all bytes. Don't complete the ExistingPipe.Output when we're done because we still want to use it. await mxStreamIncomingBytesReader.LinkToAsync(existingPipe.Output, propagateSuccessfulCompletion: false).ConfigureAwait(false); return(existingPipe.Output); }); } else { // We haven't created a Pipe yet, so we can simply direct all writing to the ExistingPipe.Output immediately. this.mxStreamIOWriter = channelOptions.ExistingPipe.Output; } this.mxStreamIOReader = channelOptions.ExistingPipe.Input; } } else { this.InitializeOwnPipes(); } this.mxStreamIOReaderCompleted = this.ProcessOutboundTransmissionsAsync(); this.DisposeSelfOnFailure(this.mxStreamIOReaderCompleted); this.DisposeSelfOnFailure(this.AutoCloseOnPipesClosureAsync()); } catch (Exception ex) { this.optionsAppliedTaskSource?.TrySetException(ex); throw; } finally { this.optionsAppliedTaskSource?.TrySetResult(null); } }
/// <summary> /// Initializes a new instance of the <see cref="Sequence{T}"/> class. /// </summary> /// <param name="memoryPool">The pool to use for recycling backing arrays.</param> public Sequence(MemoryPool <T> memoryPool) { Requires.NotNull(memoryPool, nameof(memoryPool)); this.memoryPool = memoryPool; }
/// <summary> /// Advances the sequence to include the specified number of elements initialized into memory /// returned by a prior call to <see cref="GetMemory(int)"/>. /// </summary> /// <param name="count">The number of elements written into memory.</param> public void Advance(int count) { Requires.Range(count >= 0, nameof(count)); this.last.End += count; }