bit-struct 0.13.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/History.txt +102 -0
- data/README.txt +189 -0
- data/Rakefile +34 -0
- data/TODO +23 -0
- data/TODO-ALSO +71 -0
- data/examples/ara-player-data.rb +82 -0
- data/examples/bignum.rb +18 -0
- data/examples/bits.rb +19 -0
- data/examples/byte-bdy.rb +30 -0
- data/examples/field-ripper.rb +22 -0
- data/examples/fixed-point.rb +17 -0
- data/examples/ip.rb +81 -0
- data/examples/longlong.rb +30 -0
- data/examples/md.rb +23 -0
- data/examples/modular-def.rb +38 -0
- data/examples/native.rb +31 -0
- data/examples/nested.rb +33 -0
- data/examples/pad.rb +14 -0
- data/examples/ping-recv.rb +25 -0
- data/examples/ping.rb +73 -0
- data/examples/player-data.rb +75 -0
- data/examples/raw.rb +62 -0
- data/examples/rest.rb +30 -0
- data/examples/switch-endian.rb +49 -0
- data/examples/vector.rb +98 -0
- data/lib/bit-struct.rb +6 -0
- data/lib/bit-struct/bit-struct.rb +549 -0
- data/lib/bit-struct/char-field.rb +48 -0
- data/lib/bit-struct/fields.rb +273 -0
- data/lib/bit-struct/float-field.rb +61 -0
- data/lib/bit-struct/hex-octet-field.rb +20 -0
- data/lib/bit-struct/nested-field.rb +76 -0
- data/lib/bit-struct/octet-field.rb +45 -0
- data/lib/bit-struct/pad-field.rb +15 -0
- data/lib/bit-struct/signed-field.rb +258 -0
- data/lib/bit-struct/text-field.rb +44 -0
- data/lib/bit-struct/unsigned-field.rb +248 -0
- data/lib/bit-struct/vector-field.rb +77 -0
- data/lib/bit-struct/vector.rb +173 -0
- data/lib/bit-struct/yaml.rb +69 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- data/test/test-endian.rb +39 -0
- data/test/test-vector.rb +38 -0
- data/test/test.rb +433 -0
- metadata +126 -0
data/.gitignore
ADDED
data/History.txt
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
bit-struct 0.12
|
2
|
+
|
3
|
+
- Added vectors.
|
4
|
+
|
5
|
+
- BitStruct#initialize can take an IO argument.
|
6
|
+
|
7
|
+
bit-struct 0.11
|
8
|
+
|
9
|
+
- Allow unaligned fields to cross up to two byte boundaries.
|
10
|
+
See examples/byte-bdy.rb.
|
11
|
+
|
12
|
+
bit-struct 0.10
|
13
|
+
|
14
|
+
- Fixed a bug when calling #to_yaml on a BitStruct with a pad field. Thanks
|
15
|
+
to Jay Reitz for reporting it and providing the solution.
|
16
|
+
|
17
|
+
- Added BitStruct.default_options. Particularly useful for default endian
|
18
|
+
settings--see examples/native.rb.
|
19
|
+
|
20
|
+
- Fixed a bug that prevented warning about field name conflicts with
|
21
|
+
existing methods when the name is given as a symbol.
|
22
|
+
|
23
|
+
- Fixed point fields may now have fractional divisors (like :fixed => 0.001).
|
24
|
+
|
25
|
+
bit-struct 0.9
|
26
|
+
|
27
|
+
- Added examples/field-ripper.rb.
|
28
|
+
|
29
|
+
- Added BitStruct#field_by_name.
|
30
|
+
|
31
|
+
- Added more warnings about nested field accessors returning a *copy* of the
|
32
|
+
nested data.
|
33
|
+
|
34
|
+
- Added "pad" fields. See documentation in pad-field.rb and examples/pad.rb.
|
35
|
+
|
36
|
+
- The #initial_value method now yields the value to a block, if given.
|
37
|
+
|
38
|
+
- A BitStruct class is only closed when an instance is created. (After this
|
39
|
+
point no fields can be added.) Formerly, a class was closed when any method
|
40
|
+
requested the total length of the structure. This change makes it easier
|
41
|
+
to add groups of fields modularly, each with their own initial_value block.
|
42
|
+
|
43
|
+
- Added examples/modular-def.rb to explain how to factor a BitStruct
|
44
|
+
definition into modules.
|
45
|
+
|
46
|
+
bit-struct 0.8
|
47
|
+
|
48
|
+
- Signed fields can now (like unsigned fields) be any multiple of 8 bits, and are accessed as fixnums or bignums, as needed.
|
49
|
+
|
50
|
+
- It's easier to subclass BitStruct::OctetField. BitStruct::HexOctetField is now implemented in this way, just by defining three constants and two trivial class methods.
|
51
|
+
|
52
|
+
bit-struct 0.7
|
53
|
+
|
54
|
+
- BitStruct.describe now takes an option hash, and the :expand=>true option causes nested fields to be expanded in the description.
|
55
|
+
|
56
|
+
- Unsigned integer fields can now be any multiple of 8 bytes: 8, 16, 24, 32, 40, ... (Fields of 1..15 bits in length are of course still supported.)
|
57
|
+
|
58
|
+
- Added the :endian => :little option to signed integer, unsigned integer, and float fields. The full set of endian options is now [:little, :big, :network, :native]. The default is always :network.
|
59
|
+
|
60
|
+
- Option names may be strings or symbols. Values that can be symbols can also be strings.
|
61
|
+
|
62
|
+
- Added examples/bignum.rb.
|
63
|
+
|
64
|
+
- Added support for the YAML in ruby 1.8.2 (the YAML in 1.8.4 was already supported).
|
65
|
+
|
66
|
+
bit-struct 0.6
|
67
|
+
|
68
|
+
- Added the :endian => :native option for numerical fields (signed, unsigned, float).
|
69
|
+
|
70
|
+
- Fixed error message with 9..15 bit fields aligned on byte boundary.
|
71
|
+
|
72
|
+
- The #initial_value is now inherited (before applying defaults).
|
73
|
+
|
74
|
+
- New examples: raw.rb, native.rb.
|
75
|
+
|
76
|
+
bit-struct 0.5
|
77
|
+
|
78
|
+
- Integer fields may now cross byte boundaries, as long as the field fits within two whole bytes.
|
79
|
+
|
80
|
+
bit-struct 0.4
|
81
|
+
|
82
|
+
- Fixed a bug in reading text and char fields in YAML: if the value was interpreted by YAML as something other than a string, an error would result.
|
83
|
+
|
84
|
+
- When BitStructs are loaded from yaml, the key is treated as a setter method, rather than a field. This is useful in case there is a field that needs special setters to accept humanly readable input. (For example, a char field with length-prefixed subfields.)
|
85
|
+
|
86
|
+
bit-struct 0.3
|
87
|
+
|
88
|
+
- BitStruct classes are now YAML friendly.
|
89
|
+
|
90
|
+
- The default behavior of BitStruct#inspect and BitStruct#inspect_detailed is changed to print out the "rest" field, if any. This can be disabled by passing inspect an options hash with :include_rest => false. See BitStruct::DEFAULT_INSPECT_OPTS and BitStruct::DETAILED_INSPECT_OPTS. See examples/ip.rb and examples/rest.rb.
|
91
|
+
|
92
|
+
- The default behavior of BitStruct#to_h is changed to include the "rest" field. As above, this can be disabled by passing to_h an options hash with :include_rest => false.
|
93
|
+
|
94
|
+
- The default behavior of BitStruct#to_a is changed to include the "rest" field. As above, this can be disabled by passing false as an argument to to_a.
|
95
|
+
|
96
|
+
bit-struct 0.2
|
97
|
+
|
98
|
+
- first public release
|
99
|
+
|
100
|
+
bit-struct 0.1
|
101
|
+
|
102
|
+
- first release
|
data/README.txt
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
= BitStruct
|
2
|
+
|
3
|
+
Class for packed binary data stored in ruby Strings. BitStruct accessors, generated from user declared fields, use pack/unpack to treat substrings as fields with a specified portable format.
|
4
|
+
|
5
|
+
Field types include:
|
6
|
+
|
7
|
+
* signed and unsigned integer (1..16 bits, or 24, 32, 40, 48... bits)
|
8
|
+
|
9
|
+
* numeric fields (signed, unsigned, float) can be designated as any of the following endians: little, big, native, network (default)
|
10
|
+
|
11
|
+
* fixed point, with arbitrary scale factor
|
12
|
+
|
13
|
+
* fixed length character array
|
14
|
+
|
15
|
+
* null-terminated character array for printable text
|
16
|
+
|
17
|
+
* octets (hex and decimal representation options; useful for IP and MAC addrs)
|
18
|
+
|
19
|
+
* float
|
20
|
+
|
21
|
+
* nested BitStruct
|
22
|
+
|
23
|
+
* vectors of embedded BitStructs
|
24
|
+
|
25
|
+
* free-form "rest" field (e.g., for the variable-size payload of a packet)
|
26
|
+
|
27
|
+
Field options (specifiable as :foo => val or "foo" => val) include:
|
28
|
+
|
29
|
+
* *display_name*: used in BitStruct#inspect_detailed and BitStruct#describe outputs.
|
30
|
+
|
31
|
+
* *default*: default field value
|
32
|
+
|
33
|
+
* *format*: alternate format string for inspect
|
34
|
+
|
35
|
+
* *endian*: for byte ordering of numeric fields (unsigned, signed, float): little, big, native, network (default)
|
36
|
+
|
37
|
+
* *fixed*: float stored as fixed-point integer, with specified scale factor
|
38
|
+
|
39
|
+
|
40
|
+
== Installation
|
41
|
+
|
42
|
+
For .gem:
|
43
|
+
|
44
|
+
gem install bit-struct
|
45
|
+
|
46
|
+
For .tgz, unpack and then:
|
47
|
+
|
48
|
+
ruby install.rb config
|
49
|
+
ruby install.rb setup
|
50
|
+
ruby install.rb install
|
51
|
+
|
52
|
+
== Uses
|
53
|
+
|
54
|
+
BitStruct is useful for defining packets used in network protocols. This is especially useful for raw IP--see examples/ping-recv.rb. All multibyte numeric fields are stored by default in network order.
|
55
|
+
|
56
|
+
BitStruct is most efficient when your data is primarily treated as a binary string, and only secondarily treated as a data structure. (For instance, you are routing packets from one socket to another, possibly looking at one or two fields as it passes through or munging some headers.) If accessor operations are a bottleneck, a better approach is to define a class that wraps an array and uses pack/unpack when the object needs to behave like a binary string.
|
57
|
+
|
58
|
+
== Features
|
59
|
+
|
60
|
+
* Extensible with user-defined field classes.
|
61
|
+
|
62
|
+
* Fields are fully introspectable and can be defined programmatically.
|
63
|
+
|
64
|
+
* BitStruct.describe prints out documentation of all the fields of a BitStruct subclass, based on declarations. This is useful for communicating with developers who are not using ruby, but need to talk the same protocols. See Example, below.
|
65
|
+
|
66
|
+
* Fields are inherited by subclasses. (The free-form "rest" field does not inherit, because it usually represents a payload whose structure is defined in subclasses using the fixed-size fields.)
|
67
|
+
|
68
|
+
* BitStruct#inspect and BitStruct#inspect_detailed can be used for prettified display of contents. (More generally, BitStruct#inspect takes some options that control formatting and detail level.) See Example, below.
|
69
|
+
|
70
|
+
* BitStruct inherits from String, so all the usual methods are available, and string-sharing (copy-on-write) is in effect.
|
71
|
+
|
72
|
+
* Easy access to a "prototype" instance of each BitStruct subclass, from which all instances of that subclass are initialized as a copy (in the absence of other initialization parameters, such as a hash, a string, or a block). See BitStruct.initial_value, and BitStruct#initialize. See Example, below.
|
73
|
+
|
74
|
+
* Easy conversion to and from hashes, using BitStruct#to_h and BitStruct.new.
|
75
|
+
|
76
|
+
* BitStructs can persist using Marshal (a BitStruct is after all just a string) or using YAML (with human readable representation of the fields).
|
77
|
+
|
78
|
+
* Includes tests, examples, and rdoc API documentation.
|
79
|
+
|
80
|
+
== Limitations
|
81
|
+
|
82
|
+
* Fields that are not aligned on byte boundaries may cross no more than two bytes boundaries. (See examples/byte-bdy.rb.)
|
83
|
+
|
84
|
+
* No variable length fields (except the #rest field).
|
85
|
+
|
86
|
+
== Future plans
|
87
|
+
|
88
|
+
* Currently, the library is written in pure ruby. The implementation uses Array#pack and String#unpack calls, as well as shifting and masking in pure ruby. Future versions will optionally generate a customized C extension for better efficiency.
|
89
|
+
|
90
|
+
* A debug mode in which a class identifier is prepended to every BitStruct, so that protocol errors can be detected. (This feature has been implemented in an app that uses BitStruct, but needs to be refactored into the BitStruct library itself.)
|
91
|
+
|
92
|
+
* Remove field size and alignment limitations.
|
93
|
+
|
94
|
+
== Example
|
95
|
+
|
96
|
+
An IP packet can be defined and used like this:
|
97
|
+
|
98
|
+
require 'bit-struct'
|
99
|
+
|
100
|
+
class IP < BitStruct
|
101
|
+
unsigned :ip_v, 4, "Version"
|
102
|
+
unsigned :ip_hl, 4, "Header length"
|
103
|
+
unsigned :ip_tos, 8, "TOS"
|
104
|
+
unsigned :ip_len, 16, "Length"
|
105
|
+
unsigned :ip_id, 16, "ID"
|
106
|
+
unsigned :ip_off, 16, "Frag offset"
|
107
|
+
unsigned :ip_ttl, 8, "TTL"
|
108
|
+
unsigned :ip_p, 8, "Protocol"
|
109
|
+
unsigned :ip_sum, 16, "Checksum"
|
110
|
+
octets :ip_src, 32, "Source addr"
|
111
|
+
octets :ip_dst, 32, "Dest addr"
|
112
|
+
rest :body, "Body of message"
|
113
|
+
|
114
|
+
note " rest is application defined message body"
|
115
|
+
|
116
|
+
initial_value.ip_v = 4
|
117
|
+
initial_value.ip_hl = 5
|
118
|
+
end
|
119
|
+
|
120
|
+
ip = IP.new
|
121
|
+
ip.ip_tos = 0
|
122
|
+
ip.ip_len = 0
|
123
|
+
ip.ip_id = 0
|
124
|
+
ip.ip_off = 0
|
125
|
+
ip.ip_ttl = 255
|
126
|
+
ip.ip_p = 255
|
127
|
+
ip.ip_sum = 0
|
128
|
+
ip.ip_src = "192.168.1.4"
|
129
|
+
ip.ip_dst = "192.168.1.255"
|
130
|
+
ip.body = "This is the payload text."
|
131
|
+
ip.ip_len = ip.length
|
132
|
+
|
133
|
+
puts ip.inspect
|
134
|
+
puts "-"*50
|
135
|
+
puts ip.inspect_detailed
|
136
|
+
puts "-"*50
|
137
|
+
puts IP.describe
|
138
|
+
|
139
|
+
(Note that you can also construct an IP packet by passing a string to new, or by passing a hash of <tt>field,value</tt> pairs, or by providing a block that is yielded the new BitStruct.)
|
140
|
+
|
141
|
+
The output of this fragment is:
|
142
|
+
|
143
|
+
#<IP ip_v=4, ip_hl=5, ip_tos=0, ip_len=45, ip_id=0, ip_off=0, ip_ttl=255, ip_p=255, ip_sum=0, ip_src="192.168.1.4", ip_dst="192.168.1.255", body="This is the payload text.">
|
144
|
+
--------------------------------------------------
|
145
|
+
IP:
|
146
|
+
Version = 4
|
147
|
+
Header length = 5
|
148
|
+
TOS = 0
|
149
|
+
Length = 45
|
150
|
+
ID = 0
|
151
|
+
Frag offset = 0
|
152
|
+
TTL = 255
|
153
|
+
Protocol = 255
|
154
|
+
Checksum = 0
|
155
|
+
Source addr = "192.168.1.4"
|
156
|
+
Dest addr = "192.168.1.255"
|
157
|
+
Body of message = "This is the payload text."
|
158
|
+
--------------------------------------------------
|
159
|
+
|
160
|
+
Description of IP Packet:
|
161
|
+
byte: type name [size] description
|
162
|
+
----------------------------------------------------------------------
|
163
|
+
@0: unsigned ip_v [ 4b] Version
|
164
|
+
@0: unsigned ip_hl [ 4b] Header length
|
165
|
+
@1: unsigned ip_tos [ 8b] TOS
|
166
|
+
@2: unsigned ip_len [ 16b] Length
|
167
|
+
@4: unsigned ip_id [ 16b] ID
|
168
|
+
@6: unsigned ip_off [ 16b] Frag offset
|
169
|
+
@8: unsigned ip_ttl [ 8b] TTL
|
170
|
+
@9: unsigned ip_p [ 8b] Protocol
|
171
|
+
@10: unsigned ip_sum [ 16b] Checksum
|
172
|
+
@12: octets ip_src [ 32b] Source addr
|
173
|
+
@16: octets ip_dst [ 32b] Dest addr
|
174
|
+
rest is application defined message body
|
175
|
+
|
176
|
+
== Version
|
177
|
+
|
178
|
+
bit-struct 0.12
|
179
|
+
|
180
|
+
The current version of this software can be found at http://redshift.sourceforge.net/bit-struct.
|
181
|
+
|
182
|
+
== License
|
183
|
+
|
184
|
+
This software is distributed under the Ruby license. See http://www.ruby-lang.org.
|
185
|
+
|
186
|
+
== Author
|
187
|
+
|
188
|
+
Joel VanderWerf, mailto:vjoel@users.sourceforge.net
|
189
|
+
Copyright (c) 2005-2009, Joel VanderWerf.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bones'
|
7
|
+
Bones.setup
|
8
|
+
rescue LoadError
|
9
|
+
begin
|
10
|
+
load 'tasks/setup.rb'
|
11
|
+
rescue LoadError
|
12
|
+
raise RuntimeError, '### please install the "bones" gem ###'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ensure_in_path 'lib'
|
17
|
+
require 'bit-struct/bit-struct'
|
18
|
+
|
19
|
+
task :default => 'spec:run'
|
20
|
+
|
21
|
+
PROJ.name = 'bit-struct'
|
22
|
+
PROJ.authors = 'Joel VanderWerf'
|
23
|
+
PROJ.email = 'vjoel@users.sourceforge.net'
|
24
|
+
PROJ.url = 'http://rubyforge.org/projects/bit-struct/'
|
25
|
+
PROJ.version = BitStruct::VERSION
|
26
|
+
PROJ.rubyforge.name = 'bit-struct'
|
27
|
+
PROJ.summary = "Library for packed binary data stored in ruby Strings"
|
28
|
+
PROJ.description = <<END
|
29
|
+
Library for packed binary data stored in ruby Strings. Useful for accessing fields in network packets and binary files.
|
30
|
+
END
|
31
|
+
|
32
|
+
PROJ.spec.opts << '--color'
|
33
|
+
|
34
|
+
# EOF
|
data/TODO
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
website:
|
2
|
+
|
3
|
+
scp doc/ vjoel@rubyforge.org:/var/www/gforge-projects/bit-struct/
|
4
|
+
|
5
|
+
|
6
|
+
easy way to define wrappers
|
7
|
+
|
8
|
+
|
9
|
+
to do:
|
10
|
+
|
11
|
+
generate C code from bit-struct spec?
|
12
|
+
|
13
|
+
variable-length embedded fields, with referenced length field
|
14
|
+
|
15
|
+
terminated arrays?
|
16
|
+
|
17
|
+
use with mmap; in general: bit struct that references a position in another string or string-like object (e.g. a Mmap).
|
18
|
+
|
19
|
+
use require 'ipaddr'?
|
20
|
+
|
21
|
+
See ideas in
|
22
|
+
|
23
|
+
http://www.notwork.org/~gotoken/ruby/p/as-is/pack.rb
|
data/TODO-ALSO
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
rest :name, :terminator => ...
|
2
|
+
|
3
|
+
> * Allow block also for "nest" ?
|
4
|
+
>
|
5
|
+
> It may sound redundant in the first place, but when it's just for
|
6
|
+
> providing more structure without requiring an extra class definition, it
|
7
|
+
> could be useful:
|
8
|
+
>
|
9
|
+
> class Foo < BitStruct
|
10
|
+
> nest :coord do
|
11
|
+
> signed :x, 8
|
12
|
+
> signed :y, 8
|
13
|
+
> end
|
14
|
+
> end
|
15
|
+
>
|
16
|
+
> Foo.new.coord.x
|
17
|
+
|
18
|
+
Agree completely.
|
19
|
+
|
20
|
+
> * Is explicit :length for vector necessary?
|
21
|
+
>
|
22
|
+
> class Tag < BitStruct
|
23
|
+
> signed :flags, 32
|
24
|
+
> vector :axis, Vec, :length => 3
|
25
|
+
> end
|
26
|
+
>
|
27
|
+
> compared to
|
28
|
+
>
|
29
|
+
> class Tag < BitStruct
|
30
|
+
> signed :flags, 32
|
31
|
+
> vector :axis, Vec, 3
|
32
|
+
> end
|
33
|
+
>
|
34
|
+
> Or am I missing any ambiguities because of the simple cases?
|
35
|
+
|
36
|
+
Nothing ambiguous, I just get giddy when there are too many positional args. But since length is required, it does make sense to pass it as a positional arg. I'll change that...
|
37
|
+
|
38
|
+
> * Allow length not only in bits, but also bytes?
|
39
|
+
>
|
40
|
+
> In my cases I've never encountered a situation where I needed a member
|
41
|
+
> of a structure to represent anything which is not on a byte boundary.
|
42
|
+
|
43
|
+
Sigh, if only life we always like that. There's a reason I call the library _bit_-struct :)
|
44
|
+
|
45
|
+
> All my signed and unsigned int have to read "32" (32bit, 4bytes) all
|
46
|
+
> over the place. For strings I'm writing "64*8" for string with 64
|
47
|
+
> characters.
|
48
|
+
>
|
49
|
+
> How about a new default_option :granularity which is "1" by default.
|
50
|
+
> When set to "8", every specified length (except for vector ...) is
|
51
|
+
> multiplied by that factor before used?
|
52
|
+
|
53
|
+
Hm, will think about that. I wish I could define Fixnum#bytes, but only in the context of field declarations in a BitStruct subclass.
|
54
|
+
|
55
|
+
I don't like granularity because it's really only meaningful if the value is 1 or 8. Perhaps :granularity => :bit, or :granularity => :byte. But I still don't like an option that you have to keep in mind to understand whether
|
56
|
+
|
57
|
+
char :x, 80
|
58
|
+
|
59
|
+
is 8 or 80 chars. It's too much context sensitivity.
|
60
|
+
|
61
|
+
What about
|
62
|
+
|
63
|
+
signed :x, bytes(4)
|
64
|
+
|
65
|
+
Is that too clunky? It would be trivial to implement...
|
66
|
+
|
67
|
+
> * Why "vector" and not just "array"?
|
68
|
+
|
69
|
+
For consistency with things like NArray, which has Vector, Matrix, and Array classes, where vectors are essentially one-dim arrays.
|
70
|
+
|
71
|
+
Also, "array" might lead to confusion with ruby arrays.
|
@@ -0,0 +1,82 @@
|
|
1
|
+
class PlayerData
|
2
|
+
class << self
|
3
|
+
def create(*a)
|
4
|
+
new(a.pack(FORMAT))
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
SPEC = [
|
9
|
+
%w( pid i ),
|
10
|
+
%w( x_position f ),
|
11
|
+
%w( y_position f ),
|
12
|
+
%w( z_position f ),
|
13
|
+
%w( foobar i ),
|
14
|
+
]
|
15
|
+
|
16
|
+
ATTRIBUTES = SPEC.map{|s| s.first}
|
17
|
+
|
18
|
+
FORMAT = SPEC.map{|s| s.last}.join
|
19
|
+
|
20
|
+
SPEC.each_with_index do |spec, ix|
|
21
|
+
at, format = spec
|
22
|
+
eval <<-src
|
23
|
+
def #{ at }
|
24
|
+
@#{ at } ||= @data[#{ ix }]
|
25
|
+
end
|
26
|
+
def #{ at }= value
|
27
|
+
raise TypeError unless self.#{ at }.class == value.class
|
28
|
+
uncache
|
29
|
+
@#{ at } = @data[#{ ix }] = value
|
30
|
+
end
|
31
|
+
src
|
32
|
+
end
|
33
|
+
|
34
|
+
def update buffer
|
35
|
+
uncache
|
36
|
+
@data = buffer.unpack FORMAT
|
37
|
+
end
|
38
|
+
alias initialize update
|
39
|
+
def uncache
|
40
|
+
@to_s = @to_bin = nil
|
41
|
+
end
|
42
|
+
def to_s
|
43
|
+
@to_s ||= ATTRIBUTES.inject(''){|s,a| s << "#{ a } : #{ send a }, " }.chop.chop
|
44
|
+
end
|
45
|
+
def to_bin
|
46
|
+
@to_bin ||= @data.pack(FORMAT)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
id, x_position, y_position, z_position, foobar =
|
51
|
+
400, 1.0, 2.0, 3.0, 0b101010
|
52
|
+
|
53
|
+
pd = PlayerData::create id, x_position, y_position, z_position, foobar
|
54
|
+
|
55
|
+
p pd
|
56
|
+
p pd.pid
|
57
|
+
p pd.x_position
|
58
|
+
p pd.foobar
|
59
|
+
puts pd
|
60
|
+
|
61
|
+
begin
|
62
|
+
require 'timeout'
|
63
|
+
n = 0
|
64
|
+
sec = 10
|
65
|
+
Timeout::timeout(sec) do
|
66
|
+
loop do
|
67
|
+
PlayerData::create id, x_position, y_position, z_position, foobar
|
68
|
+
n += 1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
rescue Timeout::Error
|
72
|
+
puts "creations per second : #{ n / sec }"
|
73
|
+
end
|
74
|
+
|
75
|
+
__END__
|
76
|
+
|
77
|
+
#<PlayerData:0xb7e29b7c @to_s=nil, @data=[400, 1.0, 2.0, 3.0, 42], @to_bin=nil>
|
78
|
+
400
|
79
|
+
1.0
|
80
|
+
42
|
81
|
+
pid : 400, x_position : 1.0, y_position : 2.0, z_position : 3.0, foobar : 42
|
82
|
+
creations per second : 131746
|