Module: Svn::Utils

Defined in:
lib/svn/utils.rb

Overview

Utility functions for working with FFI

Defined Under Namespace

Modules: Extensions Classes: Factory

Class Method Summary collapse

Class Method Details

.content_for(pointer, type, len = nil) ⇒ Object

returns the the pointer’s value as type

for example:

# char *get_string( void ):
ptr = get_string()
str = content_for( ptr, :string )

# hash *get_hash( void ):
class Hash < FFI::AutoPointer; end
ptr = get_hash( out_ptr )
hash = content_for( out_ptr, Hash )


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/svn/utils.rb', line 103

def content_for( pointer, type, len=nil )
  return if pointer.nil?
  if type.is_a? Array
    type.inject( pointer ) do |ptr, subtype|
      content_for( ptr, subtype, len )
    end
  elsif type.is_a? Factory
    type.new( pointer ) unless pointer.null?
  elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
    type.new( pointer ) unless pointer.null?
  elsif type.is_a?( FFI::Type::Mapped )
    type.from_native( pointer, nil ) unless pointer.null?
  elsif type == :string
    # if len is nil or -1, use it for reading instead of counting on it to
    # be null-terminated
    pointer.read_string( ( len == -1 ) ? nil : len ) unless pointer.null?
  else
    pointer.send( :"read_#{type}" ) unless pointer.null?
  end
end

.content_from(pointer, type, len = nil) ⇒ Object

returns the contents of the pointer as type

for example:

# void get_string( char **p ):
get_string( out_ptr ); content_for( out_ptr, :string )

# void get_hash( hash_t **p ):
class Hash < FFI::AutoPointer; end
get_hash( out_ptr ); content_for( out_ptr, Hash )

if the type is a FFI::Pointer, this will try to instantiate it; to avoid instantiation, pass :pointer as the type



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/svn/utils.rb', line 71

def content_from( pointer, type, len=nil )
  return if pointer.nil?
  if type.is_a? Array
    type.inject( pointer ) do |ptr, subtype|
      content_for( ptr, subtype, len )
    end
  elsif type.is_a? Factory
    type.new( pointer.read_pointer ) unless pointer.null?
  elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
    type.new( pointer.read_pointer ) unless pointer.null?
  elsif type.is_a?( FFI::Type::Mapped )
    type.from_native( pointer.read_pointer, nil ) unless pointer.null?
  elsif type == :string
    pointer.read_pointer.read_string(
        ( len == -1 ) ? nil : len
      ) unless pointer.null?
  else
    pointer.send( :"read_#{type}" )
  end
end

.pointer_for(value, type) ⇒ Object



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/svn/utils.rb', line 124

def pointer_for( value, type )
  if type.is_a? Array
    type.reverse.inject( value ) do |val, subtype|
      pointer_for( val, subtype )
    end
  elsif type.is_a? Factory
    pointer_for( value, type.real_class )
  elsif type.is_a?( Class ) && type.ancestors.include?( FFI::Pointer )
    # use val directly
    value
  elsif type.is_a?( FFI::Type::Mapped )
    # mapped types are really pointers to structs; they are read
    # differently, but they should still be pointers we can use directly
    value
  elsif type == :string
    # use from_string even if it isn't necessary to null-terminate
    FFI::MemoryPointer.from_string( value )
  else
    # it must be a FFI type, use a new MemoryPointer
    ptr = FFI::MemoryPointer.new( type )
    ptr.send( :"write_#{type}", value )
    ptr
  end
end

.unwrap(ptr) ⇒ Object

Returns the object for the object_id stored in ptr



19
20
21
# File 'lib/svn/utils.rb', line 19

def unwrap( ptr )
  ObjectSpace._id2ref( ptr.read_uint64 )
end

.wrap(obj) ⇒ Object

Returns a pointer to the object_id of obj



12
13
14
15
16
# File 'lib/svn/utils.rb', line 12

def wrap( obj )
  ptr = FFI::MemoryPointer.new( :uint64 )
  ptr.write_uint64( obj.object_id )
  ptr
end