forked from pythonnet/pythonnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNewReference.cs
More file actions
160 lines (140 loc) · 5.93 KB
/
NewReference.cs
File metadata and controls
160 lines (140 loc) · 5.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
namespace Python.Runtime
{
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
/// <summary>
/// Represents a reference to a Python object, that is tracked by Python's reference counting.
/// </summary>
[NonCopyable]
ref struct NewReference
{
IntPtr pointer;
/// <summary>Creates a <see cref="NewReference"/> pointing to the same object</summary>
[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;
}
/// <summary>Creates a <see cref="NewReference"/> pointing to the same object</summary>
public NewReference(in NewReference reference, bool canBeNull = false)
: this(reference.BorrowNullable(), canBeNull) { }
/// <summary>
/// Returns <see cref="PyObject"/> wrapper around this reference, which now owns
/// the pointer. Sets the original reference to <c>null</c>, as it no longer owns it.
/// </summary>
public PyObject MoveToPyObject()
{
if (this.IsNull()) throw new NullReferenceException();
return new PyObject(this.StealNullable());
}
/// <summary>Moves ownership of this instance to unmanged pointer</summary>
public IntPtr DangerousMoveToPointer()
{
if (this.IsNull()) throw new NullReferenceException();
var result = this.pointer;
this.pointer = IntPtr.Zero;
return result;
}
/// <summary>Moves ownership of this instance to unmanged pointer</summary>
public IntPtr DangerousMoveToPointerOrNull()
{
var result = this.pointer;
this.pointer = IntPtr.Zero;
return result;
}
/// <summary>
/// Returns <see cref="PyObject"/> wrapper around this reference, which now owns
/// the pointer. Sets the original reference to <c>null</c>, as it no longer owns it.
/// </summary>
public PyObject? MoveToPyObjectOrNull() => this.IsNull() ? null : this.MoveToPyObject();
/// <summary>
/// Call this method to move ownership of this reference to a Python C API function,
/// that steals reference passed to it.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[DebuggerHidden]
public StolenReference StealNullable() => StolenReference.TakeNullable(ref this.pointer);
/// <summary>
/// Call this method to move ownership of this reference to a Python C API function,
/// that steals reference passed to it.
/// </summary>
[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();
}
/// <summary>
/// Removes this reference to a Python object, and sets it to <c>null</c>.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
if (this.IsNull())
{
return;
}
Runtime.XDecref(this.Steal());
}
/// <summary>
/// Creates <see cref="NewReference"/> from a raw pointer
/// </summary>
[Pure]
public static NewReference DangerousFromPointer(IntPtr pointer)
=> new NewReference {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;
}
/// <summary>
/// These members can not be directly in <see cref="NewReference"/> type,
/// because <c>this</c> is always passed by value, which we need to avoid.
/// (note <code>this in NewReference</code> vs the usual <code>this NewReference</code>)
/// </summary>
static class NewReferenceExtensions
{
/// <summary>Gets a raw pointer to the Python object</summary>
[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();
}
}