cassandra-driver 1.0.0.beta.2-java

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.
Files changed (118) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +4 -0
  3. data/README.md +125 -0
  4. data/lib/cassandra/auth/providers/password.rb +73 -0
  5. data/lib/cassandra/auth/providers.rb +16 -0
  6. data/lib/cassandra/auth.rb +97 -0
  7. data/lib/cassandra/client/batch.rb +212 -0
  8. data/lib/cassandra/client/client.rb +591 -0
  9. data/lib/cassandra/client/column_metadata.rb +54 -0
  10. data/lib/cassandra/client/connection_manager.rb +72 -0
  11. data/lib/cassandra/client/connector.rb +277 -0
  12. data/lib/cassandra/client/execute_options_decoder.rb +59 -0
  13. data/lib/cassandra/client/null_logger.rb +37 -0
  14. data/lib/cassandra/client/peer_discovery.rb +50 -0
  15. data/lib/cassandra/client/prepared_statement.rb +314 -0
  16. data/lib/cassandra/client/query_result.rb +230 -0
  17. data/lib/cassandra/client/request_runner.rb +71 -0
  18. data/lib/cassandra/client/result_metadata.rb +48 -0
  19. data/lib/cassandra/client/void_result.rb +78 -0
  20. data/lib/cassandra/client.rb +144 -0
  21. data/lib/cassandra/cluster/client.rb +768 -0
  22. data/lib/cassandra/cluster/connector.rb +244 -0
  23. data/lib/cassandra/cluster/control_connection.rb +425 -0
  24. data/lib/cassandra/cluster/metadata.rb +124 -0
  25. data/lib/cassandra/cluster/options.rb +42 -0
  26. data/lib/cassandra/cluster/registry.rb +198 -0
  27. data/lib/cassandra/cluster/schema/partitioners/murmur3.rb +47 -0
  28. data/lib/cassandra/cluster/schema/partitioners/ordered.rb +37 -0
  29. data/lib/cassandra/cluster/schema/partitioners/random.rb +37 -0
  30. data/lib/cassandra/cluster/schema/partitioners.rb +21 -0
  31. data/lib/cassandra/cluster/schema/replication_strategies/network_topology.rb +92 -0
  32. data/lib/cassandra/cluster/schema/replication_strategies/none.rb +39 -0
  33. data/lib/cassandra/cluster/schema/replication_strategies/simple.rb +44 -0
  34. data/lib/cassandra/cluster/schema/replication_strategies.rb +21 -0
  35. data/lib/cassandra/cluster/schema/type_parser.rb +138 -0
  36. data/lib/cassandra/cluster/schema.rb +340 -0
  37. data/lib/cassandra/cluster.rb +215 -0
  38. data/lib/cassandra/column.rb +92 -0
  39. data/lib/cassandra/compression/compressors/lz4.rb +72 -0
  40. data/lib/cassandra/compression/compressors/snappy.rb +66 -0
  41. data/lib/cassandra/compression.rb +66 -0
  42. data/lib/cassandra/driver.rb +111 -0
  43. data/lib/cassandra/errors.rb +79 -0
  44. data/lib/cassandra/execution/info.rb +51 -0
  45. data/lib/cassandra/execution/options.rb +80 -0
  46. data/lib/cassandra/execution/trace.rb +152 -0
  47. data/lib/cassandra/future.rb +675 -0
  48. data/lib/cassandra/host.rb +79 -0
  49. data/lib/cassandra/keyspace.rb +133 -0
  50. data/lib/cassandra/listener.rb +87 -0
  51. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +149 -0
  52. data/lib/cassandra/load_balancing/policies/round_robin.rb +132 -0
  53. data/lib/cassandra/load_balancing/policies/token_aware.rb +119 -0
  54. data/lib/cassandra/load_balancing/policies/white_list.rb +90 -0
  55. data/lib/cassandra/load_balancing/policies.rb +19 -0
  56. data/lib/cassandra/load_balancing.rb +113 -0
  57. data/lib/cassandra/protocol/cql_byte_buffer.rb +307 -0
  58. data/lib/cassandra/protocol/cql_protocol_handler.rb +323 -0
  59. data/lib/cassandra/protocol/frame_decoder.rb +128 -0
  60. data/lib/cassandra/protocol/frame_encoder.rb +48 -0
  61. data/lib/cassandra/protocol/request.rb +38 -0
  62. data/lib/cassandra/protocol/requests/auth_response_request.rb +47 -0
  63. data/lib/cassandra/protocol/requests/batch_request.rb +76 -0
  64. data/lib/cassandra/protocol/requests/credentials_request.rb +47 -0
  65. data/lib/cassandra/protocol/requests/execute_request.rb +103 -0
  66. data/lib/cassandra/protocol/requests/options_request.rb +39 -0
  67. data/lib/cassandra/protocol/requests/prepare_request.rb +50 -0
  68. data/lib/cassandra/protocol/requests/query_request.rb +153 -0
  69. data/lib/cassandra/protocol/requests/register_request.rb +38 -0
  70. data/lib/cassandra/protocol/requests/startup_request.rb +49 -0
  71. data/lib/cassandra/protocol/requests/void_query_request.rb +24 -0
  72. data/lib/cassandra/protocol/response.rb +38 -0
  73. data/lib/cassandra/protocol/responses/auth_challenge_response.rb +41 -0
  74. data/lib/cassandra/protocol/responses/auth_success_response.rb +41 -0
  75. data/lib/cassandra/protocol/responses/authenticate_response.rb +41 -0
  76. data/lib/cassandra/protocol/responses/detailed_error_response.rb +60 -0
  77. data/lib/cassandra/protocol/responses/error_response.rb +50 -0
  78. data/lib/cassandra/protocol/responses/event_response.rb +39 -0
  79. data/lib/cassandra/protocol/responses/prepared_result_response.rb +64 -0
  80. data/lib/cassandra/protocol/responses/raw_rows_result_response.rb +43 -0
  81. data/lib/cassandra/protocol/responses/ready_response.rb +44 -0
  82. data/lib/cassandra/protocol/responses/result_response.rb +48 -0
  83. data/lib/cassandra/protocol/responses/rows_result_response.rb +139 -0
  84. data/lib/cassandra/protocol/responses/schema_change_event_response.rb +60 -0
  85. data/lib/cassandra/protocol/responses/schema_change_result_response.rb +57 -0
  86. data/lib/cassandra/protocol/responses/set_keyspace_result_response.rb +42 -0
  87. data/lib/cassandra/protocol/responses/status_change_event_response.rb +44 -0
  88. data/lib/cassandra/protocol/responses/supported_response.rb +41 -0
  89. data/lib/cassandra/protocol/responses/topology_change_event_response.rb +34 -0
  90. data/lib/cassandra/protocol/responses/void_result_response.rb +39 -0
  91. data/lib/cassandra/protocol/type_converter.rb +384 -0
  92. data/lib/cassandra/protocol.rb +93 -0
  93. data/lib/cassandra/reconnection/policies/constant.rb +48 -0
  94. data/lib/cassandra/reconnection/policies/exponential.rb +79 -0
  95. data/lib/cassandra/reconnection/policies.rb +20 -0
  96. data/lib/cassandra/reconnection.rb +49 -0
  97. data/lib/cassandra/result.rb +215 -0
  98. data/lib/cassandra/retry/policies/default.rb +47 -0
  99. data/lib/cassandra/retry/policies/downgrading_consistency.rb +71 -0
  100. data/lib/cassandra/retry/policies/fallthrough.rb +39 -0
  101. data/lib/cassandra/retry/policies.rb +21 -0
  102. data/lib/cassandra/retry.rb +142 -0
  103. data/lib/cassandra/session.rb +202 -0
  104. data/lib/cassandra/statement.rb +22 -0
  105. data/lib/cassandra/statements/batch.rb +95 -0
  106. data/lib/cassandra/statements/bound.rb +48 -0
  107. data/lib/cassandra/statements/prepared.rb +81 -0
  108. data/lib/cassandra/statements/simple.rb +58 -0
  109. data/lib/cassandra/statements/void.rb +33 -0
  110. data/lib/cassandra/statements.rb +23 -0
  111. data/lib/cassandra/table.rb +299 -0
  112. data/lib/cassandra/time_uuid.rb +142 -0
  113. data/lib/cassandra/util.rb +167 -0
  114. data/lib/cassandra/uuid.rb +104 -0
  115. data/lib/cassandra/version.rb +21 -0
  116. data/lib/cassandra.rb +428 -0
  117. data/lib/cassandra_murmur3.jar +0 -0
  118. metadata +211 -0
