Changeset 52

Show
Ignore:
Timestamp:
12/10/06 18:02:59 (2 years ago)
Author:
KirkMcDonald
Message:

Struct wrapping; static member function wrapping; various back-end type-exposing improvements

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/dcompiler.py

    r51 r52  
    3737    'pyd.d', 
    3838    'pydobject.d', 
     39    'struct_wrap.d', 
    3940] 
    4041 
  • trunk/examples/testdll/test.py

    r37 r52  
    3737print 
    3838 
     39S = testdll.S 
     40s = S() 
     41print "s.s = 'hello'" 
     42s.s = 'hello' 
     43print "s.s" 
     44print s.s 
     45print "s.write_s()" 
     46s.write_s() 
     47 
     48print 
     49 
    3950print '--------' 
    4051print 'SUCCESS' 
  • trunk/examples/testdll/testdll.d

    r45 r52  
    110110} 
    111111 
     112struct S { 
     113    int i; 
     114    char[] s; 
     115    void write_s() { 
     116        writefln(s); 
     117    } 
     118} 
     119 
    112120Foo spam(Foo f) { 
    113121    f.foo(); 
     
    142150    f.prop!(Foo.i); 
    143151    finalize_class(f); 
     152 
     153    wrapped_struct!(S) s; 
     154    s.def!(S.write_s); 
     155    const size_t i = S.i.offsetof; 
     156    const size_t t = S.s.offsetof; 
     157    s.member!(int, i, "i"); 
     158    s.member!(char[], t, "s"); 
     159    finalize_struct(s); 
    144160} 
    145161 
  • trunk/html_doc/basics.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
  • trunk/html_doc/celerid.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
  • trunk/html_doc/class_wrapping.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="navcur" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
     
    4041<dd>This wraps a method of the class. It functions exactly like the <code>def</code> function used to <a href="func_wrapping.html">wrap regular functions</a>, with one very important difference: There is no support for default arguments. (This is a side-effect of the fact that you cannot call an alias of a method in D, and delegates do not understand default arguments.)</dd> 
    4142 
     43<dt><code>static void static_def(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), <span class="t_arg">fn_t</span> = typeof(&amp;fn), uint <span class="t_arg">MIN_ARGS</span> = minArgs!(fn)) ();</code></dt> 
     44<dd>This wraps a static member function of the class. It also functions exactly like the <code>def</code> function used to wrap regular functions, and even includes support for default arguments.</dd> 
     45 
    4246<dt><code>static void prop(alias <span class="t_arg">fn</span>, char[] <span class="t_arg">name</span> = symbolnameof!(fn), bool <span class="t_arg">RO</span> = false) ();</code></dt> 
    4347<dd>This wraps a property. See the examples below for more details. 
     
    4549    <li><span class="t_arg">fn</span> is the name of the property. <code>prop</code> will automatically attempt to wrap both the "get" and "set" forms of the property, unless <span class="t_arg">RO</span> is specified.</li> 
    4650    <li><span class="t_arg">name</span> is the name of the property as it will appear in Python. As with <code>def</code>, <code>prop</code> will attempt to derive this automatically.</li> 
    47     <li><span class="t_arg">RO</span> specifies whether this is a <i>read-only</i> property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. (This is a little hackish, and I will probably try to make this detection more automatic in the future. It also means it cannot support a property that only has a "set" form.)</li> 
     51    <li><span class="t_arg">RO</span> specifies whether this is a <i>read-only</i> property. If true, it will only wrap the "get" form of the property. If false, it will wrap both the "get" and "set" forms. <i>(This is a little hackish, and I will probably try to make this detection more automatic in the future. It also means it cannot support a property that only has a "set" form.)</i></li> 
    4852    </ul> 
    4953</dd> 
     
    8690 
    8791<p>Missing from this list are <code>opUShr</code> and <code>opUShrAssign</code>. Python does not have an unsigned right-shift operator, so these operator overloads are not supported. (You may still wrap them with a normal method using <code>wrapped_class.def</code>, of course.) Also missing from the list is <code>opApplyReverse</code>. This must be wrapped explicitly with <code>wrapped_class.alt_iter</code>.</p> 
     92 
     93<p>Also missing from the list is <code>opAssign</code>. Python has strict reference semantics for its objects, so overloading the assignment operator is not possible. You must explicitly wrap <code>opAssign</code> with a regular method.</p> 
    8894 
    8995<p>Additionally, if a class provides a <code>length</code> property, Pyd will automatically make it available via Python's built-in function <code>len</code> and the special <code>__len__</code> method. You may still wrap it with <code>prop</code> or <code>def</code> if you wish it to be available as a normal property or method.</p> 
  • trunk/html_doc/conversion.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
     
    4041<tr><td>idouble, cdouble</td>                   <td>complex</td>    </tr> 
    4142<tr><td>char[] (as ASCII string)</td>           <td>str</td>        </tr> 
    42 <tr><td>wchar[] (as UCS2 string)</td>           <td>unicode</td>    </tr
     43<!--<tr><td>wchar[] (as UCS2 string)</td>           <td>unicode</td>    </tr>--
    4344<tr><td>dynamic array</td>                      <td>list</td>       </tr> 
    4445<tr><td>associative array</td>                  <td>dict</td>       </tr> 
    4546<tr><td>delegate or function pointer</td>       <td>A callable object</td></tr> 
    4647<tr><td><a href="class_wrapping.html">A wrapped class</a></td> <td>The wrapped type</td></tr> 
     48<tr><td><a href="struct_wrapping.html">A wrapped struct</a></td> <td>The wrapped type</td></tr> 
     49<tr><td>Pointer-to-wrapped-struct</td>          <td>The wrapped type</td></tr> 
    4750<tr><td><a href="pydobject.html">PydObject</a></td> <td>The wrapped object's type</td></tr> 
    4851<tr><td>PyObject*</td>                          <td>The object's type</td></tr> 
     
    6164<tr><td>Any type</td>       <td>PyObject*</td>                          </tr> 
    6265<tr><td>Any type</td>       <td><a href="pydobject.html">PydObject</a></td></tr> 
     66<tr><td><a href="struct_wrapping.html">Wrapped struct</a></td> <td>Wrapped struct</td></tr> 
     67<tr><td><a href="struct_wrapping.html">Wrapped struct</a></td> <td>Pointer to wrapped struct</td></tr> 
    6368<tr><td><a href="class_wrapping.html">Wrapped class</a></td> <td>Wrapped class</td></tr> 
    6469<tr><td>Any callable</td>   <td>delegate</td>                           </tr> 
  • trunk/html_doc/credits.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
  • trunk/html_doc/except_wrapping.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="navcur" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
  • trunk/html_doc/func_wrapping.html

    r49 r52  
    1717<a class="navcur" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
     
    3637    </ul> 
    3738 
    38 <p>All calls to <code>def</code> must occur <em>before</em> calling <code>module_init</code>. Any function whose return type and arguments are <a href="conversion.html">convertable</a> can be wrapped by <code>def</code>. <code>def</code> can only wrap functions with <code>in</code> arguments (not <code>out</code> or <code>inout</code>). <code>def</code> also provides support for wrapping overloaded functions as well as functions with default arguments. Here are some examples:</p> 
     39<p>All calls to <code>def</code> must occur <em>before</em> calling <code>module_init</code>. Any function whose return type and arguments are <a href="conversion.html">convertible</a> can be wrapped by <code>def</code>. <code>def</code> can only wrap functions with <code>in</code> arguments (not <code>out</code> or <code>inout</code> or <code>lazy</code>). <code>def</code> also provides support for wrapping overloaded functions as well as functions with default arguments. Here are some examples:</p> 
    3940 
    4041<pre class="code"><span class="keyword">import</span> pyd.pyd; 
  • trunk/html_doc/index.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
  • trunk/html_doc/install.html

    r51 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="nav" href="pydobject.html">PydObject</a><br /> 
  • trunk/html_doc/pydobject.html

    r49 r52  
    1717<a class="nav" href="func_wrapping.html">Function wrapping</a><br /> 
    1818<a class="nav" href="class_wrapping.html">Class wrapping</a><br /> 
     19<a class="nav" href="struct_wrapping.html">Struct wrapping</a><br /> 
    1920<a class="nav" href="except_wrapping.html">Exception wrapping</a><br /> 
    2021<a class="navcur" href="pydobject.html">PydObject</a><br /> 
  • trunk/infrastructure/pyd/class_wrap.d

    r51 r52  
    111111} 
    112112 
    113 // The set of all instances of this class that are passed into Python. Keeping 
    114 // references here in D is needed to keep the GC happy. The integer value is 
    115 // used to make this a sort of poor man's multiset. 
    116 template wrap_class_instances(T) { 
    117     int[T] wrap_class_instances; 
    118 
     113// A mapping of all objects referenced by the GC that are being held by Python. 
     114PyObject*[void*] wrapped_gc_objects; 
    119115 
    120116/** 
     
    165161    extern(C) 
    166162    void wrapped_dealloc(PyObject* self) { 
    167         //exception_catcher(delegate PyObject*() { 
    168         try { 
     163        exception_catcher(delegate void() { 
    169164            WrapPyObject_SetObj(self, null); 
    170         } catch { } 
    171         self.ob_type.tp_free(self); 
    172         return null; 
    173         //}); 
     165            self.ob_type.tp_free(self); 
     166        }); 
    174167    } 
    175168} 
     
    245238 * wrapping the specific parts of the class. 
    246239 */ 
    247 template wrapped_class(T, char[] classname = symbolnameof!(T)) { 
    248     pragma(msg, "wrapped_class: " ~ classname); 
    249     struct wrapped_class { 
    250         static const char[] _name = classname; 
    251         T t = null; 
    252         /** 
    253          * Wraps a member function of the class. 
    254          * 
    255          * Params: 
    256          * name = The name of the function as it will appear in Python. 
    257          * fn = The member function to wrap. 
    258          * MIN_ARGS = The minimum number of arguments this function can accept. 
    259          * fn_t = The type of the function. It is only useful to specify this 
    260          *        if more than one function has the same name as this one. 
    261          */ 
    262         template def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) { 
    263             pragma(msg, "class.def: " ~ name); 
    264             static void def() { 
    265                 static PyMethodDef empty = { null, null, 0, null }; 
    266                 alias wrapped_method_list!(T) list; 
    267                 list[length-1].ml_name = name ~ \0; 
    268                 list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; 
    269                 list[length-1].ml_flags = METH_VARARGS; 
    270                 list[length-1].ml_doc = ""; 
    271                 list ~= empty; 
    272                 // It's possible that appending the empty item invalidated the 
    273                 // pointer in the type struct, so we renew it here. 
    274                 wrapped_class_type!(T).tp_methods = list; 
    275             } 
     240struct wrapped_class(T, char[] classname = symbolnameof!(T)) { 
     241    static if (is(T == class)) pragma(msg, "wrapped_class: " ~ classname); 
     242    static const char[] _name = classname; 
     243    alias T wrapped_type; 
     244    /** 
     245     * Wraps a member function of the class. 
     246     * 
     247     * Params: 
     248     * fn = The member function to wrap. 
     249     * name = The name of the function as it will appear in Python. 
     250     * fn_t = The type of the function. It is only useful to specify this 
     251     *        if more than one function has the same name as this one. 
     252     */ 
     253    static void def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn)) () { 
     254        pragma(msg, "class.def: " ~ name); 
     255        static PyMethodDef empty = { null, null, 0, null }; 
     256        alias wrapped_method_list!(T) list; 
     257        list[length-1].ml_name = (name ~ \0).ptr; 
     258        list[length-1].ml_meth = &method_wrap!(T, fn, fn_t).func; 
     259        list[length-1].ml_flags = METH_VARARGS; 
     260        list[length-1].ml_doc = ""; 
     261        list ~= empty; 
     262        // It's possible that appending the empty item invalidated the 
     263        // pointer in the type struct, so we renew it here. 
     264        wrapped_class_type!(T).tp_methods = list; 
     265    } 
     266 
     267    /** 
     268     * Wraps a static member function of the class. Identical to pyd.def.def 
     269     */ 
     270    static void static_def(alias fn, char[] name = symbolnameof!(fn), fn_t=typeof(&fn), uint MIN_ARGS=minArgs!(fn)) () { 
     271        pragma(msg, "class.static_def: " ~ name); 
     272        static PyMethodDef empty = { null, null, 0, null }; 
     273        alias wrapped_method_list!(T) list; 
     274        list[length-1].ml_name = (name ~ \0).ptr; 
     275        list[length-1].ml_meth = &function_wrap!(fn, MIN_ARGS, fn_t).func; 
     276        list[length-1].ml_flags = METH_VARARGS | METH_STATIC; 
     277        list[length-1].ml_doc = ""; 
     278        list ~= empty; 
     279        wrapped_class_type!(T).tp_methods = list; 
     280    } 
     281 
     282    /** 
     283     * Wraps a property of the class. 
     284     * 
     285     * Params: 
     286     * fn = The property to wrap. 
     287     * name = The name of the property as it will appear in Python. 
     288     * RO = Whether this is a read-only property. 
     289     */ 
     290    static void prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) () { 
     291        pragma(msg, "class.prop: " ~ name); 
     292        static PyGetSetDef empty = { null, null, null, null, null }; 
     293        wrapped_prop_list!(T)[length-1].name = name ~ \0; 
     294        wrapped_prop_list!(T)[length-1].get = 
     295            &wrapped_get!(T, fn).func; 
     296        static if (!RO) { 
     297            wrapped_prop_list!(T)[length-1].set = 
     298                &wrapped_set!(T, fn).func; 
    276299        } 
    277  
    278         /** 
    279          * Wraps a property of the class. 
    280          * 
    281          * Params: 
    282          * name = The name of the property as it will appear in Python. 
    283          * fn = The property to wrap. 
    284          * RO = Whether this is a read-only property. 
    285          */ 
    286         template prop(alias fn, char[] name = symbolnameof!(fn), bool RO=false) { 
    287             pragma(msg, "class.prop: " ~ name); 
    288             static void prop() { 
    289                 static PyGetSetDef empty = { null, null, null, null, null }; 
    290                 wrapped_prop_list!(T)[length-1].name = name ~ \0; 
    291                 wrapped_prop_list!(T)[length-1].get = 
    292                     &wrapped_get!(T, fn).func; 
    293                 static if (!RO) { 
    294                     wrapped_prop_list!(T)[length-1].set = 
    295                         &wrapped_set!(T, fn).func; 
    296                 } 
    297                 wrapped_prop_list!(T)[length-1].doc = ""; 
    298                 wrapped_prop_list!(T)[length-1].closure = null; 
    299                 wrapped_prop_list!(T) ~= empty; 
    300                 // It's possible that appending the empty item invalidated the 
    301                 // pointer in the type struct, so we renew it here. 
    302                 wrapped_class_type!(T).tp_getset = 
    303                     wrapped_prop_list!(T); 
    304             } 
    305         } 
    306  
    307         /** 
    308          * Wraps the constructors of the class. 
    309          * 
    310          * This template takes a series of specializations of the ctor template 
    311          * (see ctor_wrap.d), each of which describes a different constructor 
    312          * that the class supports. The default constructor need not be 
    313          * specified, and will always be available if the class supports it. 
    314          * 
    315          * Bugs: 
    316          * This currently does not support having multiple constructors with 
    317          * the same number of arguments. 
    318          */ 
    319         static void init(C ...) () { 
    320             wrapped_class_type!(T).tp_init = 
    321                 &wrapped_ctors!(T, C).init_func; 
    322         } 
    323  
    324         // Iteration wrapping support requires StackThreads 
    325         version(Pyd_with_StackThreads) { 
    326  
    327         /** 
    328          * Allows selection of alternate opApply overloads. iter_t should be 
    329          * the type of the delegate in the opApply function that the user wants 
    330          * to be the default. 
    331          */ 
    332         static void iter(iter_t) () { 
    333             PydStackContext_Ready(); 
    334             wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; 
    335         } 
    336  
    337         /** 
    338          * Exposes alternate iteration methods, originally intended for use with 
    339          * D's delegate-as-iterator features, as methods returning a Python 
    340          * iterator. 
    341          */ 
    342         static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) () { 
    343             static PyMethodDef empty = { null, null, 0, null }; 
    344             alias wrapped_method_list!(T) list; 
    345             PydStackContext_Ready(); 
    346             list[length-1].ml_name = name ~ \0; 
    347             list[length-1].ml_meth = cast(PyCFunction)&wrapped_iter!(T, fn, int function(iter_t)).iter; 
    348             list[length-1].ml_flags = METH_VARARGS; 
    349             list[length-1].ml_doc = ""; 
    350             list ~= empty; 
    351             // It's possible that appending the empty item invalidated the 
    352             // pointer in the type struct, so we renew it here. 
    353             wrapped_class_type!(T).tp_methods = list; 
    354         } 
    355  
    356         } /*Pyd_with_StackThreads*/ 
    357     } 
     300        wrapped_prop_list!(T)[length-1].doc = ""; 
     301        wrapped_prop_list!(T)[length-1].closure = null; 
     302        wrapped_prop_list!(T) ~= empty; 
     303        // It's possible that appending the empty item invalidated the 
     304        // pointer in the type struct, so we renew it here. 
     305        wrapped_class_type!(T).tp_getset = 
     306            wrapped_prop_list!(T); 
     307    } 
     308 
     309    /** 
     310     * Wraps the constructors of the class. 
     311     * 
     312     * This template takes a series of specializations of the ctor template 
     313     * (see ctor_wrap.d), each of which describes a different constructor 
     314     * that the class supports. The default constructor need not be 
     315     * specified, and will always be available if the class supports it. 
     316     * 
     317     * Bugs: 
     318     * This currently does not support having multiple constructors with 
     319     * the same number of arguments. 
     320     */ 
     321    static void init(C ...) () { 
     322        wrapped_class_type!(T).tp_init = 
     323            &wrapped_ctors!(T, C).init_func; 
     324    } 
     325 
     326    // Iteration wrapping support requires StackThreads 
     327    version(Pyd_with_StackThreads) { 
     328 
     329    /** 
     330     * Allows selection of alternate opApply overloads. iter_t should be 
     331     * the type of the delegate in the opApply function that the user wants 
     332     * to be the default. 
     333     */ 
     334    static void iter(iter_t) () { 
     335        PydStackContext_Ready(); 
     336        wrapped_class_type!(T).tp_iter = &wrapped_iter!(T, T.opApply, int function(iter_t)).iter; 
     337    } 
     338 
     339    /** 
     340     * Exposes alternate iteration methods, originally intended for use with 
     341     * D's delegate-as-iterator features, as methods returning a Python 
     342     * iterator. 
     343     */ 
     344    static void alt_iter(alias fn, char[] name = symbolnameof!(fn), iter_t = funcDelegInfoT!(typeof(&fn)).Meta.ArgType!(0)) () { 
     345        static PyMethodDef empty = { null, null, 0, null }; 
     346        alias wrapped_method_list!(T) list; 
     347        PydStackContext_Ready(); 
     348        list[length-1].ml_name = name ~ \0; 
     349        list[length-1].ml_meth = cast(PyCFunction)&wrapped_iter!(T, fn, int function(iter_t)).iter; 
     350        list[length-1].ml_flags = METH_VARARGS; 
     351        list[length-1].ml_doc = ""; 
     352        list ~= empty; 
     353        // It's possible that appending the empty item invalidated the 
     354        // pointer in the type struct, so we renew it here. 
     355        wrapped_class_type!(T).tp_methods = list; 
     356    } 
     357 
     358    } /*Pyd_with_StackThreads*/ 
    358359} 
    359360 
     
    363364 */ 
    364365void finalize_class(CLS) (CLS cls, char[] modulename="") { 
    365     alias typeof(cls.t) T; 
     366    alias CLS.wrapped_type T; 
    366367    alias wrapped_class_type!(T) type; 
    367368    const char[] name = CLS._name; 
    368     pragma(msg, "finalize_class: " ~ name); 
     369    static if (is(T == class)) { 
     370        pragma(msg, "finalize_class: " ~ name); 
     371    } else { 
     372        pragma(msg, "finalize_struct: " ~ name); 
     373    } 
     374    pragma(msg, "finalize_class, T is " ~ prettytypeof!(T)); 
    369375     
    370     assert(Pyd_Module_p !is null, "Must initialize module before wrapping classes."); 
     376    assert(Pyd_Module_p(modulename) !is null, "Must initialize module before wrapping classes."); 
    371377    char[] module_name = toString(PyModule_GetName(Pyd_Module_p(modulename))); 
    372378    // Fill in missing values 
    373379    type.ob_type      = PyType_Type_p(); 
    374     //type.tp_new       = &(wrapped_methods!(T).wrapped_new); 
    375     //type.tp_dealloc   = &(wrapped_methods!(T).wrapped_dealloc); 
    376380    type.tp_basicsize = (wrapped_class_object!(T)).sizeof; 
    377381    type.tp_doc       = name ~ " objects" ~ \0; 
    378382    type.tp_flags     = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 
    379     //type.tp_new       = &PyType_GenericNew; 
    380383    //type.tp_repr      = &wrapped_repr!(T).repr; 
    381384    type.tp_methods   = wrapped_method_list!(T); 
     
    415418 
    416419    // If a ctor wasn't supplied, try the default. 
    417     //if (type.tp_init is null) { 
    418     //    type.tp_init = &wrapped_init!(T).init; 
    419     //} 
     420    if (type.tp_init is null) { 
     421        static if (is(T == class)) { 
     422            type.tp_init = &wrapped_init!(T).init; 
     423        } else { 
     424            type.tp_init = &wrapped_struct_init!(T).init; 
     425        } 
     426    } 
    420427    if (PyType_Ready(&type) < 0) { 
    421428        // XXX: This will probably crash the interpreter, as it isn't normally 
     
    432439// PYD API FUNCTIONS // 
    433440/////////////////////// 
     441 
     442private union aa_reference(T) { 
     443    T aa; 
     444    void* ptr; 
     445} 
     446 
     447private void* get_voidptr(T)(T t) { 
     448    static if (isAA!(T)) { 
     449        aa_reference!(T) ref; 
     450        ref.aa = t; 
     451        return ref.ptr; 
     452    } else { 
     453        return cast(void*)t; 
     454    } 
     455} 
    434456 
    435457/** 
     
    440462    alias wrapped_class_type!(T) type; 
    441463    if (is_wrapped!(T)) { 
    442         // Allocate the object 
    443         wrapped_object* obj = 
    444             cast(wrapped_object*)type.tp_new(&type, null, null); 
     464        // If this object is already wrapped, get the existing object. 
     465        PyObject** obj_p = get_voidptr(t) in wrapped_gc_objects; 
     466        if (obj_p) return *obj_p; 
     467        // Otherwise, allocate a new object 
     468        PyObject* obj = type.tp_new(&type, null, null); 
    445469        // Set the contained instance 
    446470        WrapPyObject_SetObj(obj, t); 
    447         return cast(PyObject*)obj; 
     471        return obj; 
    448472    } else { 
    449473        PyErr_SetString(PyExc_RuntimeError, "Type " ~ typeid(T).toString() ~ " is not wrapped by Pyd."); 
     
    460484    wrapped_object* self = cast(wrapped_object*)_self; 
    461485    if (!is_wrapped!(T) || self is null || !PyObject_TypeCheck(_self, &type)) { 
    462         // Throw something 
     486        throw new Exception("Error extracting D object from Python object..."); 
    463487    } 
    464488    return self.d_obj; 
     
    471495    alias wrapped_class_object!(T) obj; 
    472496    obj* self = cast(obj*)_self; 
     497    if (get_voidptr(t) == get_voidptr(self.d_obj)) 
     498        return; 
    473499    // Clean up the old object, if there is one 
    474500    if (self.d_obj !is null) { 
    475         wrap_class_instances!(T)[self.d_obj]--; 
    476         if (wrap_class_instances!(T)[self.d_obj] <= 0) { 
    477             wrap_class_instances!(T).remove(self.d_obj); 
    478         } 
     501        wrapped_gc_objects.remove(get_voidptr(self.d_obj)); 
    479502    } 
    480503    self.d_obj = t; 
    481504    // Handle the new one, if there is one 
    482     if (t !is null) wrap_class_instances!(T)[t]++
    483 } 
    484  
     505    if (t !is null) wrapped_gc_objects[get_voidptr(self.d_obj)] = _self
     506} 
     507 
  • trunk/infrastructure/pyd/ctor_wrap.d

    r50 r52  
    2828private import pyd.make_object; 
    2929 
     30private import meta.Nameof; 
     31 
    3032private import std.traits; 
    3133 
     
    3638// The default __init__ method calls the class's zero-argument constructor. 
    3739template wrapped_init(T) { 
    38     alias wrapped_class_object!(T) wrap_object; 
    3940    extern(C) 
    4041    int init(PyObject* self, PyObject* args, PyObject* kwds) { 
    4142        return exception_catcher({ 
    4243            WrapPyObject_SetObj(self, new T); 
     44            return 0; 
     45        }); 
     46    } 
     47} 
     48 
     49// The __init__ slot for wrapped structs. T is of the type of a pointer to the 
     50// struct. 
     51template wrapped_struct_init(T) { 
     52    extern(C) 
     53    int init(PyObject* self, PyObject* args, PyObject* kwds) { 
     54        return exception_catcher({ 
     55            static if (is(T S : S*)) { 
     56                pragma(msg, "wrapped_struct_init, S is " ~ prettynameof!(S)); 
     57                T t = new S; 
     58                WrapPyObject_SetObj(self, t); 
     59            } 
    4360            return 0; 
    4461        }); 
  • trunk/infrastructure/pyd/def.d

    r51 r52  
    3737 
    3838PyObject* Pyd_Module_p(char[] modulename="") { 
    39     return pyd_modules[modulename]; 
     39    PyObject** m = modulename in pyd_modules; 
     40    if (m is null) return null; 
     41    else return *m; 
    4042} 
    4143 
  • trunk/infrastructure/pyd/func_wrap.d

    r50 r52  
    3939 
    4040// Builds a callable Python object from a delegate or function pointer. 
    41 PyObject* PydFunc_FromDelegate(T) (T dg) { 
     41void PydWrappedFunc_Ready(T)() { 
    4242    alias wrapped_class_type!(T) type; 
    4343    alias wrapped_class_object!(T) obj; 
    4444    if (!is_wrapped!(T)) { 
    4545        type.ob_type = PyType_Type_p; 
    46         type.tp_new       = &wrapped_methods!(T).wrapped_new; 
    47         type.tp_dealloc   = &wrapped_methods!(T).wrapped_dealloc; 
    4846        type.tp_basicsize = obj.sizeof; 
    4947        type.tp_name = "PydFunc"; 
     48 
    5049        type.tp_call = &wrapped_func_call!(T).call; 
     50 
    5151        PyType_Ready(&type); 
    5252        is_wrapped!(T) = true; 
    5353        wrapped_classes[typeid(T)] = true; 
    5454    } 
    55     obj* func = cast(obj*)type.tp_new(&type, null, null); 
    56     func.d_obj = dg; 
    57     wrap_class_instances!(T)[dg]++; 
    58     return cast(PyObject*)func; 
    5955} 
    6056 
  • trunk/infrastructure/pyd/iteration.d

    r51 r52  
    6060        // enclosing function's stack frame. 
    6161        StackContext.yield(); 
    62         PyObject* temp; 
    6362 
    6463        t(delegate int(inout Info i) { 
     
    116115    if (!is_wrapped!(StackContext)) { 
    117116        type.ob_type = PyType_Type_p; 
    118         //type.tp_new       = &wrapped_methods!(StackContext).wrapped_new; 
    119         //type.tp_dealloc   = &wrapped_methods!(StackContext).wrapped_dealloc; 
    120117        type.tp_basicsize = PydSC_object.sizeof; 
    121118        type.tp_flags     = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 
    122         //type.tp_doc = ""; 
    123119        type.tp_name = "PydOpApplyWrapper"; 
    124120 
     
    127123 
    128124        PyType_Ready(&type); 
    129  
    130         // Mark the class as ready 
    131125        is_wrapped!(StackContext) = true; 
    132126        wrapped_classes[typeid(StackContext)] = true; 
  • trunk/infrastructure/pyd/make_object.d

    r51 r52  
    3838 
    3939import std.string; 
     40//import std.stdio; 
    4041 
    4142import pyd.pydobject; 
     
    4445import pyd.exception; 
    4546 
    46 private template isArray(T) { 
     47package template isArray(T) { 
    4748    const bool isArray = is(typeof(T.init[0])[] == T); 
    4849} 
     
    5556// say "!is(typeof(T.init) == T)"; however, this template has the advantage of 
    5657// being easily fixable should this behavior for static arrays change. 
    57 private template isStaticArray(T) { 
     58package template isStaticArray(T) { 
    5859    const bool isStaticArray = is(typeof(T.init)[(T).sizeof / typeof(T.init).sizeof] == T); 
    5960} 
    6061 
    61 private template isAA(T) { 
     62package template isAA(T) { 
    6263    const bool isAA = is(typeof(T.init.values[0])[typeof(T.init.keys[0])] == T); 
    6364} 
     
    8990        return PyComplex_FromDoubles(t.re, t.im); 
    9091    } else static if (is(T : char[])) { 
    91         return PyString_FromString(t ~ \0); 
     92        return PyString_FromString((t ~ \0).ptr); 
    9293    } else static if (is(T : wchar[])) { 
    9394        return PyUnicode_FromWideChar(t, t.length); 
     
    132133        return dict; 
    133134    } else static if (is(T == delegate) || is(T == function)) { 
    134         return PydFunc_FromDelegate!(T)(t); 
     135        PydWrappedFunc_Ready!(T)(); 
     136        return WrapPyObject_FromObject(t); 
    135137    } else static if (is(T : PydObject)) { 
    136138        PyObject* temp = t.ptr(); 
     
    139141    // Convert wrapped type of a PyObject* 
    140142    } else static if (is(T == class)) { 
    141         // Put only if it actually is a wrapped type. :-) 
     143        // But only if it actually is a wrapped type. :-) 
    142144        if (is_wrapped!(T)) { 
    143145            return WrapPyObject_FromObject(t); 
    144146        } 
    145147        // If it's not a wrapped type, fall through to the exception. 
     148    // If converting a struct by value, create a copy and wrap that 
     149    } else static if (is(T == struct)) { 
     150        if (is_wrapped!(T*)) { 
     151            T* temp = new T; 
     152            *temp = t; 
     153            return WrapPyObject_FromObject(temp); 
     154        } 
     155    // If converting a struct by reference, wrap the thing directly 
     156    } else static if (is(typeof(*t) == struct)) { 
     157        if (is_wrapped!(T)) { 
     158            return WrapPyObject_FromObject(t); 
     159        } 
    146160    // The function expects to be passed a borrowed reference and return an 
    147161    // owned reference. Thus, if passed a PyObject*, this will increment the 
     
    227241        return Py_None; 
    228242    } else static if (is(T == class)) { 
    229         static if (is(T == Object)) { 
    230             pragma(msg, "d_type: T is Object"); 
    231         } 
    232243        // We can only convert to a class if it has been wrapped, and of course 
    233244        // we can only convert the object if it is the wrapped type. 
     
    237248        // Otherwise, throw up an exception. 
    238249        could_not_convert!(T)(o); 
     250    } else static if (is(T == struct)) { // struct by value 
     251        if (is_wrapped!(T*) && PyObject_TypeCheck(o, &wrapped_class_type!(T*))) {  
     252            return *WrapPyObject_AsObject!(T*)(o); 
     253        } else could_not_convert!(T)(o); 
     254    } else static if (is(typeof(*(T.init)) == struct)) { // pointer to struct    
     255        if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 
     256            return WrapPyObject_AsObject!(T)(o); 
     257        } else could_not_convert!(T)(o); 
    239258    } else static if (is(T == delegate)) { 
    240         if (PyCallable_Check(o)) { 
     259        // Get the original wrapped delegate out if this is a wrapped delegate 
     260        if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 
     261            return WrapPyObject_AsObject!(T)(o); 
     262        // Otherwise, wrap the PyCallable with a delegate 
     263        } else if (PyCallable_Check(o)) { 
    241264            return PydCallable_AsDelegate!(T)(o); 
     265        } else could_not_convert!(T)(o); 
     266    } else static if (is(T == function)) { 
     267        // We can only make it a function pointer if we originally wrapped a 
     268        // function pointer. 
     269        if (is_wrapped!(T) && PyObject_TypeCheck(o, &wrapped_class_type!(T))) { 
     270            return WrapPyObject_AsObject!(T)(o); 
    242271        } else could_not_convert!(T)(o); 
    243272    /+ 
     
    249278    +/ 
    250279    } else static if (is(char[] : T)) { 
     280        //writefln("d_type!(char[])"); 
    251281        char* result; 
    252282        PyObject* repr; 
     
    262292        } 
    263293        if (result is null) handle_exception(); 
    264         return .toString(result); 
     294        //char[] s = .toString(result); 
     295        //writefln("result is |%s|", result); 
     296        //writefln("s is      |%s|", s); 
     297        return .toString(result).dup; 
    265298    } else static if (is(cdouble : T)) { 
    266299        double real_ = PyComplex_RealAsDouble(o); 
  • trunk/infrastructure/pyd/pyd.d

    r51 r52  
    3434    import pyd.make_object; 
    3535    import pyd.pydobject; 
     36    import pyd.struct_wrap; 
    3637 
    3738    // Importing these is only needed as a workaround to bug #311