Class: CTypes::Union::Builder
- Inherits:
-
Object
- Object
- CTypes::Union::Builder
- Includes:
- Helpers
- Defined in:
- lib/ctypes/union/builder.rb
Overview
CTypes::Union layout builder
This class is used to describe the memory layout of a CTypes::Union type. There are two approaches available for defining the layout, the declaritive approach used in ruby source files, or a programmatic approach that enables the construction of CTypes::Union types from data.
Instance Method Summary collapse
-
#build ⇒ Union
build a CTypes::Union instance with the layout configured in this builder.
-
#endian(value) ⇒ Object
set the endian of this union.
-
#initialize(type_lookup: CTypes.type_lookup) ⇒ Builder
constructor
A new instance of Builder.
-
#member(name, type = nil) ⇒ Object
declare a member in the union This function supports the use of Struct and CTypes::Union types for declaring unnamed fields (ISO C11).
-
#method_missing(name, *args, &block) ⇒ Object
used for custom type resolution.
-
#name(value) ⇒ Object
set the name of this union for use in pretty-printing.
- #result ⇒ Object private
-
#size(&block) ⇒ Object
Add a proc for determining Union size based on decoded bytes When unpacking a variable length CTypes::Union, the size proc is passed a frozen CTypes::Union instance with the entire input buffer.
Methods included from Helpers
#array, #bitfield, #bitmap, #enum, #string, #struct, #union
Constructor Details
#initialize(type_lookup: CTypes.type_lookup) ⇒ Builder
Returns a new instance of Builder.
60 61 62 63 64 65 66 67 |
# File 'lib/ctypes/union/builder.rb', line 60 def initialize(type_lookup: CTypes.type_lookup) @type_lookup = type_lookup @fields = [] @field_names = Set.new @schema = [] @size = 0 @fixed_size = true end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
used for custom type resolution
212 213 214 215 216 217 218 |
# File 'lib/ctypes/union/builder.rb', line 212 def method_missing(name, *args, &block) if @type_lookup && args.empty? && block.nil? type = @type_lookup.call(name) return type if type end super end |
Instance Method Details
#build ⇒ Union
build a CTypes::Union instance with the layout configured in this builder
71 72 73 74 75 |
# File 'lib/ctypes/union/builder.rb', line 71 def build k = Class.new(Union) k.send(:apply_layout, self) k end |
#endian(value) ⇒ Object
set the endian of this union
93 94 95 96 |
# File 'lib/ctypes/union/builder.rb', line 93 def endian(value) @endian = Endian[value] self end |
#member(name, type = nil) ⇒ Object
declare a member in the union This function supports the use of Struct and CTypes::Union types for declaring unnamed fields (ISO C11). See example below for more details.
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/ctypes/union/builder.rb', line 131 def member(name, type = nil) # named field if type name = name.to_sym @fields << [name, type].freeze @field_names << name @schema << Dry::Types::Schema::Key .new(type.dry_type.type, name, required: false) @default ||= {name => type.default_value} # unnamed field else type = name dry_keys = type.dry_type.keys or raise Error, "unsupported type for unnamed field: %p" % [type] names = dry_keys.map(&:name) if (duplicate = names.any? { |n| @field_names.include?(n) }) raise Error, "duplicate field name %p in unnamed field: %p" % [duplicate, type] end @fields << [names, type].freeze @field_names += names @schema += dry_keys.map do |key| # for all of the keys in the type, we need to create an equivalent # Key where the key is omittable. # # note: we strip the default value off the dry type here when defining # the schema for our own dry type. If we do not do this, `dry_type[{}]` # has every member in it, resulting in "only one member" error being # raised in Union.pack when the union is nested within a struct. # # Example: # struct(id: uint8, value: union(byte: uint8, word: uint32)) # .pack({value: byte: 1}) Dry::Types::Schema::Key.new(key.type.type, key.name, required: false) end @default ||= type.default_value end # fix up the size @size = type.size if @size.is_a?(Integer) && type.size > @size @fixed_size &&= type.fixed_size? self end |
#name(value) ⇒ Object
set the name of this union for use in pretty-printing
87 88 89 90 |
# File 'lib/ctypes/union/builder.rb', line 87 def name(value) @name = value.dup.freeze self end |
#result ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
78 79 80 81 82 83 84 |
# File 'lib/ctypes/union/builder.rb', line 78 def result dry_type = Dry::Types["coercible.hash"] .schema(@schema) .strict .default(@default.freeze) [@name, @fields.freeze, dry_type, @size, @fixed_size, @endian] end |
#size(&block) ⇒ Object
Add a proc for determining Union size based on decoded bytes When unpacking a variable length CTypes::Union, the size proc is passed a frozen CTypes::Union instance with the entire input buffer. The size proc will then unpack only those members it needs to calculate the total union size, and return the union size in bytes.
204 205 206 207 208 |
# File 'lib/ctypes/union/builder.rb', line 204 def size(&block) @fixed_size = false @size = block self end |