class Spotify::ManagedPointer

An autopointer base class for Spotify pointers.

It contains a default implementation for release, retain, and a default constructor. When the underlying pointer is garbage collected, the pointer is released automatically.

This class is never instantiated; instead you’ll be dealing with any of it’s subclasses.

@note The default ManagedPointer does not retain its pointer after initialization,

but provides a class that does through {.retaining_class}. This is better as
it allows you to err on the side of segfaulting, instead of leaking memory.

@api private

Public Class Methods

from_native(pointer, ctx) click to toggle source

Casts all null pointers to nil.

Calls superclass method
# File lib/spotify/managed_pointer.rb, line 59
def from_native(pointer, ctx)
  value = super
  value unless value.null?
end
initialize(*args, &block) click to toggle source
# File lib/spotify/managed_pointer.rb, line 99
def initialize(*args, &block)
  super_initialize(*args, &block)
  self.class.retain(self)
end
release(pointer) click to toggle source

Schedules given pointer for release.

@param [FFI::Pointer] pointer

# File lib/spotify/managed_pointer.rb, line 24
def release(pointer)
  unless pointer.null?
    # this is to circumvent the type protection, and wrap the pointer
    # with the correct type for later freeing
    freeable = type_class.new(pointer)
    # and this is to not make this pointer trigger release again
    freeable.autorelease = false

    Spotify.performer.async { freeable.free }
  end
end
retain(pointer) click to toggle source

Retains the given pointer if it is not null.

This method derives the retain method from the class name.

@param [self] pointer must be an instance of {#type_class}

# File lib/spotify/managed_pointer.rb, line 41
def retain(pointer)
  unless pointer.null?
    Spotify.log "Spotify.#{type}_add_ref(#{pointer.inspect})"
    Spotify.public_send(:"#{type}_add_ref", pointer)
  end
end
retaining_class() click to toggle source

Retaining class is needed for the functions that return a pointer that does not have its reference count increased. This class is a subclass of the ManagedPointer, and should behave the same in all circumstances except for during initialization.

This dynamic method is needed to DRY the pointers up. We have about ten subclasses of ManagedPointer; all of them need a subclass that retains its pointer on initialization. We could create one manually for each Album, Artist, Track, and so on, but that would be annoying.

@return [self] subclass that retains its pointer on initialization.

# File lib/spotify/managed_pointer.rb, line 81
def retaining_class
  if defined?(self::Retaining)
    self::Retaining
  else
    subclass = Class.new(self) do
      class << self
        def type
          superclass.type
        end

        protected

        def type_class
          superclass
        end
      end

      alias_method :super_initialize, :initialize
      def initialize(*args, &block)
        super_initialize(*args, &block)
        self.class.retain(self)
      end
    end

    const_set("Retaining", subclass)
  end
end
size() click to toggle source

@see github.com/jruby/jruby/issues/607 @return [Integer] size of the native type, defined for JRuby.

# File lib/spotify/managed_pointer.rb, line 66
def size
  FFI.type_size(:pointer)
end
to_native(value, ctx) click to toggle source

Makes all ManagedPointers typesafe in the sense that they will raise an argument error on any value that is not of the same kind.

Calls superclass method
# File lib/spotify/managed_pointer.rb, line 50
def to_native(value, ctx)
  if value.nil? or value.null?
    raise TypeError, "#{name} pointers cannot be null, was #{value.inspect}"
  else
    super
  end
end
type() click to toggle source
# File lib/spotify/managed_pointer.rb, line 87
def type
  superclass.type
end

Protected Class Methods

type_class() click to toggle source
# File lib/spotify/managed_pointer.rb, line 93
def type_class
  superclass
end

Public Instance Methods

free() click to toggle source

Immediately releases the underlying pointer.

@note Does NOT call self.class.release. @note This is NOT idempotent.

# File lib/spotify/managed_pointer.rb, line 125
def free
  unless null?
    self.autorelease = false
    Spotify.log "Spotify.#{type}_release(#{inspect})"
    Spotify.public_send(:"#{type}_release", self)
  end
end
inspect() click to toggle source

@return [String] string representation of self.

# File lib/spotify/managed_pointer.rb, line 134
def inspect
  "#<#{self.class} address=0x%x>" % address
end
Also aliased as: to_s
to_s()
Alias for: inspect
type() click to toggle source

@see self.class.type

# File lib/spotify/managed_pointer.rb, line 117
def type
  self.class.type
end