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

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

/// <summary>
/// Synchronously disposable object
/// </summary>
[u.sync_only_disposable]
public abstract class DisposableSyncImpl<TSelf>: u.IDisposableSync<TSelf>
where TSelf: DisposableSyncImpl<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 StackTrace? DisposableCreationStack =>
   u.disposable_impl.CreationStackValue( ref _creationStack );

//--------------------------------------------------------------------------------------------------

[MethodImpl( MethodImplOptions.NoInlining )]
protected void ValidateDisposable() =>
   u.disposable_impl.Validate( ref _needsDispose, ref _creationStack, 1 );

/// <exception cref="ArgumentOutOfRangeException" />
[MethodImpl( MethodImplOptions.NoInlining )]
protected void ValidateDisposable( [u.not_negative] int skipFrames ) =>
   u.disposable_impl.Validate( ref _needsDispose, ref _creationStack,
      u.arg_check.NotNegative( skipFrames, nameof(skipFrames) ) + 1 );

protected void ValidateDisposable( StackTrace? creationStack ) =>
   u.disposable_impl.Validate( ref _needsDispose, ref _creationStack, creationStack );

//--------------------------------------------------------------------------------------------------

protected virtual void OnSyncDispose()
{}

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

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

/// <exception cref="InvalidOperationException" />
~DisposableSyncImpl() =>
   u.disposable_impl.VerifySyncDisposedFromFinalizer(
      IsValidDisposable, GetType(), _creationStack );

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

StackTrace? _creationStack;
bool _needsDispose;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
} // DisposableSyncImpl<TSelf>

} // user_rtx (.wasm)
