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, read, #ref, #size, #size=, #to_i, #to_int, to_ptr, #to_str, #to_value, write
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
340 341 342 343 344 345 346 |
# File 'lib/fiddle/struct.rb', line 340 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
277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/fiddle/struct.rb', line 277 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.
293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'lib/fiddle/struct.rb', line 293 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
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 |
# File 'lib/fiddle/struct.rb', line 313 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
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 |
# File 'lib/fiddle/struct.rb', line 413 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
465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/fiddle/struct.rb', line 465 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
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/fiddle/struct.rb', line 349 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.
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/fiddle/struct.rb', line 375 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:
505 506 507 |
# File 'lib/fiddle/struct.rb', line 505 def to_s() # :nodoc: super(@size) end |