class BSON::Binary
Represents binary data.
@see bsonspec.org/#/specification
@since 2.0.0
Constants
- BSON_TYPE
-
A binary is type 0x05 in the
BSON
spec.@since 2.0.0
- SUBTYPES
-
The mappings of subtypes to their single byte identifiers.
@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.
@since 2.0.0
- TYPES
-
The mappings of single byte subtypes to their symbol counterparts.
@since 2.0.0
- USER_SUBTYPE
-
The starting point of the user-defined subtype range.
- VECTOR_DATA_TYPES
-
Types of vector data.
- VECTOR_DATA_TYPES_INVERSE
-
@api private
Attributes
@return [ String
] The raw binary data.
The string is always stored in BINARY encoding.
@since 2.0.0
@return [ String
] The raw type value, as an encoded integer.
Public Class Methods
Source
# 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
Deserialize the binary data from BSON
.
@param [ ByteBuffer
] buffer The byte buffer.
@option options [ nil | :bson ] :mode Decoding mode to use.
@return [ Binary
] The decoded binary data.
@see bsonspec.org/#/specification
@since 2.0.0
Source
# 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
Constructs a new binary object from a csharp legacy-format binary UUID representation.
@param [ String
] uuid_binary the UUID data
@return [ BSON::Binary
] the Binary
object
@api private
Source
# 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
Constructs a new binary object from a java legacy-format binary UUID representation.
@param [ String
] uuid_binary the UUID data
@return [ BSON::Binary
] the Binary
object
@api private
Source
# File lib/bson/binary.rb, line 399 def self.from_python_legacy_uuid(uuid_binary) new(uuid_binary, :uuid_old) end
Constructs a new binary object from a python legacy-format binary UUID representation.
@param [ String
] uuid_binary the UUID data
@return [ BSON::Binary
] the Binary
object
@api private
Source
# File lib/bson/binary.rb, line 359 def self.from_standard_uuid(uuid_binary) new(uuid_binary, :uuid) end
Constructs a new binary object from a standard-format binary UUID representation.
@param [ String
] uuid_binary the UUID data
@return [ BSON::Binary
] the Binary
object
@api private
Source
# 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
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.
@param [ String
] uuid The string representation of the UUID. @param [ Symbol
] representation How to interpret the UUID.
@return [ Binary
] The binary.
@raise [ ArgumentError ] If invalid representation is requested.
@api experimental
Source
# 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 metadata = [ VECTOR_DATA_TYPES[dtype], padding ].pack('CC') data = data.pack(format) new(metadata.concat(data), :vector) end
@param [ BSON::Vector
| Array
] vector The vector data. @param [ Symbol
| nil ] dtype The vector data type, must be nil if vector is a BSON::Vector
. @param [ Integer
] padding The number of bits in the final byte that are to be ignored when a vector element’s size is less than a byte. Must be 0 if vector is a BSON::Vector
. @param [ Boolean
] validate_vector_data Whether to validate the vector data.
@return [ BSON::Binary
] The binary object.
Source
# File lib/bson/binary.rb, line 197 def initialize(data = '', type = :generic) initialize_instance(data, type) end
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.
@example Instantiate a binary.
BSON::Binary.new(data, :md5)
@param [ String
] data The raw binary data. @param [ Symbol
] type The binary type.
@since 2.0.0
Private Class Methods
Source
# File lib/bson/binary.rb, line 439 def self.extract_args_for_vector(vector, dtype, padding) if vector.is_a?(BSON::Vector) if dtype || padding != 0 raise ArgumentError, 'Do not specify dtype and padding if the first argument is BSON::Vector' end data = vector.data dtype = vector.dtype padding = vector.padding else data = vector end [ data, dtype, padding ] end
Extracts the arguments for a binary vector.
@param [ BSON::Vector
| Array
] vector The vector data. @param [ ::Symbol | nil ] dtype The vector data type, must be nil if vector is a BSON::Vector
. @param [ Integer
] padding The padding. Must be 0 if vector is a BSON::Vector
.
@return [ Array
] The extracted data, dtype, and padding.
Source
# File lib/bson/binary.rb, line 460 def self.validate_args_for_vector!(data, dtype, padding) raise ArgumentError, "Unknown dtype #{dtype}" unless VECTOR_DATA_TYPES.key?(dtype) if %i[int8 float32].include?(dtype) raise ArgumentError, 'Padding applies only to packed_bit' if padding != 0 elsif padding.positive? && data.empty? raise ArgumentError, 'Padding must be zero when the vector is empty for PACKED_BIT' elsif padding.negative? || padding > 7 raise ArgumentError, "Padding must be between 0 and 7, got #{padding}" end end
Validate the arguments for a binary vector. @param [ Array
] data The vector data. @param [ ::Symbol ] dtype The vector data type. @param [ Integer
] padding The padding. Must be 0 if vector is a BSON::Vector
. @raise [ ArgumentError ] If the arguments are invalid.
Source
# File lib/bson/binary.rb, line 477 def self.validate_vector_data!(data, dtype) validator = case dtype when :int8 ->(v) { v.is_a?(Integer) && v.between?(-128, 127) } when :float32 ->(v) { v.is_a?(Float) } when :packed_bit ->(v) { v.is_a?(Integer) && v.between?(0, 255) } else raise ArgumentError, "Unsupported type: #{dtype}" end data.each do |v| raise ArgumentError, "Invalid value #{v} for type #{dtype}" unless validator.call(v) end end
Validate that all the values in the vector data are valid for the given dtype.
@param [ Array
] data The vector data. @param [ ::Symbol ] dtype The vector data type.
Public Instance Methods
Source
# File lib/bson/binary.rb, line 114 def <=>(other) return nil unless other.is_a?(Binary) && type == other.type data <=> other.data end
Compare this binary object to another object. The two objects must have the same type for any meaningful comparison.
@param [ Object
] other The object to compare against.
@return [ 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.
Source
# File lib/bson/binary.rb, line 98 def ==(other) return false unless other.is_a?(Binary) type == other.type && data == other.data end
Determine if this binary object is equal to another object.
@example Check the binary equality.
binary == other
@param [ Object
] other The object to compare against.
@return [ true, false ] If the objects are equal.
@since 2.0.0
Source
# 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
Converts this object to a representation directly serializable to Extended JSON
(github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md).
@option opts [ nil | :relaxed | :legacy ] :mode Serialization mode
(default is canonical extended JSON)
@return [ Hash
] The extended json representation.
Source
# File lib/bson/binary.rb, line 137 def as_json(*_args) as_extended_json end
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.
@return [ Hash
] The extended json representation.
Source
# 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
Decode the binary data as a vector data type.
@return [ BSON::Vector
] The decoded vector data.
Source
# File lib/bson/binary.rb, line 127 def hash [data, type].hash end
Generates a Fixnum hash value for this object.
Allows using Binary
as hash keys.
@return [ Fixnum ]
@since 2.3.1
Source
# File lib/bson/binary.rb, line 206 def init_with(coder) initialize_instance(coder['data'], coder['type']) end
For legacy deserialization support where BSON::Binary
objects are expected to have a specific internal representation (with only @type and @data instance variables).
@api private
Source
# File lib/bson/binary.rb, line 218 def inspect "<BSON::Binary:0x#{object_id} type=#{type} data=0x#{data[0, 8].unpack1('H*')}...>" end
Get a nice string for use with object inspection.
@example Inspect the binary.
object_id.inspect
@return [ String
] The binary in form BSON::Binary
:object_id
@since 2.3.0
Source
# 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
Encode the binary type
@example Encode the binary.
binary.to_bson
@return [ BSON::ByteBuffer
] The buffer with the encoded object.
@see bsonspec.org/#/specification
@since 2.0.0
Source
# 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
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.
@param [ Symbol
] representation How to interpret the UUID.
@return [ String
] The string representation of the UUID.
@raise [ TypeError ] If the subtype of Binary
is not :uuid nor :uuid_old. @raise [ 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.
@api experimental
Private Instance Methods
Source
# File lib/bson/binary.rb, line 566 def from_uuid_old_to_csharp_legacy_uuid(hex) hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(.{16})\z/, '\4\3\2\1\6\5\8\7\9') end
Converts a UUID-old object to a csharp-legacy representation.
@param [ String
] hex The hexadecimal string to convert
@return [ String
] the csharp-legacy-formatted UUID
Source
# File lib/bson/binary.rb, line 575 def from_uuid_old_to_java_legacy_uuid(hex) hex.sub(/\A(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)(..)\z/) do (::Regexp.last_match[1..8].reverse + ::Regexp.last_match[9..16].reverse).join end end
Converts a UUID-old object to a java-legacy representation.
@param [ String
] hex The hexadecimal string to convert
@return [ String
] the java-legacy-formatted UUID
Source
Source
# File lib/bson/binary.rb, line 557 def from_uuid_old_to_standard_uuid(_hex) raise ArgumentError, 'BSON::Binary objects of type :uuid_old cannot be stringified to :standard representation' end
Tries to convert a UUID-old object to a standard representation, which is not supported.
@param [ String
] hex The hexadecimal string to convert
@raise [ ArgumentError ] because standard representation is not supported
Source
# File lib/bson/binary.rb, line 537 def from_uuid_old_to_uuid(representation) if representation.nil? raise ArgumentError, 'Representation must be specified for BSON::Binary objects of type :uuid_old' end hex = data.chars.map { |n| '%02x' % n.ord }.join handler = :"from_uuid_old_to_#{representation}_uuid" raise ArgumentError, "Invalid representation: #{representation}" unless respond_to?(handler, true) send(handler, hex) .sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5') end
Converts the UUID-old object to a UUID of the given representation.
@param [ Symbol
] representation The representation to target
@return [ String
] the UUID as a string
Source
# File lib/bson/binary.rb, line 518 def from_uuid_to_uuid(representation) if representation != :standard raise ArgumentError, 'Binary of type :uuid can only be stringified to :standard representation, ' \ "requested: #{representation.inspect}" end data .chars .map { |n| '%02x' % n.ord } .join .sub(/\A(.{8})(.{4})(.{4})(.{4})(.{12})\z/, '\1-\2-\3-\4-\5') end
Converts the Binary
UUID object to a UUID of the given representation. Currently, only :standard representation is supported.
@param [ Symbol
] representation The representation to target (must be
:standard)
@return [ String
] the UUID as a string
Source
# File lib/bson/binary.rb, line 498 def initialize_instance(data, type) @type = validate_type!(type) # The Binary class used to force encoding to BINARY when serializing to # BSON. Instead of doing that during serialization, perform this # operation during Binary construction to make it clear that once # the string is given to the Binary, the data is treated as a binary # string and not a text string in any encoding. data = data.dup.force_encoding('BINARY') unless data.encoding == Encoding.find('BINARY') @data = data end
initializes an instance of BSON::Binary
.
@param [ String
] data the data to initialize the object with @param [ Symbol
] type the type to assign the binary object
Source
# File lib/bson/binary.rb, line 626 def validate_integer_type!(type) @raw_type = type.chr.force_encoding('BINARY').freeze if type < USER_SUBTYPE raise BSON::Error::InvalidBinaryType, type unless TYPES.key?(@raw_type) return TYPES[@raw_type] end :user end
Test that the given integer type is valid.
@param [ Integer
] type the provided type
@return [ Symbol
] the symbolic type corresponding to the argument.
@raise [ BSON::Error::InvalidBinaryType
] if the type is invalid.
Source
# File lib/bson/binary.rb, line 645 def validate_symbol_type!(type) raise BSON::Error::InvalidBinaryType, type unless SUBTYPES.key?(type) @raw_type = SUBTYPES[type] type end
Test that the given symbol type is valid.
@param [ Symbol
] type the provided type
@return [ Symbol
] the symbolic type corresponding to the argument.
@raise [ BSON::Error::InvalidBinaryType
] if the type is invalid.
Source
# File lib/bson/binary.rb, line 604 def validate_type!(type) case type when Integer then validate_integer_type!(type) when String if type.length > 1 validate_symbol_type!(type.to_sym) else validate_integer_type!(type.bytes.first) end when Symbol then validate_symbol_type!(type) else raise BSON::Error::InvalidBinaryType, type end end
Validate the provided type is a valid type.
@api private
@example Validate the type.
binary.validate_type!(:user)
@param [ Symbol
| String
| Integer
] type The provided type.
@return [ Symbol
] the symbolic type corresponding to the argument.
@raise [ BSON::Error::InvalidBinaryType
] The the type is invalid.
@since 2.0.0