ffi-bitfield 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/ffi/bit_field/layout.rb +17 -3
- data/lib/ffi/bit_field/property.rb +72 -13
- data/lib/ffi/bit_field/version.rb +2 -1
- data/lib/ffi/bit_field.rb +19 -1
- data/lib/ffi/bit_struct.rb +19 -1
- data/lib/ffi/managed_bit_struct.rb +22 -1
- metadata +3 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50775cc156bce79d4d20153303484ba80d19d23707d5413ea2557676260e8b38
|
4
|
+
data.tar.gz: 941e057d7cd548da1fd133f81143e573d7795c060d7678334c74cd1ed7cdaa31
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7329ad0a6bf66f580af0fdbbc3219774a53e7624a78e8e3891562150444282c0b2aae26b5eb4382edf8f67e27e66224aaf32592757f6e813105ab432a5e646a5
|
7
|
+
data.tar.gz: 3e4bb498d57114b6f9ccaf140d5789239609ff402f3be888d419fefa66957547659f1d5ab8577439f9fb98ad89fa6d56869f30a985b04486bc9bc90799c9b82a
|
data/README.md
CHANGED
@@ -99,7 +99,7 @@ bundle exec rake test
|
|
99
99
|
Your feedback is important.
|
100
100
|
|
101
101
|
ffi-bitfield is a library under development, so even small improvements like typofix are welcome! Please feel free to send us your pull requests.
|
102
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/
|
102
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/kojix2/ffi-bitfield.
|
103
103
|
|
104
104
|
Do you need commit rights to my repository?
|
105
105
|
Do you want to get admin rights and take over the project?
|
data/lib/ffi/bit_field/layout.rb
CHANGED
@@ -2,10 +2,24 @@
|
|
2
2
|
|
3
3
|
module FFI
|
4
4
|
module BitField
|
5
|
-
# Layout provides
|
5
|
+
# Layout provides methods for defining bit field layouts.
|
6
|
+
# This module is extended by BitStruct and ManagedBitStruct classes.
|
6
7
|
module Layout
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# Defines bit fields within a parent field.
|
9
|
+
#
|
10
|
+
# @param [Array] layout_args An array where the first element is the parent field name,
|
11
|
+
# followed by alternating field name and bit width pairs
|
12
|
+
# @return [Symbol] parent_name The name of the parent field
|
13
|
+
#
|
14
|
+
# @example Define bit fields in an 8-bit integer
|
15
|
+
# bit_fields :flags,
|
16
|
+
# :read, 1, # 1 bit for read permission
|
17
|
+
# :write, 1, # 1 bit for write permission
|
18
|
+
# :execute, 1, # 1 bit for execute permission
|
19
|
+
# :unused, 5 # 5 unused bits
|
20
|
+
#
|
21
|
+
# @note The total bit width should not exceed the size of the parent field.
|
22
|
+
# For example, a :uint8 field can hold at most 8 bits.
|
9
23
|
def bit_fields(*layout_args)
|
10
24
|
# The reason for using class instance variable here instead of class variable
|
11
25
|
# is not because class instance variables are clean,
|
@@ -2,36 +2,95 @@
|
|
2
2
|
|
3
3
|
module FFI
|
4
4
|
module BitField
|
5
|
-
#
|
5
|
+
# Property provides methods for reading and writing bit field values.
|
6
|
+
# This module is included in BitStruct and ManagedBitStruct classes.
|
6
7
|
module Property
|
7
|
-
#
|
8
|
-
#
|
8
|
+
# Reads a value from a bit field or regular field.
|
9
|
+
#
|
10
|
+
# @param [Symbol] member_name The name of the field to read
|
11
|
+
# @return [Integer] The value of the field
|
12
|
+
#
|
13
|
+
# @example Reading a bit field
|
14
|
+
# struct[:flag1] # => 1
|
9
15
|
def [](member_name)
|
10
16
|
parent_name, start, width = member_value_info(member_name)
|
11
17
|
if parent_name
|
12
18
|
value = get_member_value(parent_name)
|
13
|
-
value
|
19
|
+
(value >> start) & ((1 << width) - 1)
|
14
20
|
else
|
15
21
|
get_member_value(member_name)
|
16
22
|
end
|
17
23
|
end
|
18
24
|
|
25
|
+
# Writes a value to a bit field or regular field.
|
26
|
+
#
|
27
|
+
# @param [Symbol] member_name The name of the field to write
|
28
|
+
# @param [Integer] value The value to write
|
29
|
+
# @return [Integer] The written value
|
30
|
+
# @raise [ArgumentError] If the value is too large for the bit field
|
31
|
+
# @raise [ArgumentError] If the value is too small (negative) for the bit field
|
32
|
+
# @raise [ArgumentError] If the member name is not a valid bit field
|
33
|
+
# @raise [TypeError] If the value is not an Integer
|
34
|
+
#
|
35
|
+
# @example Writing to a bit field
|
36
|
+
# struct[:flag1] = 1
|
37
|
+
# @example Writing a negative value (bit-flipped)
|
38
|
+
# struct[:field] = -1 # Sets all bits to 1
|
19
39
|
def []=(member_name, value)
|
20
|
-
|
21
|
-
|
22
|
-
raise ArgumentError, "Value #{value} is larger than bit_length: #{width}" if value.bit_length > width
|
40
|
+
# Ensure value is an Integer
|
41
|
+
raise TypeError, "Value must be an Integer, got #{value.class}" unless value.is_a?(Integer)
|
23
42
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
43
|
+
# Get bit field information
|
44
|
+
field_info = member_value_info(member_name)
|
45
|
+
|
46
|
+
# If not a bit field, delegate to regular field setter
|
47
|
+
return set_member_value(member_name, value) unless field_info
|
48
|
+
|
49
|
+
# Extract bit field information
|
50
|
+
parent_name, start, width = field_info
|
51
|
+
|
52
|
+
# Calculate max value for this bit width
|
53
|
+
max_value = (1 << width) - 1
|
54
|
+
|
55
|
+
# Handle negative values by bit-flipping
|
56
|
+
if value.negative?
|
57
|
+
# For negative values, we interpret them as bit-flipped positive values
|
58
|
+
# For example, with 4 bits, -1 becomes 1111 (15), -2 becomes 1110 (14), etc.
|
59
|
+
|
60
|
+
# Check if the negative value is within range
|
61
|
+
# For bit-flipping, valid range is -(2^n) to -1
|
62
|
+
min_value = -(1 << width)
|
63
|
+
if value < min_value
|
64
|
+
raise ArgumentError, "Value #{value} is too small for bit_length: #{width}, minimum is #{min_value}"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Convert negative value to bit-flipped positive value
|
68
|
+
# -1 -> 15, -2 -> 14, etc.
|
69
|
+
value = max_value + value + 1
|
70
|
+
|
71
|
+
# Sanity check after conversion
|
72
|
+
if value.negative? || value > max_value
|
73
|
+
raise ArgumentError, "Internal error: converted value #{value} is out of range for bit_length: #{width}"
|
74
|
+
end
|
75
|
+
elsif value > max_value
|
76
|
+
# For positive values, check if they fit in the bit width
|
77
|
+
raise ArgumentError, "Value #{value} is too large for bit_length: #{width}, maximum is #{max_value}"
|
30
78
|
end
|
79
|
+
|
80
|
+
# Update the parent field with the new bit field value
|
81
|
+
parent_value = get_member_value(parent_name)
|
82
|
+
mask = ((1 << width) - 1) << start
|
83
|
+
new_value = (parent_value & ~mask) | ((value & ((1 << width) - 1)) << start)
|
84
|
+
|
85
|
+
set_member_value(parent_name, new_value)
|
31
86
|
end
|
32
87
|
|
33
88
|
private
|
34
89
|
|
90
|
+
# Gets information about a bit field member.
|
91
|
+
#
|
92
|
+
# @param [Symbol] member_name The name of the bit field
|
93
|
+
# @return [Array, nil] An array containing [parent_name, start_bit, width] or nil if not a bit field
|
35
94
|
def member_value_info(member_name)
|
36
95
|
self.class.instance_variable_get(:@bit_field_hash_table)[member_name]
|
37
96
|
end
|
data/lib/ffi/bit_field.rb
CHANGED
@@ -4,8 +4,26 @@ require_relative 'bit_field/version'
|
|
4
4
|
require_relative 'bit_struct'
|
5
5
|
require_relative 'managed_bit_struct'
|
6
6
|
|
7
|
+
# Foreign Function Interface module for Ruby.
|
8
|
+
# This is the main namespace for the Ruby-FFI library.
|
7
9
|
module FFI
|
8
|
-
#
|
10
|
+
# BitField provides bit field functionality for Ruby-FFI.
|
11
|
+
# It allows defining, reading, and writing bit fields within FFI structs.
|
12
|
+
#
|
13
|
+
# @example Basic usage
|
14
|
+
# class MyStruct < FFI::BitStruct
|
15
|
+
# layout \
|
16
|
+
# :flags, :uint8
|
17
|
+
#
|
18
|
+
# bit_fields :flags,
|
19
|
+
# :flag1, 1,
|
20
|
+
# :flag2, 1,
|
21
|
+
# :value, 6
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# struct = MyStruct.new
|
25
|
+
# struct[:flag1] = 1
|
26
|
+
# struct[:value] = 42
|
9
27
|
module BitField
|
10
28
|
end
|
11
29
|
end
|
data/lib/ffi/bit_struct.rb
CHANGED
@@ -6,7 +6,25 @@ require_relative 'bit_field/layout'
|
|
6
6
|
require_relative 'bit_field/property'
|
7
7
|
|
8
8
|
module FFI
|
9
|
-
# Subclass of FFI::Struct that
|
9
|
+
# Subclass of FFI::Struct that supports bit fields.
|
10
|
+
# Allows defining and accessing individual bits within integer fields.
|
11
|
+
#
|
12
|
+
# @example Define a struct with bit fields
|
13
|
+
# class Flags < FFI::BitStruct
|
14
|
+
# layout \
|
15
|
+
# :value, :uint8
|
16
|
+
#
|
17
|
+
# bit_fields :value,
|
18
|
+
# :read, 1, # 1 bit for read permission
|
19
|
+
# :write, 1, # 1 bit for write permission
|
20
|
+
# :execute, 1, # 1 bit for execute permission
|
21
|
+
# :unused, 5 # 5 unused bits
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# flags = Flags.new
|
25
|
+
# flags[:read] = 1
|
26
|
+
# flags[:write] = 1
|
27
|
+
# puts flags[:value] # => 3
|
10
28
|
class BitStruct < Struct
|
11
29
|
# [] is defined in FFI::Struct
|
12
30
|
alias get_member_value []
|
@@ -6,7 +6,28 @@ require_relative 'bit_field/layout'
|
|
6
6
|
require_relative 'bit_field/property'
|
7
7
|
|
8
8
|
module FFI
|
9
|
-
# Subclass of FFI::ManagedStruct that
|
9
|
+
# Subclass of FFI::ManagedStruct that supports bit fields.
|
10
|
+
# Combines memory management with bit field functionality.
|
11
|
+
#
|
12
|
+
# Use this class when you need automatic memory management for your structs
|
13
|
+
# with bit fields. You must implement the self.release method to handle
|
14
|
+
# memory cleanup.
|
15
|
+
#
|
16
|
+
# @example Define a managed struct with bit fields
|
17
|
+
# class ManagedFlags < FFI::ManagedBitStruct
|
18
|
+
# layout \
|
19
|
+
# :value, :uint8
|
20
|
+
#
|
21
|
+
# bit_fields :value,
|
22
|
+
# :read, 1,
|
23
|
+
# :write, 1,
|
24
|
+
# :execute, 1,
|
25
|
+
# :unused, 5
|
26
|
+
#
|
27
|
+
# def self.release(ptr)
|
28
|
+
# # Custom memory cleanup code
|
29
|
+
# end
|
30
|
+
# end
|
10
31
|
class ManagedBitStruct < ManagedStruct
|
11
32
|
# [] is defined in FFI::Struct
|
12
33
|
alias get_member_value []
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ffi-bitfield
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- kojix2
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-03-21 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: ffi
|
@@ -43,7 +42,6 @@ homepage: https://github.com/kojix2/ffi-bitfield
|
|
43
42
|
licenses:
|
44
43
|
- MIT
|
45
44
|
metadata: {}
|
46
|
-
post_install_message:
|
47
45
|
rdoc_options: []
|
48
46
|
require_paths:
|
49
47
|
- lib
|
@@ -58,8 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
58
56
|
- !ruby/object:Gem::Version
|
59
57
|
version: '0'
|
60
58
|
requirements: []
|
61
|
-
rubygems_version: 3.
|
62
|
-
signing_key:
|
59
|
+
rubygems_version: 3.6.2
|
63
60
|
specification_version: 4
|
64
61
|
summary: bit fields for Ruby-FFI
|
65
62
|
test_files: []
|