//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
// UserRTX.NET satellite library | Author: Sergei Y.Kitáev
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;

#if !WASM
namespace user_rtx { using u = user_rtx;
#else
namespace user_rtx.wasm { using u = user_rtx.wasm;
#endif

/// <summary>
/// Synchronously and asynchronously and disposable object
/// </summary>
[u.sync_only_disposable]
public abstract class AsyncDisposableImpl<TSelf>: u.IAsyncDisposable<TSelf>
where TSelf: AsyncDisposableImpl<TSelf> {
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[u.volatile_access]
public bool IsValidDisposable =>
   NeedsDispose;

[u.volatile_access][u.returns_self]
public TSelf? ValidDisposableN =>
   IsValidDisposable ? DisposableSelf : default;

/// <exception cref="ObjectDisposedException" />
[u.volatile_access][u.returns_self]
public TSelf VerifyNotDisposed()
{
   u.disposable_impl.VerifyValid( IsValidDisposable, GetType() );
   return DisposableSelf;
}

//==================================================================================================

/// <exception cref="NotSupportedException" />
protected virtual TSelf DisposableSelf =>
   throw new NotSupportedException();

[u.volatile_access]
protected bool NeedsDispose =>
   disposable_impl.NeedsDisposeValue( ref _needsDispose );

[u.volatile_access]
protected void ValidateDisposable() =>
   disposable_impl.Validate( ref _needsDispose );

protected virtual void OnDispose( bool synchronous )
{}

protected virtual ValueTask OnDispose_A() =>
   default( ValueTask );

//==================================================================================================

public void Dispose()
{
   if ( u.disposable_impl.NeedsDispose( ref _needsDispose, this ) )
      OnDispose( true );
}

public async ValueTask DisposeAsync()
{
   if ( u.disposable_impl.NeedsDispose( ref _needsDispose, this ) )
      await OnDispose_A();
}

~AsyncDisposableImpl() =>
   OnDispose( false );

//==================================================================================================

bool _needsDispose;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // AsyncDisposableImpl<TSelf>

} // user_rtx (.wasm)
