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, isArray,
7     isStaticArray, isAssociativeArray, isPointer, PointerTarget, isSomeChar, isCallable;
8 import std.range: isInputRange;
9 import std.datetime: Date, DateTime;
10 
11 
12 PyObject* toPython(T)(T value) @trusted if(isIntegral!T) {
13     import python.raw: PyLong_FromLong;
14     return PyLong_FromLong(value);
15 }
16 
17 
18 PyObject* toPython(T)(T value) @trusted if(isFloatingPoint!T) {
19     import python.raw: PyFloat_FromDouble;
20     return PyFloat_FromDouble(value);
21 }
22 
23 
24 PyObject* toPython(T)(T value) if(isInputRange!T && !is(T == string) && !isStaticArray!T) {
25     import python.raw: PyList_New, PyList_SetItem, PyList_Append;
26     import std.range: isForwardRange, enumerate;
27 
28     static if(__traits(hasMember, T, "length")) {
29         const length = value.length;
30         enum append = false;
31     } else static if(isForwardRange!T){
32         import std.range: walkLength;
33         import std.array: save;
34         static assert(isForwardRange!T);
35         const length = walkLength(value.save);
36         enum append = false;
37     } else {
38         enum length = 0;
39         enum append = true;
40     }
41 
42     auto ret = PyList_New(length);
43 
44     foreach(i, elt; value.enumerate) {
45         static if(append)
46             PyList_Append(ret, toPython(elt));
47         else
48             PyList_SetItem(ret, i, toPython(elt));
49     }
50 
51     return ret;
52 
53 }
54 
55 
56 PyObject* toPython(T)(T value) if(isNonRangeUDT!T) {
57     import python.type: pythonClass;
58     return pythonClass(value);
59 }
60 
61 
62 PyObject* toPython(T)(T value) if(isPointer!T && isNonRangeUDT!(PointerTarget!T)) {
63     return toPython(*value);
64 }
65 
66 
67 PyObject* toPython(T)(T value) if(is(Unqual!T == DateTime)) {
68     import python.raw: pyDateTimeFromDateAndTime;
69     return pyDateTimeFromDateAndTime(value.year, value.month, value.day,
70                                      value.hour, value.minute, value.second);
71 }
72 
73 
74 PyObject* toPython(T)(T value) if(is(Unqual!T == Date)) {
75     import python.raw: pyDateFromDate;
76     return pyDateFromDate(value.year, value.month, value.day);
77 }
78 
79 
80 PyObject* toPython(T)(T value) if(is(T == string)) {
81     import python.raw: pyUnicodeFromStringAndSize;
82     return pyUnicodeFromStringAndSize(value.ptr, value.length);
83 }
84 
85 
86 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) {
87     import python.raw: PyBool_FromLong;
88     return PyBool_FromLong(value);
89 }
90 
91 
92 PyObject* toPython(T)(T value) if(isStaticArray!T) {
93     return toPython(value[]);
94 }
95 
96 
97 PyObject* toPython(T)(T value) if(isAssociativeArray!T) {
98     import python.raw: PyDict_New, PyDict_SetItem;
99 
100     auto ret = PyDict_New;
101 
102     foreach(k, v; value) {
103         PyDict_SetItem(ret, k.toPython, v.toPython);
104     }
105 
106     return ret;
107 }
108 
109 PyObject* toPython(T)(T value) if(isTuple!T) {
110     import python.raw: PyTuple_New, PyTuple_SetItem;
111 
112     auto ret = PyTuple_New(value.length);
113 
114     static foreach(i; 0 .. T.length) {
115         PyTuple_SetItem(ret, i, value[i].toPython);
116     }
117 
118     return ret;
119 }
120 
121 
122 PyObject* toPython(T)(T value) if(isSomeChar!T) {
123     return null;  // FIXME
124 }
125 
126 
127 PyObject* toPython(T)(T value) if(isCallable!T && !isUserAggregate!T) {
128     import python.type: pythonCallable;
129     return pythonCallable(value);
130 }