@@ -0,0 +1,90 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module LoadBalancing
21
+ module Policies
22
+ class WhiteList < Policy
23
+ extend Forwardable
24
+
25
+ # @!method plan(keyspace, statement, options)
26
+ # Delegates to wrapped policy
27
+ # @see Cassandra::LoadBalancing::Policy#plan
28
+ #
29
+ # @!method distance(host)
30
+ # Delegates to wrapped policy
31
+ # @see Cassandra::LoadBalancing::Policy#distance
32
+ def_delegators :@policy, :plan, :distance
33
+
34
+ # @param ips [Enumerable<String, IPAddr>] a list of ips to whitelist
35
+ # @param wrapped_policy [Cassandra::LoadBalancing::Policy] actual policy to filter
36
+ # @raise [ArgumentError] if arguments are of unexpected types
37
+ def initialize(ips, wrapped_policy)
38
+ raise ::ArgumentError, "ips must be enumerable" unless ips.respond_to?(:each)
39
+ methods = [:host_up, :host_down, :host_found, :host_lost, :distance, :plan]
40
+
41
+ unless methods.all? {|method| wrapped_policy.respond_to?(method)}
42
+ raise ::ArgumentError, "supplied policy must be a Cassandra::LoadBalancing::Policy, #{wrapped_policy.inspect} given"
43
+ end
44
+
45
+ @ips = ::Set.new
46
+ @policy = wrapped_policy
47
+
48
+ ips.each do |ip|
49
+ case ip
50
+ when ::IPAddr
51
+ @ips << ip
52
+ when ::String
53
+ @ips << ::IPAddr.new(ip)
54
+ else
55
+ raise ::ArgumentError, "ips must contain only instance of String or IPAddr, #{ip.inspect} given"
56
+ end
57
+ end
58
+ end
59
+
60
+ # Delegates to wrapped policy if host's ip is whitelisted
61
+ # @param host [Cassandra::Host] a host instance
62
+ # @see Cassandra::LoadBalancing::Policy#host_found
63
+ def host_found(host)
64
+ @policy.host_found(host) if @ips.include?(host.ip)
65
+ end
66
+
67
+ # Delegates to wrapped policy if host's ip is whitelisted
68
+ # @param host [Cassandra::Host] a host instance
69
+ # @see Cassandra::LoadBalancing::Policy#host_lost
70
+ def host_lost(host)
71
+ @policy.host_lost(host) if @ips.include?(host.ip)
72
+ end
73
+
74
+ # Delegates to wrapped policy if host's ip is whitelisted
75
+ # @param host [Cassandra::Host] a host instance
76
+ # @see Cassandra::LoadBalancing::Policy#host_up
77
+ def host_up(host)
78
+ @policy.host_up(host) if @ips.include?(host.ip)
79
+ end
80
+
81
+ # Delegates to wrapped policy if host's ip is whitelisted
82
+ # @param host [Cassandra::Host] a host instance
83
+ # @see Cassandra::LoadBalancing::Policy#host_down
84
+ def host_down(host)
85
+ @policy.host_down(host) if @ips.include?(host.ip)
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,19 @@
1
+ # Copyright 2013-2014 DataStax, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #++
15
+
16
+ require 'cassandra/load_balancing/policies/dc_aware_round_robin'
17
+ require 'cassandra/load_balancing/policies/round_robin'
18
+ require 'cassandra/load_balancing/policies/token_aware'
19
+ require 'cassandra/load_balancing/policies/white_list'
@@ -0,0 +1,113 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module LoadBalancing
21
+ # A list of possible load balancing distances that
22
+ # {Cassandra::LoadBalancing::Policy#distance} must return
23
+ DISTANCES = [:ignore, :local, :remote].freeze
24
+
25
+ # @abstract Actual load balancing policies don't need to extend this class,
26
+ # only implement its methods. This class exists for documentation
27
+ # purposes only.
28
+ class Policy
29
+ # Allows policy to initialize with the cluster instance. This method is
30
+ # called once before connecting to the cluster.
31
+ # @param cluster [Cassandra::Cluster] current cluster instance
32
+ # @return [void]
33
+ def setup(cluster)
34
+ end
35
+
36
+ # @see Cassandra::Listener#host_up
37
+ def host_up(host)
38
+ end
39
+
40
+ # @see Cassandra::Listener#host_down
41
+ def host_down(host)
42
+ end
43
+
44
+ # @see Cassandra::Listener#host_found
45
+ def host_found(host)
46
+ end
47
+
48
+ # @see Cassandra::Listener#host_lost
49
+ def host_lost(host)
50
+ end
51
+
52
+ # Returns a distance that determines how many connections (if any) the
53
+ # driver will open to the host.
54
+ #
55
+ # @param host [Cassandra::Host] a host instance
56
+ # @return [Symbol] distance to host. Must be one of
57
+ # {Cassandra::LoadBalancing::DISTANCES}
58
+ def distance(host)
59
+ :ignore
60
+ end
61
+
62
+ # Load balancing plan is used to determine the order in which hosts
63
+ # should be tried in case of a network failure.
64
+ #
65
+ # @note Hosts that should be ignored, must not be included in the Plan
66
+ #
67
+ # @param keyspace [String] current keyspace of the {Cassandra::Session}
68
+ # @param statement [Cassandra::Statement] actual statement to be executed
69
+ # @param options [Cassandra::Execution::Options] execution options to be used
70
+ # @raise [NotImplementedError] override this method to return a plan
71
+ # @return [Cassandra::LoadBalancing::Plan] a load balancing plan
72
+ def plan(keyspace, statement, options)
73
+ raise ::NotImplementedError, "must be implemented by a child"
74
+ end
75
+
76
+ # @return [String] a console-friendly representation of this policy
77
+ def inspect
78
+ "#<#{self.class.name}:0x#{self.object_id.to_s(16)}>"
79
+ end
80
+ end
81
+
82
+ # A load balancing plan is used to determine the order of hosts for running
83
+ # queries, preparing statements and establishing connections.
84
+ # @abstract Plans returned by {Cassandra::LoadBalancing::Policy#plan}
85
+ # implementations don't need to extend this class, only implement its
86
+ # methods. This class exists for documentation purposes only.
87
+ class Plan
88
+ # @return [Boolean] whether the plan contains any more hosts
89
+ def has_next?
90
+ end
91
+
92
+ # @return [Cql::Host] next host to try
93
+ def next
94
+ end
95
+ end
96
+
97
+ # @private
98
+ class EmptyPlan
99
+ def has_next?
100
+ false
101
+ end
102
+
103
+ def next
104
+ nil
105
+ end
106
+ end
107
+
108
+ # @private
109
+ EMPTY_PLAN = EmptyPlan.new
110
+ end
111
+ end
112
+
113
+ require 'cassandra/load_balancing/policies'
@@ -0,0 +1,307 @@
1
+ # encoding: utf-8
2
+
3
+ #--
4
+ # Copyright 2013-2014 DataStax, Inc.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #++
18
+
19
+ module Cassandra
20
+ module Protocol
21
+ class CqlByteBuffer < Ione::ByteBuffer
22
+ def read_unsigned_byte
23
+ read_byte
24
+ rescue RangeError => e
25
+ raise DecodingError, e.message, e.backtrace
26
+ end
27
+
28
+ def read_varint(len=bytesize, signed=true)
29
+ bytes = read(len)
30
+ n = 0
31
+ bytes.each_byte do |b|
32
+ n = (n << 8) | b
33
+ end
34
+ if signed && bytes.getbyte(0) & 0x80 == 0x80
35
+ n -= 2**(bytes.length * 8)
36
+ end
37
+ n
38
+ rescue RangeError => e
39
+ raise DecodingError, e.message, e.backtrace
40
+ end
41
+
42
+ def read_decimal(len=bytesize)
43
+ size = read_signed_int
44
+ number_string = read_varint(len - 4).to_s
45
+ if number_string.length <= size
46
+ if number_string.start_with?(MINUS)
47
+ number_string = number_string[1, number_string.length - 1]
48
+ fraction_string = MINUS + ZERO << DECIMAL_POINT
49
+ else
50
+ fraction_string = ZERO + DECIMAL_POINT
51
+ end
52
+ (size - number_string.length).times { fraction_string << ZERO }
53
+ fraction_string << number_string
54
+ else
55
+ fraction_string = number_string[0, number_string.length - size]
56
+ fraction_string << DECIMAL_POINT
57
+ fraction_string << number_string[number_string.length - size, number_string.length]
58
+ end
59
+ BigDecimal.new(fraction_string)
60
+ rescue DecodingError => e
61
+ raise DecodingError, e.message, e.backtrace
62
+ end
63
+
64
+ def read_long
65
+ top, bottom = read(8).unpack(Formats::TWO_INTS_FORMAT)
66
+ return (top << 32) | bottom if top <= 0x7fffffff
67
+ top ^= 0xffffffff
68
+ bottom ^= 0xffffffff
69
+ -((top << 32) | bottom) - 1
70
+ rescue RangeError => e
71
+ raise DecodingError, e.message, e.backtrace
72
+ end
73
+
74
+ def read_double
75
+ read(8).unpack(Formats::DOUBLE_FORMAT).first
76
+ rescue RangeError => e
77
+ raise DecodingError, "Not enough bytes available to decode a double: #{e.message}", e.backtrace
78
+ end
79
+
80
+ def read_float
81
+ read(4).unpack(Formats::FLOAT_FORMAT).first
82
+ rescue RangeError => e
83
+ raise DecodingError, "Not enough bytes available to decode a float: #{e.message}", e.backtrace
84
+ end
85
+
86
+ def read_signed_int
87
+ n = read_int
88
+ return n if n <= 0x7fffffff
89
+ n - 0xffffffff - 1
90
+ rescue RangeError => e
91
+ raise DecodingError, "Not enough bytes available to decode an int: #{e.message}", e.backtrace
92
+ end
93
+
94
+ def read_unsigned_short
95
+ read_short
96
+ rescue RangeError => e
97
+ raise DecodingError, "Not enough bytes available to decode a short: #{e.message}", e.backtrace
98
+ end
99
+
100
+ def read_string
101
+ length = read_unsigned_short
102
+ string = read(length)
103
+ string.force_encoding(::Encoding::UTF_8)
104
+ string
105
+ rescue RangeError => e
106
+ raise DecodingError, "Not enough bytes available to decode a string: #{e.message}", e.backtrace
107
+ end
108
+
109
+ def read_long_string
110
+ length = read_signed_int
111
+ string = read(length)
112
+ string.force_encoding(::Encoding::UTF_8)
113
+ string
114
+ rescue RangeError => e
115
+ raise DecodingError, "Not enough bytes available to decode a long string: #{e.message}", e.backtrace
116
+ end
117
+
118
+ def read_uuid(impl=Uuid)
119
+ impl.new(read_varint(16, false))
120
+ rescue DecodingError => e
121
+ raise DecodingError, "Not enough bytes available to decode a UUID: #{e.message}", e.backtrace
122
+ end
123
+
124
+ def read_string_list
125
+ size = read_unsigned_short
126
+ Array.new(size) { read_string }
127
+ end
128
+
129
+ def read_bytes
130
+ size = read_signed_int
131
+ return nil if size & 0x80000000 == 0x80000000
132
+ read(size)
133
+ rescue RangeError => e
134
+ raise DecodingError, "Not enough bytes available to decode a bytes: #{e.message}", e.backtrace
135
+ end
136
+
137
+ def read_short_bytes
138
+ size = read_unsigned_short
139
+ return nil if size & 0x8000 == 0x8000
140
+ read(size)
141
+ rescue RangeError => e
142
+ raise DecodingError, "Not enough bytes available to decode a short bytes: #{e.message}", e.backtrace
143
+ end
144
+
145
+ def read_option
146
+ id = read_unsigned_short
147
+ value = nil
148
+ if block_given?
149
+ value = yield id, self
150
+ end
151
+ [id, value]
152
+ end
153
+
154
+ def read_inet
155
+ size = read_byte
156
+ ip_addr = IPAddr.new_ntoh(read(size))
157
+ port = read_int
158
+ [ip_addr, port]
159
+ rescue RangeError => e
160
+ raise DecodingError, "Not enough bytes available to decode an INET: #{e.message}", e.backtrace
161
+ end
162
+
163
+ def read_consistency
164
+ index = read_unsigned_short
165
+ raise DecodingError, "Unknown consistency index #{index}" if index >= CONSISTENCIES.size || CONSISTENCIES[index].nil?
166
+ CONSISTENCIES[index]
167
+ end
168
+
169
+ def read_string_map
170
+ map = {}
171
+ map_size = read_unsigned_short
172
+ map_size.times do
173
+ key = read_string
174
+ map[key] = read_string
175
+ end
176
+ map
177
+ end
178
+
179
+ def read_string_multimap
180
+ map = {}
181
+ map_size = read_unsigned_short
182
+ map_size.times do
183
+ key = read_string
184
+ map[key] = read_string_list
185
+ end
186
+ map
187
+ end
188
+
189
+ def append_int(n)
190
+ append([n].pack(Formats::INT_FORMAT))
191
+ end
192
+
193
+ def append_short(n)
194
+ append([n].pack(Formats::SHORT_FORMAT))
195
+ end
196
+
197
+ def append_string(str)
198
+ str = str.to_s
199
+ append_short(str.bytesize)
200
+ append(str)
201
+ end
202
+
203
+ def append_long_string(str)
204
+ append_int(str.bytesize)
205
+ append(str)
206
+ end
207
+
208
+ def append_uuid(uuid)
209
+ v = uuid.value
210
+ append_int((v >> 96) & 0xffffffff)
211
+ append_int((v >> 64) & 0xffffffff)
212
+ append_int((v >> 32) & 0xffffffff)
213
+ append_int((v >> 0) & 0xffffffff)
214
+ end
215
+
216
+ def append_string_list(strs)
217
+ append_short(strs.size)
218
+ strs.each do |str|
219
+ append_string(str)
220
+ end
221
+ self
222
+ end
223
+
224
+ def append_bytes(bytes)
225
+ if bytes
226
+ append_int(bytes.bytesize)
227
+ append(bytes)
228
+ else
229
+ append_int(-1)
230
+ end
231
+ end
232
+
233
+ def append_short_bytes(bytes)
234
+ if bytes
235
+ append_short(bytes.bytesize)
236
+ append(bytes)
237
+ else
238
+ append_short(-1)
239
+ end
240
+ end
241
+
242
+ def append_consistency(consistency)
243
+ index = CONSISTENCIES.index(consistency)
244
+ raise EncodingError, %(Unknown consistency "#{consistency}") if index.nil? || CONSISTENCIES[index].nil?
245
+ append_short(index)
246
+ end
247
+
248
+ def append_string_map(map)
249
+ append_short(map.size)
250
+ map.each do |key, value|
251
+ append_string(key)
252
+ append_string(value)
253
+ end
254
+ self
255
+ end
256
+
257
+ def append_long(n)
258
+ top = n >> 32
259
+ bottom = n & 0xffffffff
260
+ append_int(top)
261
+ append_int(bottom)
262
+ end
263
+
264
+ def append_varint(n)
265
+ num = n
266
+ bytes = []
267
+ begin
268
+ bytes << (num & 0xff)
269
+ num >>= 8
270
+ end until (num == 0 || num == -1) && (bytes.last[7] == num[7])
271
+ append(bytes.reverse.pack(Formats::BYTES_FORMAT))
272
+ end
273
+
274
+ def append_decimal(n)
275
+ str = n.to_s(FLOAT_STRING_FORMAT)
276
+ size = str.index(DECIMAL_POINT)
277
+ number_string = str.gsub(DECIMAL_POINT, NO_CHAR)
278
+
279
+ num = number_string.to_i
280
+ raw = self.class.new.append_varint(num)
281
+ append_int(number_string.length - size)
282
+ append(raw)
283
+ end
284
+
285
+ def append_double(n)
286
+ append([n].pack(Formats::DOUBLE_FORMAT))
287
+ end
288
+
289
+ def append_float(n)
290
+ append([n].pack(Formats::FLOAT_FORMAT))
291
+ end
292
+
293
+ def eql?(other)
294
+ other.eql?(to_str)
295
+ end
296
+ alias_method :==, :eql?
297
+
298
+ private
299
+
300
+ MINUS = '-'.freeze
301
+ ZERO = '0'.freeze
302
+ DECIMAL_POINT = '.'.freeze
303
+ FLOAT_STRING_FORMAT = 'F'.freeze
304
+ NO_CHAR = ''.freeze
305
+ end
306
+ end
307
+ end