Yay, got it!

It’s actually really straight forward if you know the stuff…

The magic is in NBFFICalloutAPI. This class provides the method 
#function:address:. So if I let NB create an external object (subclass of 
NBExternalObject) for the struct field that provides the function, the address 
of the function is in the handle variable and I can define a method on that 
external object like so:

writepack: writepack buffer: buffer length: length progress: progress
        <primitive: #primitiveNativeCall module: #NativeBoostPlugin error: 
errorCode>
        ^ self nbCallout
                function: #(NBInt32 (LG2GitOdbWritepackS * writepack, const 
void * buffer, NBInt32 length, LG2GitTransferProgressS * progress))
                address: [ handle ]

This even installs native code, so call generation only happens on the first 
pass (I’ll have to see if NB is smart enough here to take changes in the handle 
into account).


>> On 22 Feb 2015, at 01:19, Nicolai Hess <nicolaih...@web.de 
>> <mailto:nicolaih...@web.de>> wrote:
>> 
>> 2015-02-22 0:06 GMT+01:00 Max Leske <maxle...@gmail.com 
>> <mailto:maxle...@gmail.com>>:
>> Hi.
>> 
>> I have a situation with libgit2 where the function I need to call is a field 
>> in a struct (the field gets populated with different functions with the same 
>> signature depending on certain conditions).
>> 
>> I’m facing two problems now:
>> 1. how do I define a function as the field type of an NBExternalStructure?
>> 
>> Athens creates a structure with callbacks as a surface plugin for the 
>> bitblter (SQSurfaceDispatch).
>> But this is a structur with functions (generated with NB) that are called 
>> "from the outside"
>>  
>> 2. how can I call the function?
>> 
>> I don't know of any example in the image, where we are calling a function 
>> defined in a struct.
>> Maybe you can extend NBFFICallout to generate a call from a function spec + 
>> function address
>> 
>> NBFFICallout>>#generateCall:module: does this, it generates a call from a 
>> function spec and and
>> address loockuped in a module, maybe you can do something similiar, but use 
>> the function address from
>> the structure isntead of calling nbGetSymbolAddress:module: 
> 
> I’ll give that a try, thanks.
> 
>> 
>>  
>> 
>> I’ve tried using callbacks as field types. That works as far as I can access 
>> the functions by pointer. But how would I then call that function?
>> I’ve looked at NBNativeFunction and NBNativeFunctionGen but I can’t see how 
>> I should use either of those to make a plain call.
>> 
>> Here’s a more precise description of my problem:
>> 
>> writepack := LG2GitOdbWritepackS new.
>> … “initialize the struct externally”
>> 
>> “now call the function ‘commit’ and pass the arguments (this is how I 
>> imagine it could work…)"
>> writepack commit
>>         value: writepack
>>         value: anotherStruct.
>> 
>> 
>> Needed struct fields:
>> 
>> backend:        git_odb_backend *
>> append:                 int (*)(git_odb_writepack *, const void *, size_t, 
>> git_transfer_progress *)
>> commit:                 int (*)(git_odb_writepack *, git_transfer_progress *)
>> free:                   void (*)(git_odb_writepack *)
>> 
>> 
>> For what is this needed?  Do you want to write your own git backend?
> 
> No. I need to implement packing of loose objects to save space. libgit2 only 
> does this for network transport. For this I need to work with the pack 
> backend directly and the backend provides the function I need to call for 
> finishing the write in the “commit” field of the struct. Of course, I know 
> which function that will be since I’m working with one particular backend. 
> But if I wanted to support multiple backends in the future it would be better 
> to call the provided function instead of explicitly naming it.
> 
>> 
>> I find this strange. I only know of two use cases for function pointers in a 
>> structs.
>> 1. to define the callbacks (like athens does it for the SQSurfaceDispatch). 
>> But we only define the functions and don't call them.
>> 2. a library defines a public api and delegates the implementation to 
>> different backends, but structure and backend functions
>>     are hidden. Users of the library don't call them.
> 
> Exactly. I’m dipping deeper here than one usually needs to.
> 
> Thanks Nicolai.
> 
>> 
>> 
>> 
>>  
>> 
>> My current (ad hoc) struct fields:
>> 
>> fieldsDesc
>>         ^#(
>>         LG2GitOdbO backend;
>>         LG2WritePackAppendCb append;
>>         LG2WritePackCommitCb commit;
>>         LG2WritePackFreeCb free;
>>         )
>> 
>> 
>> I’d even be happy if I have to implement a method on LG2GitOdbWritepackS for 
>> every function call (e.g. “writepack commit: arg1 and: arg2”) but how would 
>> I make the call?
>> 
>> Any ideas?
>> Max
>> 
> 

Reply via email to