Class: Fiddle::CStructEntity
- Defined in:
- lib/fiddle/struct.rb
Overview
A pointer to a C structure
Direct Known Subclasses
Constant Summary
Constants included from PackInfo
PackInfo::ALIGN_MAP, PackInfo::PACK_MAP, PackInfo::SIZE_MAP
Class Method Summary collapse
- .alignment(types) ⇒ Object
-
.malloc(types, func = nil, size = size(types), &block) ⇒ Object
Allocates a C struct with the
types
provided. -
.size(types) ⇒ Object
Returns the offset for the packed sizes for the given
types
.
Instance Method Summary collapse
-
#[](*args) ⇒ Object
Fetch struct member
name
if only one argument is specified. -
#[]=(*args) ⇒ Object
Set struct member
name
, to valueval
. -
#assign_names(members) ⇒ Object
Set the names of the
members
in this C struct. -
#initialize(addr, types, func = nil) ⇒ CStructEntity
constructor
Wraps the C pointer
addr
as a C struct with the giventypes
. -
#set_ctypes(types) ⇒ Object
Calculates the offsets and sizes for the given
types
in the struct. -
#to_s ⇒ Object
:nodoc:.
Methods included from ValueUtil
#signed_value, #unsigned_value, #wrap_arg, #wrap_args
Methods included from PackInfo
Methods inherited from Pointer
#+, #+@, #-, #-@, #<=>, #==, [], #call_free, #eql?, #free, #free=, #freed?, #inspect, #null?, #ptr, #ref, #size, #size=, #to_i, #to_int, to_ptr, #to_str, #to_value
Constructor Details
#initialize(addr, types, func = nil) ⇒ CStructEntity
Wraps the C pointer addr
as a C struct with the given types
.
When the instance is garbage collected, the C function func
is called.
See also Fiddle::Pointer.new
269 270 271 272 273 274 275 |
# File 'lib/fiddle/struct.rb', line 269 def initialize(addr, types, func = nil) if func && addr.is_a?(Pointer) && addr.free raise ArgumentError, 'free function specified on both underlying struct Pointer and when creating a CStructEntity - who do you want to free this?' end set_ctypes(types) super(addr, @size, func) end |
Class Method Details
.alignment(types) ⇒ Object
206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/fiddle/struct.rb', line 206 def CStructEntity.alignment(types) max = 1 types.each do |type, count = 1| if type.respond_to?(:entity_class) n = type.alignment else n = ALIGN_MAP[type] end max = n if n > max end max end |
.malloc(types, func = nil, size = size(types), &block) ⇒ Object
Allocates a C struct with the types
provided.
See Fiddle::Pointer.malloc for memory management issues.
222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/fiddle/struct.rb', line 222 def CStructEntity.malloc(types, func = nil, size = size(types), &block) if block_given? super(size, func) do |struct| struct.set_ctypes types yield struct end else struct = super(size, func) struct.set_ctypes types struct end end |
.size(types) ⇒ Object
Returns the offset for the packed sizes for the given types
.
Fiddle::CStructEntity.size(
[ Fiddle::TYPE_DOUBLE,
Fiddle::TYPE_INT,
Fiddle::TYPE_CHAR,
Fiddle::TYPE_VOIDP ]) #=> 24
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 |
# File 'lib/fiddle/struct.rb', line 242 def CStructEntity.size(types) offset = 0 max_align = types.map { |type, count = 1| last_offset = offset if type.respond_to?(:entity_class) align = type.alignment type_size = type.size else align = PackInfo::ALIGN_MAP[type] type_size = PackInfo::SIZE_MAP[type] end offset = PackInfo.align(last_offset, align) + (type_size * count) align }.max PackInfo.align(offset, max_align) end |
Instance Method Details
#[](*args) ⇒ Object
Fetch struct member name
if only one argument is specified. If two arguments are specified, the first is an offset and the second is a length and this method returns the string of length
bytes beginning at offset
.
Examples:
my_struct = struct(['int id']).malloc
my_struct.id = 1
my_struct['id'] # => 1
my_struct[0, 4] # => "\x01\x00\x00\x00".b
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 |
# File 'lib/fiddle/struct.rb', line 342 def [](*args) return super(*args) if args.size > 1 name = args[0] idx = @members.index(name) if( idx.nil? ) raise(ArgumentError, "no such member: #{name}") end ty = @ctypes[idx] if( ty.is_a?(Array) ) if ty.first.respond_to?(:entity_class) return @nested_structs[name] else r = super(@offset[idx], SIZE_MAP[ty[0]] * ty[1]) end elsif ty.respond_to?(:entity_class) return @nested_structs[name] else r = super(@offset[idx], SIZE_MAP[ty.abs]) end packer = Packer.new([ty]) val = packer.unpack([r]) case ty when Array case ty[0] when TYPE_VOIDP val = val.collect{|v| Pointer.new(v)} end when TYPE_VOIDP val = Pointer.new(val[0]) else val = val[0] end if( ty.is_a?(Integer) && (ty < 0) ) return unsigned_value(val, ty) elsif( ty.is_a?(Array) && (ty[0] < 0) ) return StructArray.new(self + @offset[idx], ty[0], val) else return val end end |
#[]=(*args) ⇒ Object
Set struct member name
, to value val
. If more arguments are specified, writes the string of bytes to the memory at the given offset
and length
.
Examples:
my_struct = struct(['int id']).malloc
my_struct['id'] = 1
my_struct[0, 4] = "\x01\x00\x00\x00".b
my_struct.id # => 1
394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/fiddle/struct.rb', line 394 def []=(*args) return super(*args) if args.size > 2 name, val = *args name = name.to_s if name.is_a?(Symbol) nested_struct = @nested_structs[name] if nested_struct if nested_struct.is_a?(StructArray) if val.nil? nested_struct.each do |s| s.replace(nil) end else val.each_with_index do |v, i| nested_struct[i] = v end end else nested_struct.replace(val) end return val end idx = @members.index(name) if( idx.nil? ) raise(ArgumentError, "no such member: #{name}") end ty = @ctypes[idx] packer = Packer.new([ty]) val = wrap_arg(val, ty, []) buff = packer.pack([val].flatten()) super(@offset[idx], buff.size, buff) if( ty.is_a?(Integer) && (ty < 0) ) return unsigned_value(val, ty) elsif( ty.is_a?(Array) && (ty[0] < 0) ) return val.collect{|v| unsigned_value(v,ty[0])} else return val end end |
#assign_names(members) ⇒ Object
Set the names of the members
in this C struct
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/fiddle/struct.rb', line 278 def assign_names(members) @members = [] @nested_structs = {} members.each_with_index do |member, index| if member.is_a?(Array) # nested struct member_name = member[0] struct_type, struct_count = @ctypes[index] if struct_count.nil? struct = struct_type.new(to_i + @offset[index]) else structs = struct_count.times.map do |i| struct_type.new(to_i + @offset[index] + i * struct_type.size) end struct = StructArray.new(to_i + @offset[index], struct_type, structs) end @nested_structs[member_name] = struct else member_name = member end @members << member_name end end |
#set_ctypes(types) ⇒ Object
Calculates the offsets and sizes for the given types
in the struct.
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 |
# File 'lib/fiddle/struct.rb', line 304 def set_ctypes(types) @ctypes = types @offset = [] offset = 0 max_align = types.map { |type, count = 1| orig_offset = offset if type.respond_to?(:entity_class) align = type.alignment type_size = type.size else align = ALIGN_MAP[type] type_size = SIZE_MAP[type] end offset = PackInfo.align(orig_offset, align) @offset << offset offset += (type_size * count) align }.max @size = PackInfo.align(offset, max_align) end |
#to_s ⇒ Object
:nodoc:
434 435 436 |
# File 'lib/fiddle/struct.rb', line 434 def to_s() # :nodoc: super(@size) end |