1 module python.conv.d_to_python;
2 
3 
4 import python.raw: PyObject;
5 import python.type: isUserAggregate, isTuple, isNonRangeUDT;
6 import std.traits: Unqual, isIntegral, isFloatingPoint, isAggregateType,
7     isStaticArray, isAssociativeArray, isPointer, isSomeChar,
8     isCallable, isSomeString, isFunctionPointer, isDelegate,
9     PointerTarget;
10 import std.range: isInputRange, isInfinite;
11 import std.datetime: Date, DateTime;
12 import core.time: Duration;
13 
14 
15 PyObject* toPython(in bool val) @trusted @nogc {
16     import python.raw: pyIncRef, _Py_TrueStruct, _Py_FalseStruct;
17 
18     auto pyTrue = cast(PyObject*) &_Py_TrueStruct;
19     auto pyFalse = cast(PyObject*) &_Py_FalseStruct;
20 
21     static PyObject* incAndRet(PyObject* obj) {
22         pyIncRef(obj);
23         return obj;
24     }
25 
26     return val ? incAndRet(pyTrue) : incAndRet(pyFalse);
27 }
28 
29 
30 PyObject* toPython(T)(T value) @trusted if(isIntegral!T && !is(T == enum)) {
31     import python.raw: PyLong_FromLong;
32     return PyLong_FromLong(value);
33 }
34 
35 
36 PyObject* toPython(T)(T value) @trusted if(isFloatingPoint!T) {
37     import python.raw: PyFloat_FromDouble;
38     return PyFloat_FromDouble(value);
39 }
40 
41 
42 PyObject* toPython(T)(T value) if(is(Unqual!T == void[])) {
43     auto bytes = cast(ubyte[]) value;
44     return bytes.toPython;
45 }
46 
47 
48 PyObject* toPython(T)(T value)
49     if(isInputRange!T && !isInfinite!T && !isSomeString!T && !isStaticArray!T)
50 {
51     import python.raw: PyList_New, PyList_SetItem, PyList_Append;
52     import std.range: isForwardRange, enumerate;
53 
54     static if(__traits(hasMember, T, "length")) {
55         const length = value.length;
56         enum append = false;
57     } else static if(isForwardRange!T) {
58         import std.range: walkLength;
59         import std.array: save;
60         const length = walkLength(value.save);
61         enum append = false;
62     } else {
63         enum length = 0;
64         enum append = true;
65     }
66 
67     auto ret = PyList_New(length);
68 
69     foreach(i, elt; value.enumerate) {
70         static if(append)
71             PyList_Append(ret, toPython(elt));
72         else
73             PyList_SetItem(ret, i, toPython(elt));
74     }
75 
76     return ret;
77 }
78 
79 PyObject* toPython(T)(T value)
80     if(isInputRange!T && isInfinite!T)
81 {
82     import python.type: pythonClass;
83     return pythonClass(value);
84 }
85 
86 
87 PyObject* toPython(T)(auto ref T value) if(isNonRangeUDT!T) {
88     import python.type: pythonClass;
89     return pythonClass(value);
90 }
91 
92 
93 PyObject* toPython(T)(T value)
94     if(isPointer!T && !isFunctionPointer!T && !isDelegate!T && !is(Unqual!(PointerTarget!T) == void))
95 {
96     import autowrap.common: AlwaysTry;
97 
98     static if(AlwaysTry || __traits(compiles, toPython(*value))) {
99         import std.traits: PointerTarget;
100         import std..string: fromStringz;
101 
102         static if(is(PointerTarget!T == const(char)) || is(PointerTarget!T == immutable(char)))
103             return value.fromStringz.toPython;
104         else
105             return toPython(*value);
106     } else {
107         import std.traits: fullyQualifiedName;
108         enum msg = "could not convert " ~ fullyQualifiedName!T ~ " to Python";
109         pragma(msg, "WARNING: ", msg);
110         throw new Exception(msg);
111     }
112 }
113 
114 
115 PyObject* toPython(T)(T value)
116     if(isPointer!T && is(Unqual!(PointerTarget!T) == void))
117 {
118     throw new Exception("Converting void* to Python is not supported");
119 }
120 
121 
122 PyObject* toPython(T)(T value) if(is(Unqual!T == DateTime)) {
123     import python.raw: pyDateTimeFromDateAndTime;
124     return pyDateTimeFromDateAndTime(value.year, value.month, value.day,
125                                      value.hour, value.minute, value.second);
126 }
127 
128 
129 PyObject* toPython(T)(T value) if(is(Unqual!T == Date)) {
130     import python.raw: pyDateFromDate;
131     return pyDateFromDate(value.year, value.month, value.day);
132 }
133 
134 
135 PyObject* toPython(T)(T value) if(isSomeString!T) {
136     import python.raw: pyUnicodeFromStringAndSize;
137     import std.conv: to;
138     auto str = value.to!string;
139     return pyUnicodeFromStringAndSize(str.ptr, str.length);
140 }
141 
142 
143 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) {
144     import python.raw: PyBool_FromLong;
145     return PyBool_FromLong(value);
146 }
147 
148 
149 PyObject* toPython(T)(T value) if(isStaticArray!T) {
150     return toPython(value[]);
151 }
152 
153 
154 PyObject* toPython(T)(T value) if(isAssociativeArray!T) {
155     import python.raw: PyDict_New, PyDict_SetItem;
156 
157     auto ret = PyDict_New;
158 
159     foreach(k, v; value) {
160         PyDict_SetItem(ret, k.toPython, v.toPython);
161     }
162 
163     return ret;
164 }
165 
166 PyObject* toPython(T)(T value) if(isTuple!T) {
167     import python.raw: PyTuple_New, PyTuple_SetItem;
168 
169     auto ret = PyTuple_New(value.length);
170 
171     static foreach(i; 0 .. T.length) {
172         PyTuple_SetItem(ret, i, value[i].toPython);
173     }
174 
175     return ret;
176 }
177 
178 
179 PyObject* toPython(T)(T value) if(is(Unqual!T == char) || is(Unqual!T == wchar) || is(Unqual!T == dchar)) {
180     return [value].toPython;
181 }
182 
183 
184 PyObject* toPython(T)(T value) if(isCallable!T && !isUserAggregate!T) {
185     import python.type: pythonCallable;
186     return pythonCallable(value);
187 }
188 
189 
190 PyObject* toPython(T)(T value) if(is(Unqual!T == Duration)) {
191     import python.raw: pyDeltaFromDSU;
192     int days, seconds, useconds;
193     value.split!("days", "seconds", "usecs")(days, seconds, useconds);
194     return pyDeltaFromDSU(days, seconds, useconds);
195 }
196 
197 
198 PyObject* toPython(T)(T value) if(is(T == enum)) {
199     import std.traits: OriginalType;
200     return toPython(cast(OriginalType!T) value);
201 }