Class: BSON::Binary

Inherits:
Object
  • Object
show all
Includes:
JSON, Comparable
Defined in:
lib/bson/binary.rb

Overview

Represents binary data.

See Also:

Since:

  • 2.0.0

Constant Summary collapse

BSON_TYPE =

A binary is type 0x05 in the BSON spec.

Since:

  • 2.0.0

::String.new(5.chr, encoding: BINARY).freeze
SUBTYPES =
Note:

subtype 6 (ciphertext) is used for the Client-Side Encryption feature. Data represented by this subtype is often encrypted, but may also be plaintext. All instances of this subtype necessary for Client-Side Encryption will be created internally by the Ruby driver. An application should not create new BSON::Binary objects of this subtype.

The mappings of subtypes to their single byte identifiers.

Since:

  • 2.0.0

{
  generic: 0.chr,
  function: 1.chr,
  old: 2.chr,
  uuid_old: 3.chr,
  uuid: 4.chr,
  md5: 5.chr,
  ciphertext: 6.chr,
  column: 7.chr,
  sensitive: 8.chr,
  vector: 9.chr,
  user: 128.chr,
}.freeze
USER_SUBTYPE =

The starting point of the user-defined subtype range.

Since:

  • 2.0.0

0x80
TYPES =

The mappings of single byte subtypes to their symbol counterparts.

Since:

  • 2.0.0

SUBTYPES.invert.freeze
VECTOR_DATA_TYPES =

Types of vector data.

Since:

  • 2.0.0

{
  int8: '0x03'.hex,
  float32: '0x27'.hex,
  packed_bit: '0x10'.hex
}.freeze
VECTOR_DATA_TYPES_INVERSE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Since:

  • 2.0.0

VECTOR_DATA_TYPES.invert.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from JSON

#to_json

Constructor Details

#initialize(data = '', type = :generic) ⇒ Binary

Instantiate the new binary object.

This method accepts a string in any encoding; however, if a string is of a non-BINARY encoding, the encoding is set to BINARY. This does not change the bytes of the string but it means that applications referencing the data of a Binary instance cannot assume it is in a non-binary encoding, even if the string given to the constructor was in such an encoding.

Examples:

Instantiate a binary.

BSON::Binary.new(data, :md5)

Parameters:

  • data (String) (defaults to: '')

    The raw binary data.

  • type (Symbol) (defaults to: :generic)

    The binary type.

Since:

  • 2.0.0



197
198
199
# File 'lib/bson/binary.rb', line 197

def initialize(data = '', type = :generic)
  initialize_instance(data, type)
end

Instance Attribute Details

#dataString (readonly)

The string is always stored in BINARY encoding.

Returns:

  • (String)

    The raw binary data.

Since:

  • 2.0.0



80
81
82
# File 'lib/bson/binary.rb', line 80

def data
  @data
end

#raw_typeString (readonly)

Returns The raw type value, as an encoded integer.

Returns:

  • (String)

    The raw type value, as an encoded integer.

Since:

  • 2.0.0



86
87
88
# File 'lib/bson/binary.rb', line 86

def raw_type
  @raw_type
end

#typeSymbol (readonly)

Returns The binary type.

Returns:

  • (Symbol)

    The binary type.

Since:

  • 2.0.0



83
84
85
# File 'lib/bson/binary.rb', line 83

def type
  @type
end

Class Method Details

.from_bson(buffer, **_options) ⇒ Binary

Deserialize the binary data from BSON.

Parameters:

  • buffer (ByteBuffer)

    The byte buffer.

  • options (Hash)

    a customizable set of options

Returns:

  • (Binary)

    The decoded binary data.

See Also:

Since:

  • 2.0.0



294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/bson/binary.rb', line 294

def self.from_bson(buffer, **_options)
  length = buffer.get_int32
  type_byte = buffer.get_byte

  if type_byte.bytes.first < USER_SUBTYPE
    type = TYPES[type_byte]

    if type.nil?
      raise Error::UnsupportedBinarySubtype,
            "BSON data contains unsupported binary subtype #{'0x%02x' % type_byte.ord}"
    end
  else
    type = type_byte
  end

  length = buffer.get_int32 if type == :old
  data = buffer.get_bytes(length)
  new(data, type)
end

.from_csharp_legacy_uuid(uuid_binary) ⇒ BSON::Binary

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.

Constructs a new binary object from a csharp legacy-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



371
372
373
374
# File 'lib/bson/binary.rb', line 371

def self.from_csharp_legacy_uuid(uuid_binary)
  uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.{8})\z/, '\4\3\2\1\6\5\8\7\9')
  new(uuid_binary, :uuid_old)
end

.from_java_legacy_uuid(uuid_binary) ⇒ BSON::Binary

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.

Constructs a new binary object from a java legacy-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



384
385
386
387
388
389
# File 'lib/bson/binary.rb', line 384

