class Mongo::Crypt::Binary

A wrapper around mongocrypt_binary_t, a non-owning buffer of uint-8 byte data. Each Binary instance keeps a copy of the data passed to it in order to keep that data alive.

@api private

Public Class Methods

from_data(data) click to toggle source

Initialize a Binary object with a string. The Binary object will store a copy of the specified string and destroy the allocated memory when it goes out of scope.

@param [ String ] data A string to be wrapped by the Binary object

@return [ Mongo::Crypt::Binary ] A new binary object

# File lib/mongo/crypt/binary.rb, line 87
def self.from_data(data)
  self.new(data: data)
end
from_pointer(pointer) click to toggle source

Initialize a Binary object from an existing pointer to a mongocrypt_binary_t object.

@param [ FFI::Pointer ] pointer A pointer to an existing

mongocrypt_binary_t object

@return [ Mongo::Crypt::Binary ] A new binary object

# File lib/mongo/crypt/binary.rb, line 76
def self.from_pointer(pointer)
  self.new(pointer: pointer)
end
new(data: nil, pointer: nil) click to toggle source

Create a new Binary object that wraps a byte string

@param [ String ] data The data string wrapped by the

byte buffer (optional)

@param [ FFI::Pointer ] pointer A pointer to an existing

mongocrypt_binary_t object

@note When initializing a Binary object with a string or a pointer, it is recommended that you use self.from_pointer or self.from_data methods

# File lib/mongo/crypt/binary.rb, line 39
def initialize(data: nil, pointer: nil)
  if data
    # Represent data string as array of uint-8 bytes
    bytes = data.unpack('C*')

    # FFI::MemoryPointer automatically frees memory when it goes out of scope
    @data_p = FFI::MemoryPointer.new(bytes.length)
              .write_array_of_uint8(bytes)

    # FFI::AutoPointer uses a custom release strategy to automatically free
    # the pointer once this object goes out of scope
    @bin = FFI::AutoPointer.new(
      Binding.mongocrypt_binary_new_from_data(@data_p, bytes.length),
      Binding.method(:mongocrypt_binary_destroy)
    )
  elsif pointer
    # If the Binary class is used this way, it means that the pointer
    # for the underlying mongocrypt_binary_t object is allocated somewhere
    # else. It is not the responsibility of this class to de-allocate data.
    @bin = pointer
  else
    # FFI::AutoPointer uses a custom release strategy to automatically free
    # the pointer once this object goes out of scope
    @bin = FFI::AutoPointer.new(
      Binding.mongocrypt_binary_new,
      Binding.method(:mongocrypt_binary_destroy)
    )
  end
end
wrap_string(str) { |binary_p| ... } click to toggle source

Wraps a String with a mongocrypt_binary_t, yielding an FFI::Pointer to the wrapped struct.

# File lib/mongo/crypt/binary.rb, line 145
def self.wrap_string(str)
  binary_p = Binding.mongocrypt_binary_new_from_data(
    FFI::MemoryPointer.from_string(str),
    str.bytesize,
  )
  begin
    yield binary_p
  ensure
    Binding.mongocrypt_binary_destroy(binary_p)
  end
end

Public Instance Methods

ref() click to toggle source

Returns the reference to the underlying mongocrypt_binary_t object

@return [ FFI::Pointer ] The underlying mongocrypt_binary_t object

# File lib/mongo/crypt/binary.rb, line 139
def ref
  @bin
end
to_s() click to toggle source

Returns the data stored as a string

@return [ String ] Data stored in the mongocrypt_binary_t as a string

# File lib/mongo/crypt/binary.rb, line 129
def to_s
  str_p = Binding.mongocrypt_binary_data(ref)
  len = Binding.mongocrypt_binary_len(ref)
  str_p.read_string(len)
end
write(data) click to toggle source

Overwrite the existing data wrapped by this Binary object

@note The data passed in must not take up more memory than the original memory allocated to the underlying mongocrypt_binary_t object. Do NOT use this method unless required to do so by libmongocrypt.

@param [ String ] data The new string data to be wrapped by this binary object

@return [ true ] Always true

@raise [ ArgumentError ] Raises when trying to write more data than was originally allocated or when writing to an object that already owns data.

# File lib/mongo/crypt/binary.rb, line 104
def write(data)
  if @data
    raise ArgumentError, 'Cannot write to an owned Binary'
  end

  # Cannot write a string that's longer than the space currently allocated
  # by the mongocrypt_binary_t object
  str_p = Binding.mongocrypt_binary_data(ref)
  len = Binding.mongocrypt_binary_len(ref)

  if len < data.bytesize
    raise ArgumentError.new(
      "Cannot write #{data.bytesize} bytes of data to a Binary object " +
      "that was initialized with #{Binding.mongocrypt_binary_len(@bin)} bytes."
    )
  end

  str_p.put_bytes(0, data)

  true
end