File: Remote\RemoteServiceCallbackDispatcher.cs
Web Access
Project: src\roslyn\src\Workspaces\Core\Portable\Microsoft.CodeAnalysis.Workspaces.csproj (Microsoft.CodeAnalysis.Workspaces)
// 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.Collections.Concurrent;
using System.Threading;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Remote;

internal interface IRemoteServiceCallbackDispatcher
{
    RemoteServiceCallbackDispatcher.Handle CreateHandle(object? instance);
}

internal class RemoteServiceCallbackDispatcher : IRemoteServiceCallbackDispatcher
{
    internal readonly struct Handle(ConcurrentDictionary<RemoteServiceCallbackId, object> callbackInstances, RemoteServiceCallbackId callbackId) : IDisposable
    {
        public readonly RemoteServiceCallbackId Id = callbackId;

        public void Dispose()
        {
            Contract.ThrowIfTrue(callbackInstances?.TryRemove(Id, out _) == false);
        }
    }

    private int _callbackId = 1;
    private readonly ConcurrentDictionary<RemoteServiceCallbackId, object> _callbackInstances = new(concurrencyLevel: 2, capacity: 10);

    public Handle CreateHandle(object? instance)
    {
        if (instance is null)
        {
            return default;
        }

        var callbackId = new RemoteServiceCallbackId(Interlocked.Increment(ref _callbackId));
        var handle = new Handle(_callbackInstances, callbackId);
        _callbackInstances.Add(callbackId, instance);
        return handle;
    }

    public object GetCallback(RemoteServiceCallbackId callbackId)
    {
        Contract.ThrowIfFalse(_callbackInstances.TryGetValue(callbackId, out var instance));
        return instance;
    }
}