def self.from_java_legacy_uuid(uuid_binary)
  uuid_binary.sub!(/\A(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\z/) do
    (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join
  end
  new(uuid_binary, :uuid_old)
end

.from_python_legacy_uuid(uuid_binary) ⇒ BSON::Binary

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.

Constructs a new binary object from a python legacy-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



399
400
401
# File 'lib/bson/binary.rb', line 399

def self.from_python_legacy_uuid(uuid_binary)
  new(uuid_binary, :uuid_old)
end

.from_standard_uuid(uuid_binary) ⇒ BSON::Binary

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.

Constructs a new binary object from a standard-format binary UUID representation.

Parameters:

  • uuid_binary (String)

    the UUID data

Returns:

Since:

  • 2.0.0



359
360
361
# File 'lib/bson/binary.rb', line 359

def self.from_standard_uuid(uuid_binary)
  new(uuid_binary, :uuid)
end

.from_uuid(uuid, representation = nil) ⇒ Binary

Creates a BSON::Binary from a string representation of a UUID.

The UUID may be given in either 00112233-4455-6677-8899-aabbccddeeff or 00112233445566778899AABBCCDDEEFF format - specifically, any dashes in the UUID are removed and both upper and lower case letters are acceptable.

The input UUID string is always interpreted to be in the RFC 4122 format.

If representation is not provided, this method creates a BSON::Binary of subtype 4 (:uuid). If representation is provided, it must be one of :standard, :csharp_legacy, :java_legacy or :python_legacy. If representation is :standard, this method creates a subtype 4 (:uuid) binary which is the same behavior as if representation was not provided. For other representations, this method creates a Binary of subtype 3 (:uuid_old) with the UUID converted to the appropriate legacy MongoDB UUID storage format.

Parameters:

  • uuid (String)

    The string representation of the UUID.

  • representation (Symbol) (defaults to: nil)

    How to interpret the UUID.

Returns:

Raises:

  • (ArgumentError)

    If invalid representation is requested.

Since:

  • 2.0.0



339
340
341
342
343
344
345
346
347
348
349
# File 'lib/bson/binary.rb', line 339

def self.from_uuid(uuid, representation = nil)
  raise ArgumentError, "Representation must be given as a symbol: #{representation}" if representation.is_a?(String)

  uuid_binary = uuid.delete('-').scan(/../).map(&:hex).map(&:chr).join
  representation ||= :standard

  handler = :"from_#{representation}_uuid"
  raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler)

  send(handler, uuid_binary)
end

.from_vector(vector, dtype = nil, padding = 0, validate_vector_data: false) ⇒ BSON::Binary

be ignored when a vector element’s size is less than a byte. Must be 0 if vector is a BSON::Vector.

Parameters:

  • vector (BSON::Vector | Array)

    The vector data.

  • dtype (Symbol | nil) (defaults to: nil)

    The vector data type, must be nil if vector is a BSON::Vector.

  • padding (Integer) (defaults to: 0)

    The number of bits in the final byte that are to

  • validate_vector_data (Boolean) (defaults to: false)

    Whether to validate the vector data.

Returns:

Since:

  • 2.0.0



412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/bson/binary.rb', line 412

def self.from_vector(vector, dtype = nil, padding = 0, validate_vector_data: false)
  data, dtype, padding = extract_args_for_vector(vector, dtype, padding)
  validate_args_for_vector!(data, dtype, padding)

  format = case dtype
           when :int8 then 'c*'
           when :float32 then 'f*'
           when :packed_bit then 'C*'
           else raise ArgumentError, "Unsupported type: #{dtype}"
           end
  if validate_vector_data
    validate_vector_data!(data, dtype)
  end
   = [ VECTOR_DATA_TYPES[dtype], padding ].pack('CC')
  data = data.pack(format)
  new(.concat(data), :vector)
end

Instance Method Details

#<=>(other) ⇒ Integer | nil

Compare this binary object to another object. The two objects must have the same type for any meaningful comparison.

Parameters:

  • other (Object)

    The object to compare against.

Returns:

  • (Integer | nil)

    If the objects have the same type, the result is -1 if self < other, 0 if self == other, and 1 if self > other. If other is not a Binary, or is a Binary of a different type, returns nil.

Since:

  • 2.0.0



114
115
116
117
118
# File 'lib/bson/binary.rb', line 114

def <=>(other)
  return nil unless other.is_a?(Binary) && type == other.type

  data <=> other.data
end

#==(other) ⇒ true, false Also known as: eql?

Determine if this binary object is equal to another object.

Examples:

Check the binary equality.

binary == other

Parameters:

  • other (Object)

    The object to compare against.

Returns:

  • (true, false)

    If the objects are equal.

Since:

  • 2.0.0



98
99
100
101
102
# File 'lib/bson/binary.rb', line 98

def ==(other)
  return false unless other.is_a?(Binary)

  type == other.type && data == other.data
end

#as_extended_json(**options) ⇒ Hash

Converts this object to a representation directly serializable to Extended JSON (github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).

Parameters:

  • opts (Hash)

    a customizable set of options

Returns:

  • (Hash)

    The extended json representation.

Since:

  • 2.0.0



148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/bson/binary.rb', line 148

def as_extended_json(**options)
  subtype = @raw_type.each_byte.map { |c| c.to_s(16) }.join
  subtype = "0#{subtype}" if subtype.length == 1

  value = Base64.encode64(data).strip

  if options[:mode] == :legacy
    { '$binary' => value, '$type' => subtype }
  else
    { '$binary' => { 'base64' => value, 'subType' => subtype } }
  end
end

#as_json(*_args) ⇒ Hash

Return a representation of the object for use in application-level JSON serialization. Since BSON::Binary is used exclusively in BSON-related contexts, this method returns the canonical Extended JSON representation.

Returns:

  • (Hash)

    The extended json representation.

Since:

  • 2.0.0



137
138
139
# File 'lib/bson/binary.rb', line 137

def as_json(*_args)
  as_extended_json
end

#as_vectorBSON::Vector

Decode the binary data as a vector data type.

Returns:

Raises:

Since:

  • 2.0.0



164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/bson/binary.rb', line 164

def as_vector
  raise BSON::Error, "Cannot decode subtype #{type} as vector" unless type == :vector

  dtype_value, padding, = data[0..1].unpack('CC')
  dtype = VECTOR_DATA_TYPES_INVERSE[dtype_value]
  raise ArgumentError, "Unsupported vector type: #{dtype_value}" unless dtype

  format = case dtype
           when :int8 then 'c*'
           when :float32 then 'f*'
           when :packed_bit then 'C*'
           else
             raise ArgumentError, "Unsupported type: #{dtype}"
           end
  BSON::Vector.new(data[2..-1].unpack(format), dtype, padding)
end

#hashFixnum

Generates a Fixnum hash value for this object.

Allows using Binary as hash keys.

Returns:

  • (Fixnum)

Since:

  • 2.3.1



127
128
129
# File 'lib/bson/binary.rb', line 127

def hash
  [data, type].hash
end

#init_with(coder) ⇒ 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.

For legacy deserialization support where BSON::Binary objects are expected to have a specific internal representation (with only

Since:

  • 2.0.0



206
207
208
# File 'lib/bson/binary.rb', line 206

def init_with(coder)
  initialize_instance(coder['data'], coder['type'])
end

#inspectString

Get a nice string for use with object inspection.

Examples:

Inspect the binary.

object_id.inspect

Returns:

  • (String)

    The binary in form BSON::Binary:object_id

Since:

  • 2.3.0



218
219
220
# File 'lib/bson/binary.rb', line 218

def inspect
  "<BSON::Binary:0x#{object_id} type=#{type} data=0x#{data[0, 8].unpack1('H*')}...>"
end

#to_bson(buffer = ByteBuffer.new) ⇒ BSON::ByteBuffer

Encode the binary type

Examples:

Encode the binary.

binary.to_bson

Returns:

See Also:

Since:

  • 2.0.0



274
275
276
277
278
279
280
281
# File 'lib/bson/binary.rb', line 274

def to_bson(buffer = ByteBuffer.new)
  position = buffer.length
  buffer.put_int32(0)
  buffer.put_byte(@raw_type)
  buffer.put_int32(data.bytesize) if type == :old
  buffer.put_bytes(data)
  buffer.replace_int32(position, buffer.length - position - 5)
end

#to_uuid(representation = nil) ⇒ String

Returns a string representation of the UUID stored in this Binary.

If the Binary is of subtype 4 (:uuid), this method returns the UUID in RFC 4122 format. If the representation parameter is provided, it must be the value :standard as a symbol or a string.

If the Binary is of subtype 3 (:uuid_old), this method requires that the representation parameter is provided and is one of :csharp_legacy, :java_legacy or :python_legacy or the equivalent strings. In this case the method assumes the Binary stores the UUID in the specified format, transforms the stored bytes to the standard RFC 4122 representation and returns the UUID in RFC 4122 format.

If the Binary is of another subtype, this method raises TypeError.

Parameters:

  • representation (Symbol) (defaults to: nil)

    How to interpret the UUID.

Returns:

  • (String)

    The string representation of the UUID.

Raises:

  • (TypeError)

    If the subtype of Binary is not :uuid nor :uuid_old.

  • (ArgumentError)

    If the representation other than :standard is requested for Binary subtype 4 (:uuid), if :standard representation is requested for Binary subtype 3 (:uuid_old), or if an invalid representation is requested.

Since:

  • 2.0.0



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/bson/binary.rb', line 248

def to_uuid(representation = nil)
  if representation.is_a?(String)
    raise ArgumentError,
          "Representation must be given as a symbol: #{representation.inspect}"
  end

  case type
  when :uuid
    from_uuid_to_uuid(representation || :standard)
  when :uuid_old
    from_uuid_old_to_uuid(representation)
  else
    raise TypeError, "The type of Binary must be :uuid or :uuid_old, this object is: #{type.inspect}"
  end
end