+
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions lib/ffi/struct.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

require 'ffi/platform'
require 'ffi/struct_layout_builder'
require 'json'

module FFI

Expand Down Expand Up @@ -146,6 +147,102 @@ def to_ptr
pointer
end

# Recursively dump this structure's data as a Hash.
# @return [Hash] Hash containing member/data pairs for every member in the struct
#
# @example
# z = Rect.new
# z[:x] = 1
# z[:y] = 2
# z[:w] = 3
# z[:h] = 4
# z.to_h => {:h=>4, :w=>3, :x=>1, :y=>2}
def to_h
m_list = {}
members.collect do |m|
if self[m].is_a?(FFI::Struct)
m_list[m] = self[m].to_h
else
m_list[m] = self[m]
end
end
return m_list
end

# Recursively dump this structure's data as an Array.
# The array contains only the data, not the member names.
# @return [Array] array of data
#
# @note the order of data in the array always matches the
# order of members given in #layout.
#
# @example
# z = Rect.new
# z[:x] = 1
# z[:y] = 2
# z[:w] = 3
# z[:h] = 4
# z.to_a => [1,2,3,4]
def to_a
members.collect do |m|
if self[m].is_a?(FFI::Struct)
self[m].to_a
else
self[m]
end
end
end

# Dump this structure's data as a raw bytestring.
# @return [String] raw byte sequence
def to_bytes
return self.pointer.get_bytes(0, self.size)
end

# Serialize data to JSON format
def to_json
JSON.generate(to_h)
end

# Serialize data for use with the Ruby standard 'Marshal' library.
# This function will be invoked when 'Marshal.dump' is called.
def marshal_dump
to_h
end

# De-serialize data generated by the standard 'Marshal.dump' method.
# This function will be invoked when 'Marshal.load' is called.
def marshal_load data
initialize
init_from_hash data
end

# Load data from a variety of different formats.
# Currently supports Array, Hash, Bytestring, and JSON.
def load(data)
case data
when Hash
init_from_hash data
when ::Array
init_from_array data
when String
if data.bytesize == size
init_from_bytes data
else
begin
init_from_json data
rescue JSON::ParserError
# This typically occurs because the string was not JSON at all.
# Displaying a JSON-specific exception can be misleading, so use
# a generic message instead.
raise TypeError, "cannot initialize #{self.class} with the given #{data.class}"
end
end
else
raise TypeError, "cannot initialize #{self.class} with type #{data.class}"
end
end

# Get struct size
# @return [Numeric]
def self.size
Expand Down Expand Up @@ -226,6 +323,57 @@ def self.auto_ptr
@managed_type ||= Type::Mapped.new(ManagedStructConverter.new(self))
end

protected

# Initialize the contents of this structure using data from a hash.
# @param val [Hash] hash containing field symbols and associated data
def init_from_hash(val)
clear
val.each do |sym, value|
raise NoMethodError unless self.members.member?(sym)
if self[sym].is_a?(FFI::Struct)
self[sym] = self[sym].class.new
self[sym].init_from_hash(value)
else
self[sym] = value
end
end
end

# Initialize the contents of this structure using elements from an array.
# Array data must be in the same order as was used with #layout.
# @param ary [Array] array of structure member data
def init_from_array(ary)
unless ary.length == members.length
raise IndexError, "expected #{members.length} items, got #{ary.length}"
end
clear
members.each_with_index do |member, i|
if self[member].is_a?(FFI::Struct)
self[member] = self[member].class.new
self[member].init_from_array(ary[i])
else
self[member] = ary[i]
end
end
end

# Initialize the contents of this structure using a bytestring.
# @param data [String] byte sequence encoded as a String
def init_from_bytes(data)
unless data.bytesize == size
raise ArgumentError, "string of length #{data.bytesize} cannot initialize a structure with size #{size}"
end
clear
self.pointer.put_bytes(0, data)
end

# De-serialize data from a JSON record
def init_from_json(data)
h = JSON.parse(data, opts={:symbolize_names => true})
init_from_hash h
end


class << self
public
Expand Down
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载