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 }