1 module juliad.types; 2 3 import std.traits : EnumMembers; 4 import std.array : array; 5 import std.traits : isSomeString, isArray; 6 import std.format : format; 7 import std.string : toLower; 8 import std.range : ElementEncodingType; 9 import std.typecons : nullable, Nullable; 10 import std.conv : to; 11 import std.stdio; 12 13 import juliad.julia; 14 import juliad.shims; 15 16 struct JuliaToDType(T) { 17 } 18 19 enum JuliaType { 20 @JuliaToDType!void Void, 21 Uniontype, 22 Unionall, 23 Typename, 24 @JuliaToDType!byte Int8, 25 @JuliaToDType!short Int16, 26 @JuliaToDType!int Int32, 27 @JuliaToDType!long Int64, 28 @JuliaToDType!ubyte UInt8, 29 @JuliaToDType!ushort UInt16, 30 @JuliaToDType!uint UInt32, 31 @JuliaToDType!ulong UInt64, 32 @JuliaToDType!bool Bool, 33 Symbol, 34 Ssavalue, 35 Expr, 36 Globalref, 37 Gotonode, 38 Pinode, 39 Phinode, 40 Phicnode, 41 Upsilonnode, 42 Quotenode, 43 Newvarnode, 44 Method_instance, 45 Code_info, 46 Method, 47 Module, 48 Task, 49 @JuliaToDType!string String, 50 @JuliaToDType!float Float16, 51 @JuliaToDType!float Float32, 52 @JuliaToDType!double Float64 53 } 54 55 pragma(msg, __traits(getAttributes, __traits(getMember, JuliaType, "String"))); 56 57 string[] buildTypeStrings() pure @safe { 58 import std.algorithm.iteration : map; 59 60 return [EnumMembers!JuliaType] 61 .map!(t => to!string(t)) 62 .map!(t => t.toLower()) 63 .array; 64 } 65 66 enum string[] typeStrings = buildTypeStrings(); 67 68 private string genJlIsType(string type) { 69 string s = 70 `bool jl_is_%1$s(_jl_value_t* v) { 71 return jl_typeis(v, jl_%1$s_type); 72 }`; 73 return format(s, type); 74 } 75 76 static foreach(t; typeStrings) { 77 mixin(genJlIsType(t)); 78 } 79 80 jl_function_t* jl_get_function(jl_module_t* m, string name) { 81 import std.string : toStringz; 82 return cast(jl_function_t*)jl_get_global(m, jl_symbol(toStringz(name))); 83 } 84 85 Nullable!JuliaType getType(jl_value_t* v) { 86 assert(v !is null, "Passed value must not be null"); 87 enum ems = [EnumMembers!JuliaType]; 88 static foreach(idx, t; typeStrings) {{ 89 enum s = format(`bool i = jl_is_%s(v);`, t); 90 mixin(s); 91 if(i) { 92 return nullable(ems[idx]); 93 } 94 }} 95 return Nullable!(JuliaType).init; 96 } 97 98 //#define jl_astaggedvalue(v) \ 99 // ((jl_taggedvalue_t*)((char*)(v) - sizeof(jl_taggedvalue_t))) 100 101 jl_taggedvalue_t* jl_astaggedvalue(jl_value_t* v) { 102 char* vc = cast(char*)v; 103 char* mtv = vc - jl_taggedvalue_t.sizeof; 104 return cast(jl_taggedvalue_t*)mtv; 105 } 106 107 108 //#define jl_valueof(v) \ 109 // ((jl_value_t*)((char*)(v) + sizeof(jl_taggedvalue_t))) 110 111 jl_value_t* jl_valueof(jl_taggedvalue_t* tv) { 112 char* vc = cast(char*)tv; 113 char* mtv = vc + jl_taggedvalue_t.sizeof; 114 return cast(jl_value_t*)mtv; 115 } 116 117 //#define jl_typeof(v) \ 118 // ((jl_value_t*)(jl_astaggedvalue(v)->header & ~(uintptr_t)15)) 119 120 jl_value_t* jl_typeof(jl_value_t* v) { 121 auto h = jl_astaggedvalue(v).header; 122 uintptr_t ft = ~cast(uintptr_t)15; 123 uintptr_t and = h & ft; 124 void* vp = cast(void*)and; 125 return cast(jl_value_t*)vp; 126 } 127 128 //#define jl_typeis(v,t) (jl_typeof(v)==(jl_value_t*)(t)) 129 bool jl_typeis(jl_value_t* v, jl_datatype_t* dt) { 130 return jl_typeof(v) is cast(jl_value_t*)dt; 131 } 132 133 bool jl_is_nothing(jl_value_t* v) { 134 return v == jl_nothing; 135 } 136 137 JuliaType dTypeToJuliaType(T)() { 138 JuliaType ret; 139 static foreach(em; EnumMembers!JuliaType) {{ 140 enum emStr = to!string(em); 141 alias emMem = __traits(getMember, JuliaType, emStr); 142 static if(__traits(getAttributes, emMem).length > 0) {{ 143 alias uda = __traits(getAttributes, emMem)[0]; 144 static if(is(uda : JuliaToDType!F, F)) { 145 static if(is(T == F)) { 146 ret = em; 147 goto retLabel; 148 } 149 } 150 }} 151 }} 152 retLabel: 153 return ret; 154 } 155 156 unittest { 157 enum JuliaType d = dTypeToJuliaType!(double); 158 static assert(d == JuliaType.Float64, format("%s", d)); 159 } 160 161 unittest { 162 enum JuliaType d = dTypeToJuliaType!(string); 163 static assert(d == JuliaType.String, format("%s", d)); 164 } 165 166 Nullable!T fromJuliaTo(T)(jl_value_t* v) if(!isSomeString!T && isArray!T) { 167 enum size_t dim = dimOfArray!T; 168 169 //if(!jl_is_array_type(v)) { 170 // writeln(__LINE__); 171 // return Nullable!(T).init; 172 //} 173 174 jl_array_t* arr = cast(jl_array_t*)v; 175 176 const size_t arrDim = to!size_t(jl_array_ndims(v)); 177 178 // if(arrDim == dim) { 179 // writeln(__LINE__); 180 // return Nullable!(T).init; 181 // } 182 183 jl_value_t* elType = jl_tparam0(jl_typeof(cast(jl_value_t*)arr)); 184 Nullable!JuliaType elJType = getType(elType); 185 186 // if(elJType.isNull()) { 187 // writeln(__LINE__); 188 // return Nullable!(T).init; 189 // } 190 191 alias RootType = ArrayRootType!T; 192 enum JuliaType tType = dTypeToJuliaType!(RootType); 193 194 // if(elJType.get() != tType) { 195 // writeln(__LINE__); 196 // return Nullable!(T).init; 197 // } 198 199 static if(dim == 1) { 200 void* data = jl_array_data(arr); 201 RootType* tData = cast(RootType*)data; 202 const size_t len1 = jl_array_dim(arr, 1); 203 RootType[] tSlice = tData[0 .. len1]; 204 205 T ret = new T(len1); 206 foreach(idx, val; tSlice) { 207 ret[idx] = val; 208 } 209 writeln(ret); 210 return nullable(ret); 211 } else { 212 static assert(false, T.stringof); 213 } 214 } 215 216 Nullable!T fromJuliaTo(T)(jl_value_t* v) if(!isSomeString!T && !isArray!T) { 217 Nullable!JuliaType jt = getType(v); 218 if(jt.isNull()) { 219 return Nullable!(T).init; 220 } 221 222 enum JuliaType djt = dTypeToJuliaType!(T); 223 return jt.get() == djt 224 ? fromJuliaImpl!(T, djt)(v) 225 : Nullable!(T).init; 226 } 227 228 Nullable!T fromJuliaTo(T)(jl_value_t* v) if(isSomeString!T) { 229 import std.string : fromStringz; 230 231 Nullable!JuliaType jt = getType(v); 232 if(jt.isNull()) { 233 return Nullable!(T).init; 234 } 235 236 enum JuliaType djt = dTypeToJuliaType!(T); 237 return jt.get() == djt 238 ? nullable(to!T(fromStringz(jl_string_ptr(v))).idup) 239 : Nullable!(T).init; 240 } 241 242 private Nullable!T fromJuliaImpl(T, JuliaType jt)(jl_value_t* v) { 243 Nullable!T ret; 244 enum emStr = to!string(jt); 245 alias emMem = __traits(getMember, JuliaType, emStr); 246 static if(__traits(getAttributes, emMem).length > 0) {{ 247 alias uda = __traits(getAttributes, emMem)[0]; 248 static if(is(uda : JuliaToDType!F, F)) {{ 249 static if(is(F == bool)) { 250 enum s = format("ret = nullable(to!bool(jl_unbox_%s(v)));", 251 emStr.toLower()); 252 } else { 253 enum s = format("ret = nullable(jl_unbox_%s(v));", 254 emStr.toLower()); 255 } 256 mixin(s); 257 }} 258 }} 259 return ret; 260 } 261 262 jl_value_t* toJulia(V)(V v) if(!isSomeString!V && !isArray!V) { 263 jl_value_t* ret; 264 enum JuliaType djt = dTypeToJuliaType!(V); 265 enum s = format("ret = jl_box_%s(v);", 266 to!string(djt).toLower()); 267 mixin(s); 268 return ret; 269 } 270 271 jl_value_t* toJulia(V)(V v) if(isSomeString!V) { 272 import std.string : toStringz; 273 jl_value_t* ret; 274 return jl_cstr_to_string(toStringz(to!string(v))); 275 } 276 277 private template dimOfArray(Arr) { 278 static if(isArray!Arr) { 279 enum dimOfArray = 1 + dimOfArray!(ElementEncodingType!Arr); 280 } else { 281 enum dimOfArray = 0; 282 } 283 } 284 285 unittest { 286 static assert(dimOfArray!(int) == 0); 287 static assert(dimOfArray!(int[]) == 1); 288 static assert(dimOfArray!(int[][]) == 2); 289 static assert(dimOfArray!(int[][][][][]) == 5); 290 } 291 292 private template ArrayRootType(Arr) { 293 static if(isArray!Arr) { 294 alias ArrayRootType = ArrayRootType!(ElementEncodingType!Arr); 295 } else { 296 alias ArrayRootType = Arr; 297 } 298 } 299 300 unittest { 301 static assert(is(ArrayRootType!(int) == int)); 302 static assert(is(ArrayRootType!(int[]) == int)); 303 static assert(is(ArrayRootType!(int[][][][][]) == int)); 304 static assert(is(ArrayRootType!(void*[][][][][]) == void*)); 305 } 306 307 jl_value_t* getArrayType(Arr)() { 308 alias RootType = ArrayRootType!Arr; 309 enum size_t dim = dimOfArray!Arr; 310 enum JuliaType jt = dTypeToJuliaType!RootType; 311 enum string jtStr = to!string(jt).toLower(); 312 enum string gen = ` 313 jl_value_t* arrayType = jl_apply_array_type(cast(jl_value_t*)jl_%s_type, %s); 314 `; 315 mixin(format(gen, jtStr, dim)); 316 return arrayType; 317 } 318 319 jl_array_t* toJulia(V)(V v) if(!isSomeString!V && isArray!V) { 320 enum dim = dimOfArray!(V); 321 alias RootType = ArrayRootType!V; 322 323 jl_value_t* arrayType = getArrayType!V; 324 jl_array_t* ret; 325 326 static if(dim == 1) { 327 ret = jl_alloc_array_1d(arrayType, v.length); 328 RootType* data = cast(RootType*)jl_array_data(ret); 329 foreach(idx, val; v) { 330 data[idx] = val; 331 } 332 } else static if(dim == 2) { 333 ret = jl_alloc_array_2d(arrayType, v.length, v[0].length); 334 RootType* data = cast(RootType*)jl_array_data(ret); 335 const size_t dim0 = jl_array_dim(ret, 0); 336 foreach(idx, it; v) { 337 foreach(jdx, jt; it) { 338 data[jdx + dim0 * idx] = jt; 339 } 340 } 341 } else static if(dim == 3) { 342 ret = jl_alloc_array_3d(arrayType, v.length, v[0].length, 343 v[0][0].length); 344 RootType* data = cast(RootType*)jl_array_data(ret); 345 const size_t dim0 = jl_array_dim(ret, 0); 346 const size_t dim1 = jl_array_dim(ret, 1); 347 foreach(idx, it; v) { 348 foreach(jdx, jt; it) { 349 foreach(kdx, kt; jt) { 350 data[(kdx * dim0 * dim1) + (jdx * dim0) + idx] = kt; 351 } 352 } 353 } 354 writeln(data[0 .. jl_array_len(ret)]); 355 } else { 356 static assert(false, V.stringof ~ 357 "can not be converted to julia array, PRs welcome"); 358 } 359 return ret; 360 }