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)(auto ref 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 && isUserAggregate!(PointerTarget!T)) {
63     import python.type: pythonClass;
64     return pythonClass(value);
65 }
66 
67 
68 PyObject* toPython(T)(T value) if(is(Unqual!T == DateTime)) {
69     import python.raw: pyDateTimeFromDateAndTime;
70     return pyDateTimeFromDateAndTime(value.year, value.month, value.day,
71                                      value.hour, value.minute, value.second);
72 }
73 
74 
75 PyObject* toPython(T)(T value) if(is(Unqual!T == Date)) {
76     import python.raw: pyDateFromDate;
77     return pyDateFromDate(value.year, value.month, value.day);
78 }
79 
80 
81 PyObject* toPython(T)(T value) if(isSomeString!T) {
82     import python.raw: pyUnicodeFromStringAndSize;
83     import std.conv: to;
84     auto str = value.to!string;
85     return pyUnicodeFromStringAndSize(str.ptr, str.length);
86 }
87 
88 
89 PyObject* toPython(T)(T value) if(is(Unqual!T == bool)) {
90     import python.raw: PyBool_FromLong;
91     return PyBool_FromLong(value);
92 }
93 
94 
95 PyObject* toPython(T)(T value) if(isStaticArray!T) {
96     return toPython(value[]);
97 }
98 
99 
100 PyObject* toPython(T)(T value) if(isAssociativeArray!T) {
101     import python.raw: PyDict_New, PyDict_SetItem;
102 
103     auto ret = PyDict_New;
104 
105     foreach(k, v; value) {
106         PyDict_SetItem(ret, k.toPython, v.toPython);
107     }
108 
109     return ret;
110 }
111 
112 PyObject* toPython(T)(T value) if(isTuple!T) {
113     import python.raw: PyTuple_New, PyTuple_SetItem;
114 
115     auto ret = PyTuple_New(value.length);
116 
117     static foreach(i; 0 .. T.length) {
118         PyTuple_SetItem(ret, i, value[i].toPython);
119     }
120 
121     return ret;
122 }
123 
124 
125 PyObject* toPython(T)(T value) if(isSomeChar!T) {
126     return null;  // FIXME
127 }
128 
129 
130 PyObject* toPython(T)(T value) if(isCallable!T && !isUserAggregate!T) {
131     import python.type: pythonCallable;
132     return pythonCallable(value);
133 }