Last active

Embed URL

HTTPS clone URL

SSH clone URL

You can clone with HTTPS or SSH.

Download Gist

Some examples custom types for use in FFI libraries

View byte_string.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
# From: https://github.com/Burgestrand/spotify/blob/master/lib/spotify/types/byte_string.rb
 
module Spotify
module ByteString
extend FFI::DataConverter
native_type FFI::Type::POINTER
 
class << self
# Given either a String or nil, make an actual FFI::Pointer
# of that value, without an ending NULL-byte.
#
# @param [#to_str, nil] value
# @param ctx
# @return [FFI::Pointer]
def to_native(value, ctx)
value && begin
value = value.to_str
 
pointer = FFI::MemoryPointer.new(:char, value.bytesize)
pointer.write_string(value)
end
end
# no from_native, as we must return a pointer because we simply
# don’t know the length of a ByteString just by looking at the pointer.
 
def reference_required?
true
end
end
end
end
View byte_string.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
# From: https://github.com/Burgestrand/spotify/blob/master/lib/spotify/types/image_id.rb
 
module Spotify
# A custom data type for Spotify image IDs.
#
# It will convert strings to image ID pointers when handling
# values from Ruby to C, and it will convert pointers to Ruby
# strings when handling values from C to Ruby.
#
# Spotify image IDs are pointers to an array of 20 bytes, but
# in Ruby we treat them as strings.
module ImageID
extend FFI::DataConverter
native_type FFI::Type::POINTER
 
class << self
# @return [Integer] bytesize of image ID pointers.
def size
20
end
 
# Given a string, convert it to an image ID pointer.
#
# @param [#to_str, nil] value image id as a string
# @param ctx
# @return [FFI::Pointer] pointer to the image ID
def to_native(value, ctx)
value && begin
value = value.to_str
 
if value.bytesize != size
raise ArgumentError, "image id bytesize must be #{size}, was #{value.bytesize}"
end
 
pointer = FFI::MemoryPointer.new(:char, size)
pointer.write_string(value)
end
end
 
# Given a pointer, read a {.size}-byte image ID from it.
#
# @param [FFI::Pointer] value
# @param ctx
# @return [String, nil] the image ID as a string, or nil
def from_native(value, ctx)
value.read_string(size) unless value.null?
end
 
# FFI needs this to know if a reference to the native object
# should be kept. Since we allocate memory using MemoryPointer,
# we want the refernce to be kept.
#
# This is used if you assign the object to a struct, for exmaple.
def reference_required?
true
end
end
end
end
View byte_string.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
# From: https://github.com/Burgestrand/plaything/blob/master/lib/plaything/support/type_class.rb
 
class Plaything
module OpenAL
# TypeClass will return an FFI::DataConverter for a built-in FFI
# type. Since you can’t subclass FFI::Type::INT, for example, this
# method will return a class for a given type that you *can* subclass.
#
# Example usage:
#
# class Source < TypeClass(FFI::Type::INT)
# end
def self.TypeClass(type)
Class.new do
extend FFI::DataConverter
 
define_singleton_method(:type) do
type
end
 
class << self
def inherited(other)
other.native_type(type)
end
 
def to_native(source, ctx)
source.value
end
 
def from_native(value, ctx)
new(value)
end
 
def size
type.size
end
end
 
def initialize(value)
@value = value
end
 
def ==(other)
other.is_a?(self.class) and other.value == value
end
 
attr_reader :value
end
end
end
end

To any elabsians wondering why this is here, I created it for the upcoming blog post on FFI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.