1 module python.conv;
2 
3 
4 import python.raw: PyObject;
5 import std.traits: Unqual, isIntegral, isFloatingPoint, isAggregateType, isArray, isStaticArray;
6 import std.range: isInputRange;
7 import std.datetime: DateTime, Date;
8 
9 
10 private enum isDateOrDateTime(T) = is(Unqual!T == DateTime) || is(Unqual!T == Date);
11 
12 
13 PyObject* toPython(T)(T value) @trusted if(isIntegral!T) {
14     import python.raw: PyLong_FromLong;
15     return PyLong_FromLong(value);
16 }
17 
18 
19 PyObject* toPython(T)(T value) @trusted if(isFloatingPoint!T) {
20     import python.raw: PyFloat_FromDouble;
21     return PyFloat_FromDouble(value);
22 }
23 
24 
25 PyObject* toPython(T)(T value) if(isInputRange!T && !is(T == string) && !isStaticArray!T) {
26     import python.raw: PyList_New, PyList_SetItem;
27 
28     auto ret = PyList_New(value.length);
29 
30     foreach(i, elt; value) {
31         PyList_SetItem(ret, i, toPython(elt));
32     }
33 
34     return ret;
35 
36 }
37 
38 
39 PyObject* toPython(T)(T value) if(isAggregateType!T && !isInputRange!T && !isDateOrDateTime!T) {
40     import python.type: pythonClass;
41     return pythonClass(value);
42 }
43 
44 
45 PyObject* toPython(T)(T value) if(is(Unqual!T == DateTime)) {
46     import python.raw: pyDateTimeFromDateAndTime;
47     return pyDateTimeFromDateAndTime(value.year, value.month, value.day,
48                                      value.hour, value.minute, value.second);
49 }
50 
51 
52 PyObject* toPython(T)(T value) if(is(Unqual!T == Date)) {
53     import python.raw: pyDateFromDate;
54     return pyDateFromDate(value.year, value.month, value.day);
55 }
56 
57 
58 PyObject* toPython(T)(T value) if(is(T == string)) {
59     import python.raw: pyUnicodeFromStringAndSize;
60     return pyUnicodeFromStringAndSize(value.ptr, value.length);
61 }
62 
63 
64 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) {
65     import python.raw: PyBool_FromLong;
66     return PyBool_FromLong(value);
67 }
68 
69 
70 PyObject* toPython(T)(T value) if(isStaticArray!T) {
71     return toPython(value[]);
72 }
73 
74 
75 T to(T)(PyObject* value) @trusted if(isIntegral!T) {
76     import python.raw: PyLong_AsLong;
77 
78     const ret = PyLong_AsLong(value);
79     if(ret > T.max || ret < T.min) throw new Exception("Overflow");
80 
81     return cast(T) ret;
82 }
83 
84 
85 T to(T)(PyObject* value) @trusted if(isFloatingPoint!T) {
86     import python.raw: PyFloat_AsDouble;
87     auto ret = PyFloat_AsDouble(value);
88     return cast(T) ret;
89 }
90 
91 
92 T to(T)(PyObject* value) if(isAggregateType!T && !isDateOrDateTime!T) {
93     import python.type: PythonClass;
94 
95     auto pyclass = cast(PythonClass!T*) value;
96 
97     Unqual!T ret;
98 
99     static foreach(i; 0 .. T.tupleof.length) {
100         ret.tupleof[i] = pyclass.getField!i.to!(typeof(T.tupleof[i]));
101     }
102 
103     return ret;
104 }
105 
106 T to(T)(PyObject* value) if(is(Unqual!T == DateTime)) {
107     import python.raw;
108 
109     return DateTime(pyDateTimeYear(value),
110                     pyDateTimeMonth(value),
111                     pyDateTimeDay(value),
112                     pyDateTimeHour(value),
113                     pyDateTimeMinute(value),
114                     pyDateTimeSecond(value));
115 
116 }
117 
118 
119 T to(T)(PyObject* value) if(is(Unqual!T == Date)) {
120     import python.raw;
121 
122     return Date(pyDateTimeYear(value),
123                 pyDateTimeMonth(value),
124                 pyDateTimeDay(value));
125 }
126 
127 
128 T to(T)(PyObject* value) if(isArray!T && !is(T == string)) {
129     import python.raw: PyList_Size, PyList_GetItem;
130     import std.range: ElementType;
131 
132     T ret;
133     static if(__traits(compiles, ret.length = 1))
134         ret.length = PyList_Size(value);
135 
136     foreach(i, ref elt; ret) {
137         elt = PyList_GetItem(value, i).to!(ElementType!T);
138     }
139 
140     return ret;
141 }
142 
143 
144 T to(T)(PyObject* value) if(is(T == string)) {
145     import python.raw: pyUnicodeGetSize, pyUnicodeCheck,
146         pyBytesAsString, pyObjectUnicode, pyUnicodeAsUtf8String, Py_ssize_t;
147 
148     value = pyObjectUnicode(value);
149 
150     const length = pyUnicodeGetSize(value);
151 
152     auto ptr = pyBytesAsString(pyUnicodeAsUtf8String(value));
153     assert(length == 0 || ptr !is null);
154 
155     return ptr[0 .. length].idup;
156 }
157 
158 
159 T to(T)(PyObject* value) if(is(Unqual!T == bool)) {
160     import python.raw: pyTrue;
161     return value is pyTrue;
162 }