Create a gist now

Instantly share code, notes, and snippets.

@elabs-dev /byte_string.rb Secret
Last active Jan 25, 2016

Some examples custom types for use in FFI libraries
# 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
# 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
# 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
@Burgestrand

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