如何对使用联合体的C结构建模以实现Go绑定?

huangapple go评论135阅读模式
英文:

How to model Go bindings to C structs that use unions?

问题

我目前正在为libfreefare编写一个Go封装器,libfreefare的API包含以下函数:

  1. type mifare_desfire_file_settings struct {
  2. file_type uint8
  3. communication_settings uint8
  4. access_rights uint16
  5. settings struct {
  6. standard_file struct {
  7. file_size uint32
  8. }
  9. value_file struct {
  10. lower_limit int32
  11. upper_limit int32
  12. limited_credit_value int32
  13. limited_credit_enabled uint8
  14. }
  15. linear_record_file struct {
  16. record_size uint32
  17. max_number_of_records uint32
  18. current_number_of_records uint32
  19. }
  20. }
  21. }
  22. func mifare_desfire_get_file_settings(tag MifareTag, file_no uint8, settings *mifare_desfire_file_settings) int

如果struct mifare_desfire_file_settings不包含任何联合体,我的封装器可能会像这样:

  1. type DESFireFileSettings struct {
  2. // 所有字段都是公开的,没有方法
  3. }
  4. func (t DESFireTag) FileSettings(fileNo byte) (DESFireFileSettings, error)

你应该如何继续?

英文:

I'm currently writing a Go wrapper for the libfreefare. The API of the libfreefare contains the following function:

  1. struct mifare_desfire_file_settings {
  2. uint8_t file_type;
  3. uint8_t communication_settings;
  4. uint16_t access_rights;
  5. union {
  6. struct {
  7. uint32_t file_size;
  8. } standard_file;
  9. struct {
  10. int32_t lower_limit;
  11. int32_t upper_limit;
  12. int32_t limited_credit_value;
  13. uint8_t limited_credit_enabled;
  14. } value_file;
  15. struct {
  16. uint32_t record_size;
  17. uint32_t max_number_of_records;
  18. uint32_t current_number_of_records;
  19. } linear_record_file;
  20. } settings;
  21. };
  22. int mifare_desfire_get_file_settings (MifareTag tag, uint8_t file_no, struct mifare_desfire_file_settings *settings);

What is the ideomatic solution for wrapping such a function? If the struct mifare_desfire_file_settings wouldn't contain any unions, my wrapper would probably look like this:

  1. type DESFireFileSettings struct {
  2. // all fields exported, no methods
  3. }
  4. func (t DESFireTag) FileSettings(fileNo byte) (DESFireFileSettings, error)

How should I proceed?

答案1

得分: 2

你需要考虑如何更新联合体中的字段。显然,你不能让用户在没有验证的情况下进行更新,否则可能会导致不一致的更新。考虑像这样做:

  1. package mifare
  2. const (
  3. MDFTStandarDataFile = 0x00
  4. MDFTBackupDataFile = 0x01
  5. MDFTValueFileWithBackup = 0x02
  6. MDFTLinearRecordFileWithBackup = 0x03
  7. MDFTCyclicRecordFileWithBackup = 0x04
  8. )
  9. type StandardFile struct {
  10. FileSize uint32
  11. }
  12. type ValueFile struct {
  13. LowerLimit int32
  14. UpperLimit int32
  15. LimitedCreditValue int32
  16. LimitedCreditEnabled uint8
  17. }
  18. type LinearRecordFile struct {
  19. Record_size uint32
  20. MaxNumberOfRecords uint32
  21. CurrentNumberOfRecords uint32
  22. }
  23. type DESFireFileSettings struct {
  24. FileType uint8
  25. CommunicationSettings uint8
  26. AccessRights uint16
  27. settings struct {
  28. StandardFile
  29. ValueFile
  30. LinearRecordFile
  31. }
  32. }
  33. func (fs *DESFireFileSettings) StandardFile() (StandardFile, error) {
  34. // 如果FileType无效,返回错误
  35. return fs.settings.StandardFile, nil
  36. }
  37. func (fs *DESFireFileSettings) SetStandardFile(standardFile StandardFile) error {
  38. // 如果FileType无效,返回错误
  39. fs.settings.StandardFile = standardFile
  40. return nil
  41. }
  42. func (fs *DESFireFileSettings) ValueFile() (ValueFile, error) {
  43. // 如果FileType无效,返回错误
  44. return fs.settings.ValueFile, nil
  45. }
  46. func (fs *DESFireFileSettings) SetValueFile(valueFile ValueFile) error {
  47. // 如果FileType无效,返回错误
  48. fs.settings.ValueFile = valueFile
  49. return nil
  50. }
  51. func (fs *DESFireFileSettings) LinearRecordFile() (LinearRecordFile, error) {
  52. // 如果FileType无效,返回错误
  53. return fs.settings.LinearRecordFile, nil
  54. }
  55. func (fs *DESFireFileSettings) SetLinearRecordFile(linearRecordFile LinearRecordFile) error {
  56. // 如果FileType无效,返回错误
  57. fs.settings.LinearRecordFile = linearRecordFile
  58. return nil
  59. }

以上是对代码的翻译。

英文:

You need to consider how you would update fields in the union. Obviously, you can't let users do that without validation. They could do inconsistent updates. Consider doing something like this:

  1. package mifare
  2. const (
  3. MDFTStandarDataFile = 0x00
  4. MDFTBackupDataFile = 0x01
  5. MDFTValueFileWithBackup = 0x02
  6. MDFTLinearRecordFileWithBackup = 0x03
  7. MDFTCyclicRecordFileWithBackup = 0x04
  8. )
  9. type StandardFile struct {
  10. FileSize uint32
  11. }
  12. type ValueFile struct {
  13. LowerLimit int32
  14. UpperLimit int32
  15. LimitedCreditValue int32
  16. LimitedCreditEnabled uint8
  17. }
  18. type LinearRecordFile struct {
  19. Record_size uint32
  20. MaxNumberOfRecords uint32
  21. CurrentNumberOfRecords uint32
  22. }
  23. type DESFireFileSettings struct {
  24. FileType uint8
  25. CommunicationSettings uint8
  26. AccessRights uint16
  27. settings struct {
  28. StandardFile
  29. ValueFile
  30. LinearRecordFile
  31. }
  32. }
  33. func (fs *DESFireFileSettings) StandardFile() (StandardFile, error) {
  34. // if not valid for FileType, return error
  35. return fs.settings.StandardFile, nil
  36. }
  37. func (fs *DESFireFileSettings) SetStandardFile(standardFile StandardFile) error {
  38. // if not valid for FileType, return error
  39. fs.settings.StandardFile = standardFile
  40. return nil
  41. }
  42. func (fs *DESFireFileSettings) ValueFile() (ValueFile, error) {
  43. // if not valid for FileType, return error
  44. return fs.settings.ValueFile, nil
  45. }
  46. func (fs *DESFireFileSettings) SetValueFile(valueFile ValueFile) error {
  47. // if not valid for FileType, return error
  48. fs.settings.ValueFile = valueFile
  49. return nil
  50. }
  51. func (fs *DESFireFileSettings) LinearRecordFile() (LinearRecordFile, error) {
  52. // if not valid for FileType, return error
  53. return fs.settings.LinearRecordFile, nil
  54. }
  55. func (fs *DESFireFileSettings) SetLinearRecordFile(linearRecordFile LinearRecordFile) error {
  56. // if not valid for FileType, return error
  57. fs.settings.LinearRecordFile = linearRecordFile
  58. return nil
  59. }

huangapple
  • 本文由 发表于 2014年4月6日 07:03:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/22888001.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定