namespace Python.Runtime
{
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
///
/// Represents a reference to a Python object, that is tracked by Python's reference counting.
///
[NonCopyable]
ref struct NewReference
{
IntPtr pointer;
/// Creates a pointing to the same object
[DebuggerHidden]
public NewReference(BorrowedReference reference, bool canBeNull = false)
{
var address = canBeNull
? reference.DangerousGetAddressOrNull()
: reference.DangerousGetAddress();
#pragma warning disable CS0618 // Type or member is obsolete
Runtime.XIncref(reference);
#pragma warning restore CS0618 // Type or member is obsolete
this.pointer = address;
}
/// Creates a pointing to the same object
public NewReference(in NewReference reference, bool canBeNull = false)
: this(reference.BorrowNullable(), canBeNull) { }
///
/// Returns wrapper around this reference, which now owns
/// the pointer. Sets the original reference to null, as it no longer owns it.
///
public PyObject MoveToPyObject()
{
if (this.IsNull()) throw new NullReferenceException();
return new PyObject(this.StealNullable());
}
///
/// Creates new instance of which now owns the pointer.
/// Sets the original reference to null, as it no longer owns the pointer.
///
public NewReference Move()
{
var result = DangerousFromPointer(this.DangerousGetAddress());
this.pointer = default;
return result;
}
/// Moves ownership of this instance to unmanged pointer
public IntPtr DangerousMoveToPointer()
{
if (this.IsNull()) throw new NullReferenceException();
var result = this.pointer;
this.pointer = IntPtr.Zero;
return result;
}
/// Moves ownership of this instance to unmanged pointer
public IntPtr DangerousMoveToPointerOrNull()
{
var result = this.pointer;
this.pointer = IntPtr.Zero;
return result;
}
///
/// Returns wrapper around this reference, which now owns
/// the pointer. Sets the original reference to null, as it no longer owns it.
///
public PyObject? MoveToPyObjectOrNull() => this.IsNull() ? null : this.MoveToPyObject();
///
/// Call this method to move ownership of this reference to a Python C API function,
/// that steals reference passed to it.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[DebuggerHidden]
public StolenReference StealNullable() => StolenReference.TakeNullable(ref this.pointer);
///
/// Call this method to move ownership of this reference to a Python C API function,
/// that steals reference passed to it.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[DebuggerHidden]
public StolenReference Steal()
{
if (this.IsNull()) throw new NullReferenceException();
return this.StealNullable();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[DebuggerHidden]
public StolenReference StealOrThrow()
{
if (this.IsNull()) throw PythonException.ThrowLastAsClrException();
return this.StealNullable();
}
///
/// Removes this reference to a Python object, and sets it to null.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
if (this.IsNull())
{
return;
}
Runtime.XDecref(this.Steal());
}
///
/// Creates from a raw pointer
///
[Pure]
public static NewReference DangerousFromPointer(IntPtr pointer)
=> new() { pointer = pointer};
[Pure]
internal static IntPtr DangerousGetAddressOrNull(in NewReference reference) => reference.pointer;
[Pure]
internal static IntPtr DangerousGetAddress(in NewReference reference)
=> IsNull(reference) ? throw new NullReferenceException() : reference.pointer;
[Pure]
[DebuggerHidden]
internal static bool IsNull(in NewReference reference)
=> reference.pointer == IntPtr.Zero;
}
///
/// These members can not be directly in type,
/// because this is always passed by value, which we need to avoid.
/// (note this in NewReference vs the usual this NewReference)
///
static class NewReferenceExtensions
{
/// Gets a raw pointer to the Python object
[Pure]
[DebuggerHidden]
public static IntPtr DangerousGetAddress(this in NewReference reference)
=> NewReference.DangerousGetAddress(reference);
[Pure]
[DebuggerHidden]
public static bool IsNull(this in NewReference reference)
=> NewReference.IsNull(reference);
[Pure]
[DebuggerHidden]
public static BorrowedReference BorrowNullable(this in NewReference reference)
=> new(NewReference.DangerousGetAddressOrNull(reference));
[Pure]
[DebuggerHidden]
public static BorrowedReference Borrow(this in NewReference reference)
=> reference.IsNull() ? throw new NullReferenceException() : reference.BorrowNullable();
[Pure]
[DebuggerHidden]
public static BorrowedReference BorrowOrThrow(this in NewReference reference)
=> reference.IsNull() ? throw PythonException.ThrowLastAsClrException() : reference.BorrowNullable();
}
}