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