UFFI correct way to cast void*

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

UFFI correct way to cast void*

Egor Scorik
Hi,

I'm trying to play with new UFFI system. It looks much easier then
NativeBoost, but unfortunately its hard to find any docs or examples.
I have problem with casting void* (ExternalAddress) into smalltalk object if
there is no hardcoded type in ffi method. And I really dislike the idea of
making many ffi methods, one for each required type.
In this example i can't understand how to make something like `address
castTo: type`

FFIExternalObject subclass: #Iterator

Iterator >> asCollectionOfType: aTypeName
        | result address type |
       
        result := OrderedCollection new.
        address := ExternalAddress new.
        type := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address] whileTrue: [
                result add: (address castTo: type).
        ].
    ^result

Iterator >> iterator_next: data
        ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))




--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

Torsten Bergmann
>but unfortunately its hard to find any docs or examples.

PDF Docu:  https://github.com/SquareBracketAssociates/Booklet-uFFI

           (this should be added to http://books.pharo.org)

Examples:  load OSWindows, OSLinuxUbuntu, ... or GlorpSQlite from catalog
           They all use UFFI.

Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

EstebanLM
In reply to this post by Egor Scorik
hi,

“casting” is not necessary in general since is just a way to tell the C compiler that a pointer is form a certain type (but is always a pointer, and in machine code is always the same).

So, here you will do something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |
       
        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass fromHandle: address) ].
   ^result

Iterator >> iterator_next: data
        ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))

now… you have a problem if your type if your type is an “atomic” type, like int, long, etc. because those values are passed “by value” and not by pointer, so you will need to decode them.
in this case, I would implement a  method extension (probably it worths to add it to UFFI):

FFIExternalType class >> valueFromHandle: anAddress
        ^ self new handle: anAddress at: 1 “This is used for structures, but we can reuse them :)"

FFIExternalReference class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

FFIExternalStructure class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

So your function will be like something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |
       
        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass valueFromHandle:: address) ].
   ^result

and voilà, you have your cast :)

Esteban

ps: (some errors can be found here, since I’m “programming at mail client”, but you get the idea ;) )

> On 15 Feb 2018, at 19:59, Egor Scorik <[hidden email]> wrote:
>
> Hi,
>
> I'm trying to play with new UFFI system. It looks much easier then
> NativeBoost, but unfortunately its hard to find any docs or examples.
> I have problem with casting void* (ExternalAddress) into smalltalk object if
> there is no hardcoded type in ffi method. And I really dislike the idea of
> making many ffi methods, one for each required type.
> In this example i can't understand how to make something like `address
> castTo: type`
>
> FFIExternalObject subclass: #Iterator
>
> Iterator >> asCollectionOfType: aTypeName
> | result address type |
>
> result := OrderedCollection new.
> address := ExternalAddress new.
> type := FFIExternalType resolveType: aTypeName.
> [self iterator_next: address] whileTrue: [
> result add: (address castTo: type).
> ].
>    ^result
>
> Iterator >> iterator_next: data
> ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>


Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

Ben Coman


On 16 February 2018 at 16:38, Esteban Lorenzano <[hidden email]> wrote:
hi,

“casting” is not necessary in general since is just a way to tell the C compiler that a pointer is form a certain type (but is always a pointer, and in machine code is always the same).

So, here you will do something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |

        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass fromHandle: address) ].

Perhaps this is a bit about discover-ability.  People with C experience may
naturally search for "cast".  If I Spotter search for..... cast #i
it turns up only four... "broadcast" under Socket class

If that was instead like...  (typeClass castFromHandle: address)
then people may be more likely to find it themselves.

cheers -ben

  
 
   ^result

Iterator >> iterator_next: data
        ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))

now… you have a problem if your type if your type is an “atomic” type, like int, long, etc. because those values are passed “by value” and not by pointer, so you will need to decode them.
in this case, I would implement a  method extension (probably it worths to add it to UFFI):

FFIExternalType class >> valueFromHandle: anAddress
        ^ self new handle: anAddress at: 1 “This is used for structures, but we can reuse them :)"

FFIExternalReference class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

FFIExternalStructure class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

So your function will be like something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |

        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass valueFromHandle:: address) ].
   ^result

and voilà, you have your cast :)

Esteban

ps: (some errors can be found here, since I’m “programming at mail client”, but you get the idea ;) )

> On 15 Feb 2018, at 19:59, Egor Scorik <[hidden email]> wrote:
>
> Hi,
>
> I'm trying to play with new UFFI system. It looks much easier then
> NativeBoost, but unfortunately its hard to find any docs or examples.
> I have problem with casting void* (ExternalAddress) into smalltalk object if
> there is no hardcoded type in ffi method. And I really dislike the idea of
> making many ffi methods, one for each required type.
> In this example i can't understand how to make something like `address
> castTo: type`
>
> FFIExternalObject subclass: #Iterator
>
> Iterator >> asCollectionOfType: aTypeName
>       | result address type |
>
>       result := OrderedCollection new.
>       address := ExternalAddress new.
>       type := FFIExternalType resolveType: aTypeName.
>       [self iterator_next: address] whileTrue: [
>               result add: (address castTo: type).
>       ].
>    ^result
>
> Iterator >> iterator_next: data
>       ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>



Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

Stephane Ducasse-3
In reply to this post by Torsten Bergmann
On Fri, Feb 16, 2018 at 9:07 AM, Torsten Bergmann <[hidden email]> wrote:
>>but unfortunately its hard to find any docs or examples.
>
> PDF Docu:  https://github.com/SquareBracketAssociates/Booklet-uFFI
>
>            (this should be added to http://books.pharo.org)

It will be added when it will be completed.
And since this is not me that will do it because I cannot then I wait.
May be one day someone with enough knowledge will consider that FFI is
important enough
to document it seriously.

Stef


>
> Examples:  load OSWindows, OSLinuxUbuntu, ... or GlorpSQlite from catalog
>            They all use UFFI.
>

Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

Stephane Ducasse-3
In reply to this post by EstebanLM
Hi esteban

do you plan to add this explanation to the documentation of uFFI?

Stef

On Fri, Feb 16, 2018 at 9:38 AM, Esteban Lorenzano <[hidden email]> wrote:

> hi,
>
> “casting” is not necessary in general since is just a way to tell the C compiler that a pointer is form a certain type (but is always a pointer, and in machine code is always the same).
>
> So, here you will do something like this:
>
> Iterator >> asCollectionOfType: aTypeName
>         | result address typeClass |
>
>         result := OrderedCollection new.
>         address := ExternalAddress new.
>         typeClass := FFIExternalType resolveType: aTypeName.
>         [self iterator_next: address]
>                 whileTrue: [ result add: (typeClass fromHandle: address) ].
>    ^result
>
> Iterator >> iterator_next: data
>         ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))
>
> now… you have a problem if your type if your type is an “atomic” type, like int, long, etc. because those values are passed “by value” and not by pointer, so you will need to decode them.
> in this case, I would implement a  method extension (probably it worths to add it to UFFI):
>
> FFIExternalType class >> valueFromHandle: anAddress
>         ^ self new handle: anAddress at: 1 “This is used for structures, but we can reuse them :)"
>
> FFIExternalReference class >> valueFromHandle: anAddress
>         ^ self fromHandle: anAddress
>
> FFIExternalStructure class >> valueFromHandle: anAddress
>         ^ self fromHandle: anAddress
>
> So your function will be like something like this:
>
> Iterator >> asCollectionOfType: aTypeName
>         | result address typeClass |
>
>         result := OrderedCollection new.
>         address := ExternalAddress new.
>         typeClass := FFIExternalType resolveType: aTypeName.
>         [self iterator_next: address]
>                 whileTrue: [ result add: (typeClass valueFromHandle:: address) ].
>    ^result
>
> and voilà, you have your cast :)
>
> Esteban
>
> ps: (some errors can be found here, since I’m “programming at mail client”, but you get the idea ;) )
>
>> On 15 Feb 2018, at 19:59, Egor Scorik <[hidden email]> wrote:
>>
>> Hi,
>>
>> I'm trying to play with new UFFI system. It looks much easier then
>> NativeBoost, but unfortunately its hard to find any docs or examples.
>> I have problem with casting void* (ExternalAddress) into smalltalk object if
>> there is no hardcoded type in ffi method. And I really dislike the idea of
>> making many ffi methods, one for each required type.
>> In this example i can't understand how to make something like `address
>> castTo: type`
>>
>> FFIExternalObject subclass: #Iterator
>>
>> Iterator >> asCollectionOfType: aTypeName
>>       | result address type |
>>
>>       result := OrderedCollection new.
>>       address := ExternalAddress new.
>>       type := FFIExternalType resolveType: aTypeName.
>>       [self iterator_next: address] whileTrue: [
>>               result add: (address castTo: type).
>>       ].
>>    ^result
>>
>> Iterator >> iterator_next: data
>>       ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))
>>
>>
>>
>>
>> --
>> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

EstebanLM
In reply to this post by Ben Coman


On 17 Feb 2018, at 02:50, Ben Coman <[hidden email]> wrote:



On 16 February 2018 at 16:38, Esteban Lorenzano <[hidden email]> wrote:
hi,

“casting” is not necessary in general since is just a way to tell the C compiler that a pointer is form a certain type (but is always a pointer, and in machine code is always the same).

So, here you will do something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |

        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass fromHandle: address) ].

Perhaps this is a bit about discover-ability.  People with C experience may
naturally search for "cast".  If I Spotter search for..... cast #i
it turns up only four... "broadcast" under Socket class

If that was instead like...  (typeClass castFromHandle: address)
then people may be more likely to find it themselves.

I was thinking to implement the #castTo: for all the “pointer” classes (ByteArray, FFIExternalReference, FFIExternalStructure). 

#[42 0 0 0] castTo: FFIInt32 -> 42

what do you think?

Esteban



cheers -ben

  
 
   ^result

Iterator >> iterator_next: data
        ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))

now… you have a problem if your type if your type is an “atomic” type, like int, long, etc. because those values are passed “by value” and not by pointer, so you will need to decode them.
in this case, I would implement a  method extension (probably it worths to add it to UFFI):

FFIExternalType class >> valueFromHandle: anAddress
        ^ self new handle: anAddress at: 1 “This is used for structures, but we can reuse them :)"

FFIExternalReference class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

FFIExternalStructure class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

So your function will be like something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |

        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass valueFromHandle:: address) ].
   ^result

and voilà, you have your cast :)

Esteban

ps: (some errors can be found here, since I’m “programming at mail client”, but you get the idea ;) )

> On 15 Feb 2018, at 19:59, Egor Scorik <[hidden email]> wrote:
>
> Hi,
>
> I'm trying to play with new UFFI system. It looks much easier then
> NativeBoost, but unfortunately its hard to find any docs or examples.
> I have problem with casting void* (ExternalAddress) into smalltalk object if
> there is no hardcoded type in ffi method. And I really dislike the idea of
> making many ffi methods, one for each required type.
> In this example i can't understand how to make something like `address
> castTo: type`
>
> FFIExternalObject subclass: #Iterator
>
> Iterator >> asCollectionOfType: aTypeName
>       | result address type |
>
>       result := OrderedCollection new.
>       address := ExternalAddress new.
>       type := FFIExternalType resolveType: aTypeName.
>       [self iterator_next: address] whileTrue: [
>               result add: (address castTo: type).
>       ].
>    ^result
>
> Iterator >> iterator_next: data
>       ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>




Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

Egor Scorik
In reply to this post by Ben Coman
Thanks! #valueFromHandle: exactly what I looking for! I also add method for
strings to make them working

FFIExternalString >> valueFromHandle: anAddress
        | data |
        data := ExternalData
                fromHandle: anAddress
                type: ExternalType string.
        data isNull ifTrue: [ ^ nil ].
        ^ data fromCString



--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Reply | Threaded
Open this post in threaded view
|

Re: UFFI correct way to cast void*

Ben Coman
In reply to this post by EstebanLM


On 18 February 2018 at 01:46, Esteban Lorenzano <[hidden email]> wrote:


On 17 Feb 2018, at 02:50, Ben Coman <[hidden email]> wrote:



On 16 February 2018 at 16:38, Esteban Lorenzano <[hidden email]> wrote:
hi,

“casting” is not necessary in general since is just a way to tell the C compiler that a pointer is form a certain type (but is always a pointer, and in machine code is always the same).

So, here you will do something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |

        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass fromHandle: address) ].

Perhaps this is a bit about discover-ability.  People with C experience may
naturally search for "cast".  If I Spotter search for..... cast #i
it turns up only four... "broadcast" under Socket class

If that was instead like...  (typeClass castFromHandle: address)
then people may be more likely to find it themselves.

I was thinking to implement the #castTo: for all the “pointer” classes (ByteArray, FFIExternalReference, FFIExternalStructure). 

#[42 0 0 0] castTo: FFIInt32 -> 42

what do you think?

That will be useful, and intuitive for people to find. 

cheers -ben

 

Esteban



cheers -ben

  
 
   ^result

Iterator >> iterator_next: data
        ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))

now… you have a problem if your type if your type is an “atomic” type, like int, long, etc. because those values are passed “by value” and not by pointer, so you will need to decode them.
in this case, I would implement a  method extension (probably it worths to add it to UFFI):

FFIExternalType class >> valueFromHandle: anAddress
        ^ self new handle: anAddress at: 1 “This is used for structures, but we can reuse them :)"

FFIExternalReference class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

FFIExternalStructure class >> valueFromHandle: anAddress
        ^ self fromHandle: anAddress

So your function will be like something like this:

Iterator >> asCollectionOfType: aTypeName
        | result address typeClass |

        result := OrderedCollection new.
        address := ExternalAddress new.
        typeClass := FFIExternalType resolveType: aTypeName.
        [self iterator_next: address]
                whileTrue: [ result add: (typeClass valueFromHandle:: address) ].
   ^result

and voilà, you have your cast :)

Esteban

ps: (some errors can be found here, since I’m “programming at mail client”, but you get the idea ;) )

> On 15 Feb 2018, at 19:59, Egor Scorik <[hidden email]> wrote:
>
> Hi,
>
> I'm trying to play with new UFFI system. It looks much easier then
> NativeBoost, but unfortunately its hard to find any docs or examples.
> I have problem with casting void* (ExternalAddress) into smalltalk object if
> there is no hardcoded type in ffi method. And I really dislike the idea of
> making many ffi methods, one for each required type.
> In this example i can't understand how to make something like `address
> castTo: type`
>
> FFIExternalObject subclass: #Iterator
>
> Iterator >> asCollectionOfType: aTypeName
>       | result address type |
>
>       result := OrderedCollection new.
>       address := ExternalAddress new.
>       type := FFIExternalType resolveType: aTypeName.
>       [self iterator_next: address] whileTrue: [
>               result add: (address castTo: type).
>       ].
>    ^result
>
> Iterator >> iterator_next: data
>       ^ self ffiCall: #(Boolean iterator_next (Iterator self, void** data))
>
>
>
>
> --
> Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html
>