Hi Stefan, First of all I want to thank you for this mail, which showed me a bug that I had in TalkFFI (the git_repository 'NBVoid *') which introduces one more indirection level, which is wrong. On Fri, Jan 25, 2013 at 2:13 AM, Stefan Marr <smalltalk@stefan-marr.de>wrote:
Hi:
I don't really understand how NativeBoostFFI handles pointers.
probably Igor is the best to answer this question... in details
I have two functions like this:
self call: #(int git_repository_open(git_repository * * handle, char * path))
and
self call: #(int git_repository_head(git_reference * * refHandle, git_repository * repo))
They use a type mapping like this: #('git_repository' 'NBVoid' 'git_reference' 'NBVoid' )
So, nothing special going on here, just pointers to pointers, and pointers to opaque data structures.
Now, the call to the _open function is done with a `repoHandle := NBExternalHandle new`. This works, and I get the result value of the c lib inside my repoHandle.
However, if I want to use it in the _head call, I first have to convert it into a NBExternalAddress (`NBExternalAddress value: repoHandle value`).
Took me a while to figure out that passing in the repoHandle to _head does actually do the wrong thing. The _head function then gets the address of repoHandle instead of its value, which is wrong for my usecase.
However, just passing in `repoHandle value` results in some strange _nil_ error.
So, the main question is, why do I need to convert between Handle and Address?
For the library I am trying to use, that becomes a somehow recurring pattern:
| repo repoPath cb branches headHandle | repo := NBExternalHandle new. repoPath := NBExternalAddress fromString: '/Users/smarr/tmp/filetree'.
LG2RepositoryH uniqueInstance repository_open: repo path: repoPath. repo := NBExternalAddress value: repo value. "<-- Why is this necessary?"
headHandle := NBExternalHandle new. LG2RepositoryH uniqueInstance repository_head: headHandle repo: repo.
^ (LG2RefsH uniqueInstance reference_name: (NBExternalAddress value: headHandle value)) "<-- Why is this necessary?" readString
Another solution which removes this recurring pattern is to use the NBExternalObject, either directly, or by subclassing it. Here is a snippet showing how: |headHandle path repo name| repo := NBExternalObject new. path := NBExternalAddress fromString: '/Users/ciprian/github/local/enso'. LG2RepositoryH uniqueInstance repository_open: repo path: path. headHandle := NBExternalObject new. LG2RepositoryH uniqueInstance repository_head: headHandle repo: repo. name := LG2RefsH uniqueInstance reference_name: headHandle. name readString. but now FFI methods need to be changed to: repository_open: out path: path ^self call: #(NBInt32 git_repository_open(NBExternalObject * out, NBCharacterType * path)) options: #( ) repository_head: out repo: repo ^self call: #(NBInt32 git_repository_head(NBExternalObject * out, NBExternalObject repo)) options: #( ) reference_name: ref ^self call: #(NBCharacterType * git_reference_name(NBExternalObject ref)) options: #( ) Notice that when using NBExternalObject one level of indirection is gone so git_repository ** becomes NBExternalObject * Even nicer, if you subclass the NBExternalObject to have LG2Repository and LG2Reference, the signatures become clearer... I will look this weekend at TalkFFI to see how can I make use of this NBExternalObject, at least in the simple cases... to prevent the need for (NBExternalAddress value: repo value) all over the place. Cheers, Ciprian
Thanks Stefan
-- Stefan Marr Software Languages Lab Vrije Universiteit Brussel Pleinlaan 2 / B-1050 Brussels / Belgium http://soft.vub.ac.be/~smarr Phone: +32 2 629 2974 Fax: +32 2 629 3525
-- Dr. Ciprian TEODOROV Ingénieur Développement CAO tél : 06 08 54 73 48 mail : ciprian.teodorov@gmail.com www.teodorov.ro