Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for nested structs #14

Closed
wants to merge 11 commits into from

Conversation

sinisterchipmunk
Copy link
Contributor

@sinisterchipmunk sinisterchipmunk commented Oct 30, 2018

This pull request does a few things. The main goal of the PR is to add support for nested structs and unions containing structs, as discussed in #12. I need this for a non-trivial project and have been using the nested struct code in numerous places within that project for several weeks now, so I am confident it is working properly. The syntax is a little strange, but works quite well, and is easy to learn. One could express the example given in #12 like so:

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

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

It is also possible to specify the nested struct in-line, by replacing StudentCollegeDetail with struct([...]), like so:

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

The hash does not need to appear last. In fact, its position in the list of members dictates the offset into the parent struct at which the nested struct appears, in order to play nicely with C structs. There can be multiple hashes, or a single hash with multiple keys/values, or any combination of these. The following examples are also valid syntax, but will result in the struct members being laid out at different offsets within the outer struct's memory:

# 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 (assuming ordered hash)
Rect = struct [ 'int id',
                {
                  position: struct(['float x', 'float y']),
                  dimensions: struct(['float w', 'float h'])
                }
              ]

Second: when calling Fiddle.malloc, the contents of the resulting memory were not initialized to 0 as they were when calling Fiddle::Pointer.malloc. This inconsistency caused me a few headaches so I decided to fix it.

Third: CStructEntity defines array set and get methods ([] / []=), which is fine except that they override Fiddle::Pointer#[] and Fiddle::Pointer#[]= and do not handle the 3rd argument that the base class allows for. I found that if I wanted to access the underlying memory of a struct directly, instead of working with the struct members, I had no good way to do that. So I modified these methods to check for an additional argument, and if present, delegate that to super so that the underlying memory could be accessed / assigned directly.

Fourth: When a member of a struct is an array, CStructEntity was returning a temporary array containing those values. Assignment to that array became a no-op, which was confusing. I fixed this so that assignment to the returned array correctly updates the member within the struct. (Example: a = struct(['int i[5]']).malloc; a.i[2] = 1; a.i[2] #=> 1)

I am happy to move these changes into multiple pull requests, or back out an undesirable change, if needed.

@sinisterchipmunk
Copy link
Contributor Author

@nobu Is there anything that I can do to help move this along?

@kematy
Copy link

kematy commented Jan 17, 2020

CADDRAW=struct ['long size',
'long dc',
{r:struct(['int left', 'int top','int right','int bottom'])},
'byte drawMode']
d:/Ruby25/lib/ruby/2.5.0/fiddle/cparser.rb:193:in compact': undefined method gsub' for {:r=>#Class:0x02b1b3e0}:Hash (NoMethodError)
from d:/Ruby25/lib/ruby/2.5.0/fiddle/cparser.rb:42:in block in parse_struct_signature' from d:/Ruby25/lib/ruby/2.5.0/fiddle/cparser.rb:41:in each'
from d:/Ruby25/lib/ruby/2.5.0/fiddle/cparser.rb:41:in parse_struct_signature' from d:/Ruby25/lib/ruby/2.5.0/fiddle/import.rb:219:in struct'
from D:/ruby-lab/caddll/caddll2019-11-6/Demos/View/DemoVB/test_fiddle-jh.rb:20:in `

'

Is {r:struct(['int left', 'int top','int right','int bottom'])} need to be added '.inspect'

@nobu
Copy link
Member

nobu commented Jan 17, 2020

Please split proposals for each “a few things.”

@nobu nobu closed this Jan 17, 2020
@kematy
Copy link

kematy commented Jan 17, 2020

CADDRAW=struct [
'long size',
'long dc',
{
r: struct([
'int left',
'int top',
'int right',
'int bottom'
])
},
'byte drawMode'
]
get same error msg

@sinisterchipmunk
Copy link
Contributor Author

@nobu I have split this PR into separate requests, as instructed. Hopefully this helps clarify the purpose of each proposal.

I also used the latest revision in master as the starting point to be sure of compatibility.

Please note that #27 depends on #26 and #26 depends on #25. I hope this is acceptable. #27 in particular would lose a lot of functionality around properly handling arrays if de-coupled from #26.

@kematy I do not fully understand your question, but I have seen that error message when Ruby tried to require the built-in version of Fiddle rather than the development version. Ruby only wants to load the built-in version, no matter what is specified in the project Gemfile. The built-in version lacks the proposed changes and so fails to parse with the error you listed. I am able to test Fiddle itself with no issues using bundle exec rake, but in order to use it from any other project I actually had to locally change fiddle's gem name, run rake install and then use the customized gem name with bundler. This makes Ruby think it's loading some other gem. I do get lots of warnings, however. For example, it correctly warns about constants that are created by fiddle and then replaced by my "fiddle-dev" gem.

@kematy
Copy link

kematy commented Jan 24, 2020 via email

@kematy
Copy link

kematy commented Jan 24, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants