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,
8     isCallable, isSomeString;
9 import std.range: isInputRange;
10 import std.datetime: Date, DateTime;
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 && !isSomeString!T && !isStaticArray!T) {
26     import python.raw: PyList_New, PyList_SetItem, PyList_Append;
27     import std.range: isForwardRange, enumerate;
28 
29     static if(__traits(hasMember, T, "length")) {
30         const length = value.length;
31         enum append = false;
32     } else static if(isForwardRange!T){
33         import std.range: walkLength;
34         import std.array: save;
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(isSomeString!T) {
81     import python.raw: pyUnicodeFromStringAndSize;
82     import std.conv: to;
83     auto str = value.to!string;
84     return pyUnicodeFromStringAndSize(str.ptr, str.length);
85 }
86 
87 
88 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) {
89     import python.raw: PyBool_FromLong;
90     return PyBool_FromLong(value);
91 }
92 
93 
94 PyObject* toPython(T)(T value) if(isStaticArray!T) {
95     return toPython(value[]);
96 }
97 
98 
99 PyObject* toPython(T)(T value) if(isAssociativeArray!T) {
100     import python.raw: PyDict_New, PyDict_SetItem;
101 
102     auto ret = PyDict_New;
103 
104     foreach(k, v; value) {
105         PyDict_SetItem(ret, k.toPython, v.toPython);
106     }
107 
108     return ret;
109 }
110 
111 PyObject* toPython(T)(T value) if(isTuple!T) {
112     import python.raw: PyTuple_New, PyTuple_SetItem;
113 
114     auto ret = PyTuple_New(value.length);
115 
116     static foreach(i; 0 .. T.length) {
117         PyTuple_SetItem(ret, i, value[i].toPython);
118     }
119 
120     return ret;
121 }
122 
123 
124 PyObject* toPython(T)(T value) if(isSomeChar!T) {
125     return null;  // FIXME
126 }
127 
128 
129 PyObject* toPython(T)(T value) if(isCallable!T && !isUserAggregate!T) {
130     import python.type: pythonCallable;
131     return pythonCallable(value);
132 }