Native object interfaces
sgs_ObjInterface object_iface[1] = {{ "object_name", // type name NULL, NULL, // destruct, gcmark NULL, NULL, // getindex, setindex NULL, NULL, NULL, NULL, // convert, serialize, dump, getnext NULL, NULL // call, expr }};
- This is the minimal object interface definition. It defines the name and implements no callbacks.
- The slightly unusual syntax is actually a definition of an interface array with one element.
- This effectively creates a pointer to interface, which is the only way the interface is requested by any API function.
- Interface must be accessible until there's at least one object using it. It can usually be defined as a global/static variable.
sgs_CreateObject( C, NULL, malloc( sizeof( mystruct ) ), object_iface ); sgs_CreateObjectIPA( C, NULL, sizeof( mystruct ), object_iface ); // preferred method
- There are two ways to create objects. Pointer to external data / in-place allocation.
- First way simply means that a data pointer is set to whatever value you want.
- Second way sets the data pointer to memory space followed by internal data, for which the internal data allocation is extended by the specified number of bytes.
- The in-place allocated block does not need to be freed explicity.
- This generally requires one less allocation to be performed.
It is very important that all memory operations on in-place allocated blocks do not, at any time, operate beyond the boundaries of those blocks. Be especially wary of putting arrays at the beginning of a structure since accidentally applying negative indices to such arrays could create issues that are extremely hard to debug.
int object_destruct( SGS_CTX, sgs_VarObj* obj ) { free( obj->data ); return SGS_SUCCESS; }
- This is a very basic object destruction callback. It simply assumes that the data pointer was malloc'ed and frees it.
- All callbacks return
int
and have the same first two arguments (sgs_Context*
andsgs_VarObj*
). - In all callbacks, negative return values are error codes and non-negative (>= 0) imply success.
int object_getindex( SGS_CTX, sgs_VarObj* obj ) { char* str; if( sgs_ParseString( C, 0, &str, NULL ) ) { if( strcmp( str, "data_pointer" ) == 0 ) return sgs_PushPtr( C, obj->data ); if( strcmp( str, "do_something" ) == 0 ) return sgs_PushCFunc( C, object_do_something ); if( strcmp( str, "do_smth_else" ) == 0 ) return sgs_PushCFunc( C, object_do_smth_else ); } return SGS_ENOTFND; // return that the specified key was not found in object } // a slightly cleaner but less hands-on, the macro-based version: int object_getindex( SGS_ARGS_GETINDEXFUNC ) { SGS_BEGIN_INDEXFUNC SGS_CASE( "data_pointer" ) return sgs_PushPtr( C, obj->data ); SGS_CASE( "do_something" ) return sgs_PushCFunc( C, object_do_something ); SGS_CASE( "do_smth_else" ) return sgs_PushCFunc( C, object_do_smth_else ); SGS_END_INDEXFUNC }
- This is a very basic index/property reading callback.
- On request for key
data_pointer
, it returns pointer to allocated memory. - On requests for the other two keys, it returns the associated methods.
- On request for key
- Both presented versions are practically interchangeable.
- This error code (SGS_ENOTFND), coming from this callback, has a specific behavior: it may trigger a 'property/index not found' warning.
- It is NOT recommended to return SGS_SUCCESS and send the warning manually because return code is passed back to API functions.