Class: CTypes::Bitfield::Builder
- Inherits:
-
Object
- Object
- CTypes::Bitfield::Builder
- Includes:
- Helpers
- Defined in:
- lib/ctypes/bitfield/builder.rb
Overview
CTypes::Bitfield layout builder
This class is used to describe the memory layout of a CTypes::Bitfield type. There are two approaches provided here for describing the layout, the first is a constructive interface using #unsigned, #signed, #align, and #skip, to build the bitfield from right-to-left. These methods track how many bits have been used, and automatically determine the offset of fields as they’re declared.
The second interface is the programmatic interface that can be used to generate the CTypes::Bitfield layout from data. This uses #field to explicitly declare fields using bit size, offset, and signedness.
Instance Attribute Summary collapse
-
#offset ⇒ Object
readonly
get the offset of the next unused bit in the bitfield.
Instance Method Summary collapse
- #align(bits) ⇒ Object
-
#build ⇒ Bitfield
build a CTypes::Bitfield instance with the layout configured in this builder.
-
#bytes(n) ⇒ Object
set the size of the CTypes::Bitfield in bytes.
-
#endian(value) ⇒ Object
set the endian for this CTypes::Bitfield.
- #field(name, offset:, bits:, signed: false) ⇒ Object
-
#initialize ⇒ Builder
constructor
A new instance of Builder.
-
#result ⇒ Object
private
get the layout description for internal use in CTypes::Bitfield.
-
#signed(name, bits = 1) ⇒ Object
append a new signed field to the bitfield.
-
#skip(bits) ⇒ Object
skip ‘bits` bits in the layout of this bitfield.
-
#unsigned(name, bits = 1) ⇒ Object
append a new unsigned field to the bitfield.
Methods included from Helpers
#array, #bitfield, #bitmap, #enum, #string, #struct, #union
Constructor Details
#initialize ⇒ Builder
Returns a new instance of Builder.
58 59 60 61 62 63 64 65 |
# File 'lib/ctypes/bitfield/builder.rb', line 58 def initialize @fields = [] @schema = {} @default = {} @offset = 0 @layout = [] @max = 0 end |
Instance Attribute Details
#offset ⇒ Object (readonly)
get the offset of the next unused bit in the bitfield
68 69 70 |
# File 'lib/ctypes/bitfield/builder.rb', line 68 def offset @offset end |
Instance Method Details
#align(bits) ⇒ Object
136 137 138 139 140 141 142 |
# File 'lib/ctypes/bitfield/builder.rb', line 136 def align(bits) raise Error, "cannot mix `#align` and `#field` in Bitfield layout" unless @offset @offset += bits - (@offset % bits) @layout << "align #{bits}" self end |
#build ⇒ Bitfield
build a CTypes::Bitfield instance with the layout configured in this builder
72 73 74 75 76 |
# File 'lib/ctypes/bitfield/builder.rb', line 72 def build k = Class.new(Bitfield) k.send(:apply_layout, self) k end |
#bytes(n) ⇒ Object
set the size of the CTypes::Bitfield in bytes
Once the size is set, the Bitfield cannot grow past that size. Any calls to #signed or #unsigned that go beyond the size will raise errors.
195 196 197 198 199 |
# File 'lib/ctypes/bitfield/builder.rb', line 195 def bytes(n) @layout << "bytes #{n}" @max = n * 8 self end |
#endian(value) ⇒ Object
set the endian for this CTypes::Bitfield
104 105 106 107 |
# File 'lib/ctypes/bitfield/builder.rb', line 104 def endian(value) @endian = Endian[value] self end |
#field(name, offset:, bits:, signed: false) ⇒ Object
215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/ctypes/bitfield/builder.rb', line 215 def field(name, offset:, bits:, signed: false) name = name.to_sym raise Error, "duplicate field: %p" % [name] if @fields.any? { |(n, _)| n == name } @layout << "field %p, offset: %d, bits: %d, signed: %p" % [name, offset, bits, signed] @offset = nil __field_impl(name:, offset:, bits:, signed:) 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::Bitfield
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/ctypes/bitfield/builder.rb', line 80 def result dry_type = Dry::Types["coercible.hash"] .schema(@schema) .strict .default(@default.freeze) type = case @max when 0..8 UInt8 when 9..16 UInt16 when 17..32 UInt32 when 32..64 UInt64 else raise Error, "bitfields greater than 64 bits not supported" end [type, @fields, dry_type, @endian, @layout] end |
#signed(name, bits = 1) ⇒ Object
append a new signed field to the bitfield
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/ctypes/bitfield/builder.rb', line 169 def signed(name, bits = 1) unless @offset raise Error, "cannot mix `#signed` and `#field` in Bitfield layout" end name = name.to_sym raise Error, "duplicate field: %p" % [name] if @fields.any? { |(n, _)| n == name } @layout << ((bits == 1) ? "signed %p" % [name] : "signed %p, %d" % [name, bits]) __field_impl(name:, bits:, offset: @offset, signed: true) @offset += bits self end |
#skip(bits) ⇒ Object
skip ‘bits` bits in the layout of this bitfield
111 112 113 114 115 116 117 118 |
# File 'lib/ctypes/bitfield/builder.rb', line 111 def skip(bits) raise Error, "cannot mix `#skip` and `#field` in Bitfield layout" unless @offset @offset += bits @max = @offset if @offset > @max @layout << "skip #{bits}" self end |
#unsigned(name, bits = 1) ⇒ Object
append a new unsigned field to the bitfield
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/ctypes/bitfield/builder.rb', line 147 def unsigned(name, bits = 1) unless @offset raise Error, "cannot mix `#unsigned` and `#field` in Bitfield layout" end name = name.to_sym raise Error, "duplicate field: %p" % [name] if @fields.any? { |(n, _)| n == name } @layout << ((bits == 1) ? "unsigned %p" % [name] : "unsigned %p, %d" % [name, bits]) __field_impl(name:, bits:, offset: @offset, signed: false) @offset += bits self end |