// 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.
namespace System.Reactive.Threading
{
///
/// Returned by , enabling the caller to release the lock.
///
public struct AsyncGateReleaser : IDisposable
{
// Holds either an IAsyncGate or an IDisposable.
// In the case where this is an IAsyncGate, it's important that we try to avoid
// calling Release more than once, because this releaser is associated with just one
// call to LockAsync. IDisposable implementations are expected to be idempotent,
// so we need to remember when we've already made our one call to Release. (This
// can't be perfect because this is a struct, so callers might end up copying
// this value and then disposing each copy. But for normal using usage that won't
// be a problem, and this provides a reasonable best-effort approach. It's why
// this can't be a readonly struct though.)
private object _parentOrDisposable;
///
/// Creates an that calls
/// on its parent when disposed.
///
///
public AsyncGateReleaser(IAsyncGate parent) => _parentOrDisposable = parent;
///
/// Creates an that calls another disposable when disposed.
///
///
/// The implementation to which to defer.
///
///
/// This can be convenient for custom implementations in that wrap
/// some underlying lock implementation that returns an as the means
/// by which the lock is released.
///
public AsyncGateReleaser(IDisposable disposable) => _parentOrDisposable = disposable;
public void Dispose()
{
switch (_parentOrDisposable)
{
case IDisposable d: d.Dispose(); break;
case IAsyncGate g: g.Release(); break;
}
_parentOrDisposable = null;
}
}
}