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
Instance Attribute Summary
Attributes inherited from Pointer
Class Method Summary collapse
- .alignment(types) ⇒ Object
-
.malloc(types, func = nil, size = size(types)) ⇒ 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
- #+(delta) ⇒ Object
- #-(delta) ⇒ Object
-
#[](*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?, from_native, #inspect, #null?, #ptr, read, #ref, #size, #size=, #to_i, to_native, #to_ptr, 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
353 354 355 356 357 358 359 |
# File 'lib/fiddle/struct.rb', line 353 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)) ⇒ 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 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/fiddle/struct.rb', line 293 def CStructEntity.malloc(types, func = nil, size = size(types)) if block_given? and func.nil? = "a free function must be supplied to #{self}.malloc " + "when it is called with a block" raise ArgumentError, end pointer = Pointer.malloc(size) begin struct = new(pointer, types, func) rescue pointer.free = func pointer.call_free raise end if block_given? begin yield(struct) ensure struct.call_free end else struct end end |
.size(types) ⇒ Object
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 |
# File 'lib/fiddle/struct.rb', line 326 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
#+(delta) ⇒ Object
522 523 524 |
# File 'lib/fiddle/struct.rb', line 522 def +(delta) Pointer.new(to_i + delta, @size - delta) end |
#-(delta) ⇒ Object
526 527 528 |
# File 'lib/fiddle/struct.rb', line 526 def -(delta) Pointer.new(to_i - delta, @size + delta) end |
#[](*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
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 453 454 455 456 457 458 459 460 461 462 463 464 465 |
# File 'lib/fiddle/struct.rb', line 426 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
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 503 504 505 506 507 508 509 510 511 512 513 514 515 |
# File 'lib/fiddle/struct.rb', line 478 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
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'lib/fiddle/struct.rb', line 362 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.
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 |
# File 'lib/fiddle/struct.rb', line 388 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:
518 519 520 |
# File 'lib/fiddle/struct.rb', line 518 def to_s() # :nodoc: super(@size) end |