Skip to content
Closed
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
51 changes: 51 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,57 @@ floor = Fiddle::Function.new(
puts floor.call(3.14159) #=> 3.0
```

### Nested Structs

You can use hashes to create nested structs, where the hash keys are member names and the values are the nested structs:

```ruby
StudentCollegeDetail = struct [
'int college_id',
'char college_name[50]'
]

StudentDetail = struct [
'int id',
'char name[20]',
{ clg_data: StudentCollegeDetail }
]
```

You can also specify an anonymous nested struct, like so:

```ruby
StudentDetail = struct [
'int id',
'char name[20]',
{
clg_data: struct([
'int college_id',
'char college_name[50]'
])
}
]
```

The position of a hash (and the order of the keys in the hash, in the case of a hash with multiple entries), dictate the offsets of the nested struct in memory. The following examples are both syntactically valid but will lay out the structs differently in memory:

```ruby
# order of members in memory: position, id, dimensions
Rect = struct [ { position: struct(['float x', 'float y']) },
'int id',
{ dimensions: struct(['float w', 'float h']) }
]

# order of members in memory: id, position, dimensions
Rect = struct [ 'int id',
{
position: struct(['float x', 'float y']),
dimensions: struct(['float w', 'float h'])
}
]
```


## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down
5 changes: 3 additions & 2 deletions ext/fiddle/fiddle.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ static VALUE
rb_fiddle_malloc(VALUE self, VALUE size)
{
void *ptr;

ptr = (void*)ruby_xmalloc(NUM2SIZET(size));
size_t sizet = NUM2SIZET(size);
ptr = (void*)ruby_xmalloc(sizet);
memset(ptr, 0, sizet);
return PTR2NUM(ptr);
}

Expand Down
22 changes: 22 additions & 0 deletions ext/fiddle/pointer.c
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,27 @@ rb_fiddle_ptr_size_get(VALUE self)
return LONG2NUM(RPTR_DATA(self)->size);
}

/*
* call-seq: memcpy
*
* Copies the contents of the given pointer into this one. Will copy up to the
* allocated size of the given pointer or the allocated size of this one,
* whichever is smaller (to prevent overflow).
*
* Returns the number of bytes actually copied.
*/
static VALUE
rb_fiddle_ptr_memcpy(VALUE self, VALUE other)
{
long self_size = NUM2LONG(rb_funcall(self, rb_intern("size"), 0));
long other_size = NUM2LONG(rb_funcall(other, rb_intern("size"), 0));
void *self_ptr = NUM2PTR(rb_fiddle_ptr_to_i(self));
void *other_ptr = NUM2PTR(rb_fiddle_ptr_to_i(other));
long size = self_size > other_size ? other_size : self_size;
memcpy(self_ptr, other_ptr, size);
return LONG2NUM(size);
}

/*
* call-seq:
* Fiddle::Pointer[val] => cptr
Expand Down Expand Up @@ -713,6 +734,7 @@ Init_fiddle_pointer(void)
rb_define_method(rb_cPointer, "[]=", rb_fiddle_ptr_aset, -1);
rb_define_method(rb_cPointer, "size", rb_fiddle_ptr_size_get, 0);
rb_define_method(rb_cPointer, "size=", rb_fiddle_ptr_size_set, 1);
rb_define_method(rb_cPointer, "memcpy", rb_fiddle_ptr_memcpy, 1);

/* Document-const: NULL
*
Expand Down
22 changes: 21 additions & 1 deletion lib/fiddle/cparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,32 @@ module CParser
def parse_struct_signature(signature, tymap=nil)
if signature.is_a?(String)
signature = split_arguments(signature, /[,;]/)
elsif signature.kind_of?(Hash)
signature = [signature]
elsif signature.respond_to?(:types) && signature.respond_to?(:members)
return signature.types, signature.members, signature.entity_class
end
mems = []
tys = []
signature.each{|msig|
msig = compact(msig)
msig = compact(msig) if msig.is_a?(String)
case msig
when Hash
msig.each do |structure_name, struct_signature|
structure_count = nil
if structure_name.to_s =~ /^([\w\*\s]+)\[(\d+)\]$/
structure_count = $2.to_i
structure_name = $1
end
structure_parsed = parse_struct_signature(struct_signature, tymap)
structure_types = structure_parsed[0]
structure_members = structure_parsed[1]
structure_klass = structure_parsed[2]
ty = [structure_types, structure_count]
ty << structure_klass if structure_klass
mems.push([structure_name.to_s, structure_members])
tys.push(ty)
end
when /^[\w\*\s]+[\*\s](\w+)$/
mems.push($1)
tys.push(parse_ctype(msig, tymap))
Expand Down
Loading