Class: CTypes::Struct::Builder
- Inherits:
-
Object
- Object
- CTypes::Struct::Builder
- Includes:
- Helpers
- Defined in:
- lib/ctypes/struct/builder.rb
Overview
CTypes::Struct layout builder
This class is used to describe the memory layout of a CTypes::Struct 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::Struct types from data.
Instance Method Summary collapse
-
#attribute(name, type = nil) ⇒ Object
declare an attribute in the structure This function supports the use of CTypes::Struct and Union types for declaring unnamed fields (ISO C11).
-
#build ⇒ Struct
build a CTypes::Struct instance with the layout configured in this builder.
-
#endian(value) ⇒ Object
set the endian of this structure.
-
#initialize(type_lookup: CTypes.type_lookup) ⇒ Builder
constructor
A new instance of Builder.
-
#method_missing(name, *args, &block) ⇒ Object
used for custom type resolution.
-
#name(value) ⇒ Object
set the name of this structure for use in pretty-printing.
-
#pad(bytes) ⇒ Object
allocate unused bytes in the CTypes::Struct This method is used to enforce alignment of other fields, or accurately mimic padding added in C structs by the compiler.
-
#result ⇒ Object
private
get the layout description for internal use in CTypes::Struct.
-
#size(&block) ⇒ Object
Add a proc for determining struct size based on decoded bytes When unpacking variable length CTypes::Structs, we unpack each attribute in order of declaration until we encounter a field that has a variable-length type.
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.
63 64 65 66 67 68 69 |
# File 'lib/ctypes/struct/builder.rb', line 63 def initialize(type_lookup: CTypes.type_lookup) @type_lookup = type_lookup @fields = [] @schema = [] @default = {} @bytes = 0 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
234 235 236 237 238 239 240 |
# File 'lib/ctypes/struct/builder.rb', line 234 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
#attribute(name, type = nil) ⇒ Object
declare an attribute in the structure This function supports the use of CTypes::Struct and Union types for declaring unnamed fields (ISO C11). See example below for more details.
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 178 |
# File 'lib/ctypes/struct/builder.rb', line 141 def attribute(name, type = nil) # handle a named field if type name = name.to_sym if @default.has_key?(name) raise Error, "duplicate field name: %p" % name end @fields << [name, type] @schema << Dry::Types::Schema::Key.new(type.dry_type, name) @default[name] = type.default_value # handle the unnamed field by adding the child fields to our type 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| @default.has_key?(n) }) raise Error, "duplicate field name %p in unnamed field: %p" % [duplicate, type] end @fields << [names, type] @schema += dry_keys @default.merge!(type.default_value) end # adjust the byte count for this type if @bytes && type.fixed_size? @bytes += type.size else @bytes = nil end self end |
#build ⇒ Struct
build a CTypes::Struct instance with the layout configured in this builder
73 74 75 76 77 |
# File 'lib/ctypes/struct/builder.rb', line 73 def build k = Class.new(Struct) k.send(:apply_layout, self) k end |
#endian(value) ⇒ Object
set the endian of this structure
96 97 98 99 |
# File 'lib/ctypes/struct/builder.rb', line 96 def endian(value) @endian = Endian[value] self end |
#name(value) ⇒ Object
set the name of this structure for use in pretty-printing
90 91 92 93 |
# File 'lib/ctypes/struct/builder.rb', line 90 def name(value) @name = value.dup.freeze self end |
#pad(bytes) ⇒ Object
allocate unused bytes in the CTypes::Struct This method is used to enforce alignment of other fields, or accurately mimic padding added in C structs by the compiler.
221 222 223 224 225 226 227 228 229 230 |
# File 'lib/ctypes/struct/builder.rb', line 221 def pad(bytes) pad = Pad.new(bytes) # we use the Pad instance as the name of the field so Struct knows to # treat the field as padding @fields << [pad, pad] @bytes += bytes if @bytes 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.
get the layout description for internal use in CTypes::Struct
81 82 83 84 85 86 87 |
# File 'lib/ctypes/struct/builder.rb', line 81 def result dry_type = Dry::Types["coercible.hash"] .schema(@schema) .strict .default(@default.freeze) [@name, @fields.freeze, dry_type, @size || @bytes, @endian] end |
#size(&block) ⇒ Object
Add a proc for determining struct size based on decoded bytes When unpacking variable length CTypes::Structs, we unpack each attribute in order of declaration until we encounter a field that has a variable-length type. At that point, we call the block provided to #size do determine the total size of the struct. The block will receive a single argument, which is an incomplete unpacking of the CTypes::Struct, containing only those fixed-length fields that have been unpacked so far. The block can access unpacked fields using CTypes::Struct#[]. Using the unpacked fields, the block must return the total size of the struct in bytes.
204 205 206 207 |
# File 'lib/ctypes/struct/builder.rb', line 204 def size(&block) @size = block self end |