-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPythonValueConverter.cs
More file actions
119 lines (107 loc) · 3.78 KB
/
Copy pathPythonValueConverter.cs
File metadata and controls
119 lines (107 loc) · 3.78 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
using System.Numerics;
using DotPython.Contracts;
using DotPython.Runtime.Managed.Execution;
namespace DotPython.Runtime.Managed;
internal static class PythonValueConverter
{
internal static PythonValue FromClr(
object? value,
PythonTypeContract contract,
string moduleName,
string functionName
)
{
if (value is null)
{
if (contract.IsNullable)
{
return PythonNoneValue.Instance;
}
throw ConversionFailure(contract, moduleName, functionName, "Null is not allowed");
}
return (contract.ClrTypeName, value) switch
{
("System.Boolean", bool item) => PythonTruthValue.FromBoolean(item),
("System.Numerics.BigInteger", BigInteger item) => PythonWholeNumberValue.Create(item),
("System.Double", double item) => new PythonFloatingPointValue(item),
("System.String", string item) => new PythonTextValue(item),
("System.Byte[]", byte[] item) => new PythonByteSequenceValue((byte[])item.Clone()),
_ => throw ConversionFailure(
contract,
moduleName,
functionName,
$"CLR value type '{value.GetType().FullName}' is not supported"
),
};
}
internal static TResult ToClr<TResult>(
PythonValue value,
PythonTypeContract contract,
string moduleName,
string functionName
)
{
if (!ResultTypeMatches<TResult>(contract))
{
throw ConversionFailure(
contract,
moduleName,
functionName,
$"Requested CLR result type '{typeof(TResult).FullName}' does not match the contract"
);
}
object? result = (contract.ClrTypeName, value) switch
{
(_, PythonNoneValue) when contract.IsNullable => null,
("System.Boolean", PythonTruthValue item) => item.Value,
("System.Numerics.BigInteger", PythonWholeNumberValue item) => item.Value,
("System.Double", PythonFloatingPointValue item) => item.Value,
("System.String", PythonTextValue item) => item.Value,
("System.Byte[]", PythonByteSequenceValue item) => (byte[])item.Value.Clone(),
_ => throw ConversionFailure(
contract,
moduleName,
functionName,
$"Python value '{value.GetType().Name}' is not compatible"
),
};
if (result is null)
{
return default!;
}
if (result is TResult typed)
{
return typed;
}
throw ConversionFailure(
contract,
moduleName,
functionName,
$"Requested CLR result type '{typeof(TResult).FullName}' does not match the contract"
);
}
private static bool ResultTypeMatches<TResult>(PythonTypeContract contract)
{
var requestedType = typeof(TResult);
var nullableType = Nullable.GetUnderlyingType(requestedType);
var comparisonType = nullableType ?? requestedType;
if (!string.Equals(comparisonType.FullName, contract.ClrTypeName, StringComparison.Ordinal))
{
return false;
}
return !contract.IsNullable || !contract.IsValueType || nullableType is not null;
}
private static DotPythonException ConversionFailure(
PythonTypeContract contract,
string moduleName,
string functionName,
string reason
) =>
new(
"DPY6007",
$"{reason} for contract type '{contract.CSharpTypeName}'.",
DotPythonFailurePhase.Conversion,
moduleName,
functionName
);
}