/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/LanguageServer/Protocol/Handler/BufferedProgress.cs
92 строки
3 KB
Cyrus Najmabadi
Use implicit object creation expressions
13 сен 2025, 01:48
13 сен 2025, 01:48
4c6a36a
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Linq; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.LanguageServer.Handler; /// <summary> /// Helper type to allow command handlers to report data either in a streaming fashion (if a client supports that), /// or as an array of results. This type is thread-safe in the same manner that <see cref="IProgress{T}"/> is /// expected to be. Namely, multiple client can be calling <see cref="IProgress{T}.Report(T)"/> on it at the same /// time. This is safe, though the order that the items are reported in when called concurrently is not specified. /// </summary> internal readonly struct BufferedProgress<T> : IProgress<T>, IDisposable { /// <summary> /// The progress stream to report results to. May be <see langword="null"/> for clients that do not support streaming. /// If <see langword="null"/> then <see cref="_buffer"/> will be non null and will contain all the produced values. /// </summary> private readonly IProgress<T>? _underlyingProgress; /// <summary> /// A buffer that results are held in if the client does not support streaming. Values of this can be retrieved /// using <see cref="GetValues"/>. /// </summary> private readonly ArrayBuilder<T>? _buffer; public BufferedProgress(IProgress<T>? underlyingProgress) { _underlyingProgress = underlyingProgress; _buffer = underlyingProgress == null ? ArrayBuilder<T>.GetInstance() : null; } public void Dispose() => _buffer?.Free(); /// <summary> /// Report a value either in a streaming or buffered fashion depending on what the client supports. /// </summary> public void Report(T value) { // Don't need to lock _underlyingProgress. It is inherently thread-safe itself being an IProgress implementation. _underlyingProgress?.Report(value); if (_buffer != null) { lock (_buffer) { _buffer.Add(value); } } } /// <summary> /// Gets the set of buffered values. Will return null if the client supports streaming. Must be called after /// all calls to <see cref="Report(T)"/> have been made. Not safe to call concurrently with any call to <see /// cref="Report(T)"/>. /// </summary> public T[]? GetValues() => _buffer?.ToArray(); } internal static class BufferedProgress { public static BufferedProgress<T> Create<T>(IProgress<T>? progress) => new(progress); public static BufferedProgress<TIn> Create<TIn, TOut>(IProgress<TOut>? progress, Func<TIn, TOut> transform) => Create(progress?.Transform(transform)); static IProgress<TIn> Transform<TIn, TOut>(this IProgress<TOut> progress, Func<TIn, TOut> transform) => new ProgressTransformer<TIn, TOut>(progress, transform); public static void Report<T>(this BufferedProgress<T[]> progress, T item) { progress.Report([item]); } public static T[]? GetFlattenedValues<T>(this BufferedProgress<T[]> progress) { return progress.GetValues()?.Flatten().ToArray(); } sealed class ProgressTransformer<TIn, TOut>(IProgress<TOut> inner, Func<TIn, TOut> transform) : IProgress<TIn> { public void Report(TIn value) => inner.Report(transform(value)); } }