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