diff --git a/config.m4 b/config.m4 index b2a182d32..40e6b862a 100644 --- a/config.m4 +++ b/config.m4 @@ -168,6 +168,7 @@ if test "$PHP_MONGODB" != "no"; then src/BSON/Unserializable.c \ src/BSON/UTCDateTime.c \ src/BSON/UTCDateTimeInterface.c \ + src/BSON/VectorType.c \ src/MongoDB/BulkWrite.c \ src/MongoDB/BulkWriteCommand.c \ src/MongoDB/BulkWriteCommandResult.c \ diff --git a/config.w32 b/config.w32 index 66979ce95..898f52488 100644 --- a/config.w32 +++ b/config.w32 @@ -116,7 +116,7 @@ if (PHP_MONGODB != "no") { EXTENSION("mongodb", "php_phongo.c", null, PHP_MONGODB_CFLAGS); MONGODB_ADD_SOURCES("/src", "phongo_apm.c phongo_atomic.c phongo_bson.c phongo_bson_encode.c phongo_client.c phongo_compat.c phongo_error.c phongo_execute.c phongo_ini.c phongo_log.c phongo_util.c"); - MONGODB_ADD_SOURCES("/src/BSON", "Binary.c BinaryInterface.c Document.c Iterator.c DBPointer.c Decimal128.c Decimal128Interface.c Int64.c Javascript.c JavascriptInterface.c MaxKey.c MaxKeyInterface.c MinKey.c MinKeyInterface.c ObjectId.c ObjectIdInterface.c PackedArray.c Persistable.c Regex.c RegexInterface.c Serializable.c Symbol.c Timestamp.c TimestampInterface.c Type.c Undefined.c Unserializable.c UTCDateTime.c UTCDateTimeInterface.c"); + MONGODB_ADD_SOURCES("/src/BSON", "Binary.c BinaryInterface.c Document.c Iterator.c DBPointer.c Decimal128.c Decimal128Interface.c Int64.c Javascript.c JavascriptInterface.c MaxKey.c MaxKeyInterface.c MinKey.c MinKeyInterface.c ObjectId.c ObjectIdInterface.c PackedArray.c Persistable.c Regex.c RegexInterface.c Serializable.c Symbol.c Timestamp.c TimestampInterface.c Type.c Undefined.c Unserializable.c UTCDateTime.c UTCDateTimeInterface.c VectorType.c"); MONGODB_ADD_SOURCES("/src/MongoDB", "BulkWrite.c BulkWriteCommand.c BulkWriteCommandResult.c ClientEncryption.c Command.c Cursor.c CursorInterface.c Manager.c Query.c ReadConcern.c ReadPreference.c Server.c ServerApi.c ServerDescription.c Session.c TopologyDescription.c WriteConcern.c WriteConcernError.c WriteError.c WriteResult.c"); MONGODB_ADD_SOURCES("/src/MongoDB/Exception", "AuthenticationException.c BulkWriteException.c BulkWriteCommandException.c CommandException.c ConnectionException.c ConnectionTimeoutException.c EncryptionException.c Exception.c ExecutionTimeoutException.c InvalidArgumentException.c LogicException.c RuntimeException.c ServerException.c UnexpectedValueException.c"); MONGODB_ADD_SOURCES("/src/MongoDB/Monitoring", "CommandFailedEvent.c CommandStartedEvent.c CommandSubscriber.c CommandSucceededEvent.c LogSubscriber.c SDAMSubscriber.c Subscriber.c ServerChangedEvent.c ServerClosedEvent.c ServerHeartbeatFailedEvent.c ServerHeartbeatStartedEvent.c ServerHeartbeatSucceededEvent.c ServerOpeningEvent.c TopologyChangedEvent.c TopologyClosedEvent.c TopologyOpeningEvent.c functions.c"); diff --git a/php_phongo.c b/php_phongo.c index 6c9bd29fc..0691c176e 100644 --- a/php_phongo.c +++ b/php_phongo.c @@ -248,6 +248,7 @@ PHP_MINIT_FUNCTION(mongodb) /* {{{ */ php_phongo_timestamp_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_undefined_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_utcdatetime_init_ce(INIT_FUNC_ARGS_PASSTHRU); + php_phongo_vectortype_init_ce(INIT_FUNC_ARGS_PASSTHRU); php_phongo_cursor_interface_init_ce(INIT_FUNC_ARGS_PASSTHRU); diff --git a/src/BSON/Binary.c b/src/BSON/Binary.c index 4583ac8ab..64fc4a90a 100644 --- a/src/BSON/Binary.c +++ b/src/BSON/Binary.c @@ -16,16 +16,22 @@ #include #include +#include #include #include "php_phongo.h" +#include "phongo_bson_encode.h" #include "phongo_error.h" +#include "Binary.h" #include "Binary_arginfo.h" - -#define PHONGO_BINARY_UUID_SIZE 16 +#include "VectorType.h" zend_class_entry* php_phongo_binary_ce; +static phongo_bson_vector_type_t phongo_binary_get_vector_type_from_data(const uint8_t* data, uint32_t data_len); +static phongo_bson_vector_type_t phongo_binary_get_vector_type(const php_phongo_binary_t* intern); +static void phongo_binary_get_vector_as_array(const php_phongo_binary_t* intern, zval* return_value); + /* Initialize the object and return whether it was successful. An exception will * be thrown on error. */ static bool php_phongo_binary_init(php_phongo_binary_t* intern, const char* data, size_t data_len, zend_long type) @@ -40,6 +46,11 @@ static bool php_phongo_binary_init(php_phongo_binary_t* intern, const char* data return false; } + if ((type == BSON_SUBTYPE_VECTOR) && phongo_binary_get_vector_type_from_data((const uint8_t*) data, data_len) == PHONGO_BSON_VECTOR_TYPE_UNKNOWN) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Binary vector data is invalid"); + return false; + } + intern->data = estrndup(data, data_len); intern->data_len = data_len; intern->type = (uint8_t) type; @@ -272,8 +283,36 @@ static int php_phongo_binary_compare_objects(zval* o1, zval* o2) static HashTable* php_phongo_binary_get_debug_info(zend_object* object, int* is_temp) { - *is_temp = 1; - return php_phongo_binary_get_properties_hash(object, true); + *is_temp = 1; + HashTable* props = php_phongo_binary_get_properties_hash(object, true); + + php_phongo_binary_t* intern = Z_OBJ_BINARY(object); + + if (intern->type == BSON_SUBTYPE_VECTOR) { + zval vector; + + phongo_binary_get_vector_as_array(intern, &vector); + + if (EG(exception)) { + return props; + } + + zend_hash_str_update(props, "vector", sizeof("vector") - 1, &vector); + + zval vector_type; + zend_object* vector_type_case = phongo_bson_vector_type_to_case(phongo_binary_get_vector_type(intern)); + + // The vector should always be valid by this point, but check for an error + if (!vector_type_case) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Binary vector data is invalid"); + return props; + } + + ZVAL_OBJ_COPY(&vector_type, vector_type_case); + zend_hash_str_update(props, "vectorType", sizeof("vectorType") - 1, &vector_type); + } + + return props; } static HashTable* php_phongo_binary_get_properties(zend_object* object) @@ -297,14 +336,328 @@ void php_phongo_binary_init_ce(INIT_FUNC_ARGS) bool phongo_binary_new(zval* object, const char* data, size_t data_len, bson_subtype_t type) { - php_phongo_binary_t* intern; - object_init_ex(object, php_phongo_binary_ce); - intern = Z_BINARY_OBJ_P(object); - intern->data = estrndup(data, data_len); - intern->data_len = data_len; - intern->type = (uint8_t) type; + return php_phongo_binary_init(Z_BINARY_OBJ_P(object), data, data_len, type); +} - return true; +static inline void phongo_binary_init_vector_from_bson_key(php_phongo_binary_t* intern, const bson_t* doc, const char* key) +{ + bson_iter_t iter; + + if (!(bson_iter_init_find(&iter, doc, key) && BSON_ITER_HOLDS_VECTOR(&iter))) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "bson_iter_init_find failed to find binary vector in key \"%s\"", key); + return; + } + + uint32_t data_len; + const uint8_t* data; + + bson_iter_binary(&iter, NULL, &data_len, &data); + php_phongo_binary_init(intern, (const char*) data, data_len, BSON_SUBTYPE_VECTOR); +} + +static void phongo_binary_init_vector_from_float32_array(php_phongo_binary_t* intern, HashTable* vector) +{ + if (!zend_array_is_list(vector)) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector to be a list"); + return; + } + + const size_t vector_len = zend_array_count(vector); + + bson_t doc = BSON_INITIALIZER; + bson_vector_float32_view_t view; + + if (!BSON_APPEND_VECTOR_FLOAT32_UNINIT(&doc, "vector", vector_len, &view)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "BSON_APPEND_VECTOR_FLOAT32_UNINIT failed for vector of size %zu", vector_len); + return; + } + + zval* val; + size_t i = 0; + + ZEND_HASH_FOREACH_VAL_IND(vector, val) + { + if (Z_TYPE_P(val) != IS_DOUBLE) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector[%zu] to be a float, %s given", i, zend_zval_type_name(val)); + return; + } + + float v = (float) Z_DVAL_P(val); + + if (!bson_vector_float32_view_write(view, &v, 1, i)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "bson_vector_float32_view_write failed to write vector[%zu]", i); + return; + } + + i += 1; + } + ZEND_HASH_FOREACH_END(); + + phongo_binary_init_vector_from_bson_key(intern, &doc, "vector"); +} + +static void phongo_binary_init_vector_from_int8_array(php_phongo_binary_t* intern, HashTable* vector) +{ + if (!zend_array_is_list(vector)) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector to be a list"); + return; + } + + const size_t vector_len = zend_array_count(vector); + + bson_t doc = BSON_INITIALIZER; + bson_vector_int8_view_t view; + + if (!BSON_APPEND_VECTOR_INT8_UNINIT(&doc, "vector", vector_len, &view)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "BSON_APPEND_VECTOR_INT8_UNINIT failed for vector of size %zu", vector_len); + return; + } + + zval* val; + size_t i = 0; + + ZEND_HASH_FOREACH_VAL_IND(vector, val) + { + if (Z_TYPE_P(val) != IS_LONG) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector[%zu] to be an integer, %s given", i, zend_zval_type_name(val)); + return; + } + + if (Z_LVAL_P(val) < INT8_MIN || Z_LVAL_P(val) > INT8_MAX) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector[%zu] to be a signed 8-bit integer, %" PHONGO_LONG_FORMAT " given", i, Z_LVAL_P(val)); + return; + } + + int8_t v = (int8_t) Z_LVAL_P(val); + + if (!bson_vector_int8_view_write(view, &v, 1, i)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "bson_vector_int8_view_write failed to write vector[%zu]", i); + return; + } + + i += 1; + } + ZEND_HASH_FOREACH_END(); + + phongo_binary_init_vector_from_bson_key(intern, &doc, "vector"); +} + +static void phongo_binary_init_vector_from_packed_bit_array(php_phongo_binary_t* intern, HashTable* vector) +{ + if (!zend_array_is_list(vector)) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector to be a list"); + return; + } + + const size_t vector_len = zend_array_count(vector); + + bson_t doc = BSON_INITIALIZER; + bson_vector_packed_bit_view_t view; + + if (!BSON_APPEND_VECTOR_PACKED_BIT_UNINIT(&doc, "vector", vector_len, &view)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "BSON_APPEND_VECTOR_PACKED_BIT_UNINIT failed for vector of size %zu", vector_len); + return; + } + + zval* val; + size_t i = 0; + + ZEND_HASH_FOREACH_VAL_IND(vector, val) + { + if (Z_TYPE_P(val) != IS_LONG && Z_TYPE_P(val) != IS_TRUE && Z_TYPE_P(val) != IS_FALSE) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector[%zu] to be 0, 1, or a boolean, %s given", i, zend_zval_type_name(val)); + return; + } + + if (Z_TYPE_P(val) == IS_LONG && Z_LVAL_P(val) != 0 && Z_LVAL_P(val) != 1) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected vector[%zu] to be 0 or 1, %" PHONGO_LONG_FORMAT " given", i, Z_LVAL_P(val)); + return; + } + + bool v = zend_is_true(val); + + if (!bson_vector_packed_bit_view_pack_bool(view, &v, 1, i)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "bson_vector_packed_bit_view_pack_bool failed to write vector[%zu]", i); + return; + } + + i += 1; + } + ZEND_HASH_FOREACH_END(); + + phongo_binary_init_vector_from_bson_key(intern, &doc, "vector"); +} + +static PHP_METHOD(MongoDB_BSON_Binary, fromVector) +{ + HashTable* vector; + zend_object* type; + + object_init_ex(return_value, php_phongo_binary_ce); + php_phongo_binary_t* intern = Z_BINARY_OBJ_P(return_value); + + PHONGO_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_ARRAY_HT(vector) + Z_PARAM_OBJ_OF_CLASS(type, php_phongo_vectortype_ce) + PHONGO_PARSE_PARAMETERS_END(); + + switch (phongo_bson_vector_type_from_case(type)) { + case PHONGO_BSON_VECTOR_TYPE_FLOAT32: + phongo_binary_init_vector_from_float32_array(intern, vector); + return; + case PHONGO_BSON_VECTOR_TYPE_INT8: + phongo_binary_init_vector_from_int8_array(intern, vector); + return; + case PHONGO_BSON_VECTOR_TYPE_PACKED_BIT: + phongo_binary_init_vector_from_packed_bit_array(intern, vector); + return; + default: + phongo_throw_exception(PHONGO_ERROR_LOGIC, "Unsupported binary vector type: %s", Z_STRVAL_P(zend_enum_fetch_case_name(type))); + RETURN_THROWS(); + } +} + +static phongo_bson_vector_type_t phongo_binary_get_vector_type_from_data(const uint8_t* data, uint32_t data_len) +{ + if (bson_vector_int8_const_view_init(NULL, data, data_len)) { + return PHONGO_BSON_VECTOR_TYPE_INT8; + } + + if (bson_vector_float32_const_view_init(NULL, data, data_len)) { + return PHONGO_BSON_VECTOR_TYPE_FLOAT32; + } + + if (bson_vector_packed_bit_const_view_init(NULL, data, data_len)) { + return PHONGO_BSON_VECTOR_TYPE_PACKED_BIT; + } + + return PHONGO_BSON_VECTOR_TYPE_UNKNOWN; +} + +static phongo_bson_vector_type_t phongo_binary_get_vector_type(const php_phongo_binary_t* intern) +{ + return phongo_binary_get_vector_type_from_data((const uint8_t*) intern->data, intern->data_len); +} + +static PHP_METHOD(MongoDB_BSON_Binary, getVectorType) +{ + PHONGO_PARSE_PARAMETERS_NONE(); + + php_phongo_binary_t* intern = Z_BINARY_OBJ_P(getThis()); + + if (intern->type != BSON_SUBTYPE_VECTOR) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected Binary of type vector (%" PRId8 ") but it is %" PHONGO_LONG_FORMAT, BSON_SUBTYPE_VECTOR, intern->type); + RETURN_THROWS(); + } + + const char* type_case = phongo_bson_vector_type_to_name(phongo_binary_get_vector_type(intern)); + + // The vector should always be valid by this point, but check for an error + if (!type_case) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Binary vector data is invalid"); + RETURN_THROWS(); + } + + RETVAL_OBJ_COPY(zend_enum_get_case_cstr(php_phongo_vectortype_ce, type_case)); +} + +static void phongo_binary_get_vector_as_array(const php_phongo_binary_t* intern, zval* return_value) +{ + bson_t tmp_doc = BSON_INITIALIZER; + + switch (phongo_binary_get_vector_type(intern)) { + case PHONGO_BSON_VECTOR_TYPE_INT8: { + bson_vector_int8_const_view_t view; + + if (!bson_vector_int8_const_view_init(&view, (const uint8_t*) intern->data, intern->data_len) || + !BSON_APPEND_ARRAY_FROM_VECTOR_INT8(&tmp_doc, "vector", view)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Failed to convert binary vector data to an array"); + bson_destroy(&tmp_doc); + RETURN_THROWS(); + } + + break; + } + case PHONGO_BSON_VECTOR_TYPE_FLOAT32: { + bson_vector_float32_const_view_t view; + + if (!bson_vector_float32_const_view_init(&view, (const uint8_t*) intern->data, intern->data_len) || + !BSON_APPEND_ARRAY_FROM_VECTOR_FLOAT32(&tmp_doc, "vector", view)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Failed to convert binary vector data to an array"); + bson_destroy(&tmp_doc); + RETURN_THROWS(); + } + + break; + } + case PHONGO_BSON_VECTOR_TYPE_PACKED_BIT: { + bson_vector_packed_bit_const_view_t view; + + if (!bson_vector_packed_bit_const_view_init(&view, (const uint8_t*) intern->data, intern->data_len) || + !BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BIT(&tmp_doc, "vector", view)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Failed to convert binary vector data to an array"); + bson_destroy(&tmp_doc); + RETURN_THROWS(); + } + + break; + } + default: + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "Binary vector data is invalid"); + RETURN_THROWS(); + } + + bson_iter_t iter; + + if (!(bson_iter_init_find(&iter, &tmp_doc, "vector") && BSON_ITER_HOLDS_ARRAY(&iter))) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "bson_iter_init_find failed for appended vector"); + bson_destroy(&tmp_doc); + RETURN_THROWS(); + } + + uint32_t data_len; + const uint8_t* data; + + bson_iter_array(&iter, &data_len, &data); + + bson_t tmp_vector = BSON_INITIALIZER; + + if (!bson_init_static(&tmp_vector, data, data_len)) { + phongo_throw_exception(PHONGO_ERROR_UNEXPECTED_VALUE, "bson_init_static failed for appended vector"); + bson_destroy(&tmp_doc); + RETURN_THROWS(); + } + + php_phongo_bson_state state; + PHONGO_BSON_INIT_STATE(state); + state.is_visiting_array = true; + + if (!php_phongo_bson_to_zval_ex(&tmp_vector, &state)) { + // Exception already thrown + bson_destroy(&tmp_doc); + zval_ptr_dtor(&state.zchild); + php_phongo_bson_typemap_dtor(&state.map); + RETURN_THROWS(); + } + + bson_destroy(&tmp_doc); + php_phongo_bson_typemap_dtor(&state.map); + + RETURN_ZVAL(&state.zchild, 0, 1); +} + +static PHP_METHOD(MongoDB_BSON_Binary, toArray) +{ + PHONGO_PARSE_PARAMETERS_NONE(); + + php_phongo_binary_t* intern = Z_BINARY_OBJ_P(getThis()); + + if (intern->type != BSON_SUBTYPE_VECTOR) { + phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "Expected Binary of type vector (%" PRId8 ") but it is %" PHONGO_LONG_FORMAT, BSON_SUBTYPE_VECTOR, intern->type); + RETURN_THROWS(); + } + + phongo_binary_get_vector_as_array(intern, return_value); } diff --git a/src/BSON/Binary.stub.php b/src/BSON/Binary.stub.php index 134fac6c7..9eb7b00ee 100644 --- a/src/BSON/Binary.stub.php +++ b/src/BSON/Binary.stub.php @@ -63,6 +63,12 @@ final class Binary implements BinaryInterface, \JsonSerializable, Type, \Stringa */ public const TYPE_SENSITIVE = UNKNOWN; + /** + * @var int + * @cvalue BSON_SUBTYPE_VECTOR + */ + public const TYPE_VECTOR = UNKNOWN; + /** * @var int * @cvalue BSON_SUBTYPE_USER @@ -71,10 +77,16 @@ final class Binary implements BinaryInterface, \JsonSerializable, Type, \Stringa final public function __construct(string $data, int $type = Binary::TYPE_GENERIC) {} + final public static function fromVector(array $vector, VectorType $vectorType): Binary {} + final public function getData(): string {} final public function getType(): int {} + final public function getVectorType(): VectorType {} + + final public function toArray(): array {} + final public static function __set_state(array $properties): Binary {} final public function __toString(): string {} diff --git a/src/BSON/Binary_arginfo.h b/src/BSON/Binary_arginfo.h index 1363dc09d..832e42e90 100644 --- a/src/BSON/Binary_arginfo.h +++ b/src/BSON/Binary_arginfo.h @@ -1,17 +1,28 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: a08dec3b63e23fbde350360b32fa0323e47069da */ + * Stub hash: 3c433c48b47c68051a55617ddbb9ed0f50c21484 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_MongoDB_BSON_Binary___construct, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, type, IS_LONG, 0, "MongoDB\\BSON\\Binary::TYPE_GENERIC") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Binary_fromVector, 0, 2, MongoDB\\BSON\\Binary, 0) + ZEND_ARG_TYPE_INFO(0, vector, IS_ARRAY, 0) + ZEND_ARG_OBJ_INFO(0, vectorType, MongoDB\\BSON\\VectorType, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_getData, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_getType, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Binary_getVectorType, 0, 0, MongoDB\\BSON\\VectorType, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_toArray, 0, 0, IS_ARRAY, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_MongoDB_BSON_Binary___set_state, 0, 1, MongoDB\\BSON\\Binary, 0) ZEND_ARG_TYPE_INFO(0, properties, IS_ARRAY, 0) ZEND_END_ARG_INFO() @@ -22,16 +33,18 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary___unse ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary___serialize, 0, 0, IS_ARRAY, 0) -ZEND_END_ARG_INFO() +#define arginfo_class_MongoDB_BSON_Binary___serialize arginfo_class_MongoDB_BSON_Binary_toArray ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_MongoDB_BSON_Binary_jsonSerialize, 0, 0, IS_MIXED, 0) ZEND_END_ARG_INFO() static ZEND_METHOD(MongoDB_BSON_Binary, __construct); +static ZEND_METHOD(MongoDB_BSON_Binary, fromVector); static ZEND_METHOD(MongoDB_BSON_Binary, getData); static ZEND_METHOD(MongoDB_BSON_Binary, getType); +static ZEND_METHOD(MongoDB_BSON_Binary, getVectorType); +static ZEND_METHOD(MongoDB_BSON_Binary, toArray); static ZEND_METHOD(MongoDB_BSON_Binary, __set_state); static ZEND_METHOD(MongoDB_BSON_Binary, __toString); static ZEND_METHOD(MongoDB_BSON_Binary, __unserialize); @@ -41,8 +54,11 @@ static ZEND_METHOD(MongoDB_BSON_Binary, jsonSerialize); static const zend_function_entry class_MongoDB_BSON_Binary_methods[] = { ZEND_ME(MongoDB_BSON_Binary, __construct, arginfo_class_MongoDB_BSON_Binary___construct, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + ZEND_ME(MongoDB_BSON_Binary, fromVector, arginfo_class_MongoDB_BSON_Binary_fromVector, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, getData, arginfo_class_MongoDB_BSON_Binary_getData, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, getType, arginfo_class_MongoDB_BSON_Binary_getType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + ZEND_ME(MongoDB_BSON_Binary, getVectorType, arginfo_class_MongoDB_BSON_Binary_getVectorType, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + ZEND_ME(MongoDB_BSON_Binary, toArray, arginfo_class_MongoDB_BSON_Binary_toArray, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __set_state, arginfo_class_MongoDB_BSON_Binary___set_state, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __toString, arginfo_class_MongoDB_BSON_Binary___toString, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) ZEND_ME(MongoDB_BSON_Binary, __unserialize, arginfo_class_MongoDB_BSON_Binary___unserialize, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) @@ -114,6 +130,12 @@ static zend_class_entry *register_class_MongoDB_BSON_Binary(zend_class_entry *cl zend_declare_class_constant_ex(class_entry, const_TYPE_SENSITIVE_name, &const_TYPE_SENSITIVE_value, ZEND_ACC_PUBLIC, NULL); zend_string_release(const_TYPE_SENSITIVE_name); + zval const_TYPE_VECTOR_value; + ZVAL_LONG(&const_TYPE_VECTOR_value, BSON_SUBTYPE_VECTOR); + zend_string *const_TYPE_VECTOR_name = zend_string_init_interned("TYPE_VECTOR", sizeof("TYPE_VECTOR") - 1, 1); + zend_declare_class_constant_ex(class_entry, const_TYPE_VECTOR_name, &const_TYPE_VECTOR_value, ZEND_ACC_PUBLIC, NULL); + zend_string_release(const_TYPE_VECTOR_name); + zval const_TYPE_USER_DEFINED_value; ZVAL_LONG(&const_TYPE_USER_DEFINED_value, BSON_SUBTYPE_USER); zend_string *const_TYPE_USER_DEFINED_name = zend_string_init_interned("TYPE_USER_DEFINED", sizeof("TYPE_USER_DEFINED") - 1, 1); diff --git a/src/BSON/VectorType.c b/src/BSON/VectorType.c new file mode 100644 index 000000000..8b9fdae18 --- /dev/null +++ b/src/BSON/VectorType.c @@ -0,0 +1,76 @@ +/* + * Copyright 2025-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "php_phongo.h" +#include "VectorType.h" +#include "VectorType_arginfo.h" + +zend_class_entry* php_phongo_vectortype_ce; + +phongo_bson_vector_type_t phongo_bson_vector_type_from_name(const char* name) +{ + if (!strcmp(name, PHONGO_BSON_VECTOR_TYPE_FLOAT32_NAME)) { + return PHONGO_BSON_VECTOR_TYPE_FLOAT32; + } + + if (!strcmp(name, PHONGO_BSON_VECTOR_TYPE_INT8_NAME)) { + return PHONGO_BSON_VECTOR_TYPE_INT8; + } + + if (!strcmp(name, PHONGO_BSON_VECTOR_TYPE_PACKED_BIT_NAME)) { + return PHONGO_BSON_VECTOR_TYPE_PACKED_BIT; + } + + return PHONGO_BSON_VECTOR_TYPE_UNKNOWN; +} + +const char* phongo_bson_vector_type_to_name(phongo_bson_vector_type_t type) +{ + switch (type) { + case PHONGO_BSON_VECTOR_TYPE_FLOAT32: + return PHONGO_BSON_VECTOR_TYPE_FLOAT32_NAME; + case PHONGO_BSON_VECTOR_TYPE_INT8: + return PHONGO_BSON_VECTOR_TYPE_INT8_NAME; + case PHONGO_BSON_VECTOR_TYPE_PACKED_BIT: + return PHONGO_BSON_VECTOR_TYPE_PACKED_BIT_NAME; + default: + return NULL; + } +} + +phongo_bson_vector_type_t phongo_bson_vector_type_from_case(zend_object* case_obj) +{ + return phongo_bson_vector_type_from_name(Z_STRVAL_P(zend_enum_fetch_case_name(case_obj))); +} + +zend_object* phongo_bson_vector_type_to_case(phongo_bson_vector_type_t type) +{ + const char* name = phongo_bson_vector_type_to_name(type); + + if (!name) { + return NULL; + } + + return zend_enum_get_case_cstr(php_phongo_vectortype_ce, name); +} + +void php_phongo_vectortype_init_ce(INIT_FUNC_ARGS) +{ + php_phongo_vectortype_ce = register_class_MongoDB_BSON_VectorType(); +} diff --git a/src/BSON/VectorType.h b/src/BSON/VectorType.h new file mode 100644 index 000000000..78d096d28 --- /dev/null +++ b/src/BSON/VectorType.h @@ -0,0 +1,36 @@ +/* + * Copyright 2025-present MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PHONGO_BSON_VECTORTYPE_H +#define PHONGO_BSON_VECTORTYPE_H + +#define PHONGO_BSON_VECTOR_TYPE_FLOAT32_NAME "Float32" +#define PHONGO_BSON_VECTOR_TYPE_INT8_NAME "Int8" +#define PHONGO_BSON_VECTOR_TYPE_PACKED_BIT_NAME "PackedBit" + +typedef enum { + PHONGO_BSON_VECTOR_TYPE_FLOAT32 = 0x27, + PHONGO_BSON_VECTOR_TYPE_INT8 = 0x03, + PHONGO_BSON_VECTOR_TYPE_PACKED_BIT = 0x10, + PHONGO_BSON_VECTOR_TYPE_UNKNOWN = 0, +} phongo_bson_vector_type_t; + +phongo_bson_vector_type_t phongo_bson_vector_type_from_name(const char* name); +const char* phongo_bson_vector_type_to_name(phongo_bson_vector_type_t type); +phongo_bson_vector_type_t phongo_bson_vector_type_from_case(zend_object* case_obj); +zend_object* phongo_bson_vector_type_to_case(phongo_bson_vector_type_t type); + +#endif /* PHONGO_BSON_VECTORTYPE_H */ diff --git a/src/BSON/VectorType.stub.php b/src/BSON/VectorType.stub.php new file mode 100644 index 000000000..191e3fdfd --- /dev/null +++ b/src/BSON/VectorType.stub.php @@ -0,0 +1,15 @@ +milliseconds); return; } + // TODO: confirm that this handles binary vector if (instanceof_function(Z_OBJCE_P(object), php_phongo_binary_ce)) { php_phongo_binary_t* intern = Z_BINARY_OBJ_P(object); diff --git a/src/phongo_classes.h b/src/phongo_classes.h index 1bdb0fafb..87afdd34f 100644 --- a/src/phongo_classes.h +++ b/src/phongo_classes.h @@ -364,6 +364,7 @@ extern zend_class_entry* php_phongo_symbol_ce; extern zend_class_entry* php_phongo_timestamp_ce; extern zend_class_entry* php_phongo_undefined_ce; extern zend_class_entry* php_phongo_utcdatetime_ce; +extern zend_class_entry* php_phongo_vectortype_ce; extern zend_class_entry* php_phongo_binary_interface_ce; extern zend_class_entry* php_phongo_decimal128_interface_ce; @@ -412,6 +413,7 @@ extern void php_phongo_type_init_ce(INIT_FUNC_ARGS); extern void php_phongo_undefined_init_ce(INIT_FUNC_ARGS); extern void php_phongo_unserializable_init_ce(INIT_FUNC_ARGS); extern void php_phongo_utcdatetime_init_ce(INIT_FUNC_ARGS); +extern void php_phongo_vectortype_init_ce(INIT_FUNC_ARGS); extern void php_phongo_binary_interface_init_ce(INIT_FUNC_ARGS); extern void php_phongo_decimal128_interface_init_ce(INIT_FUNC_ARGS); diff --git a/src/phongo_structs.h b/src/phongo_structs.h index 7b083e612..2fc3c3ae2 100644 --- a/src/phongo_structs.h +++ b/src/phongo_structs.h @@ -194,7 +194,7 @@ typedef struct { typedef struct { char* data; - int data_len; + size_t data_len; uint8_t type; HashTable* properties; zend_object std; diff --git a/tests/bson/bson-binary-constants.phpt b/tests/bson/bson-binary-constants.phpt index 7b224769f..edf8358a2 100644 --- a/tests/bson/bson-binary-constants.phpt +++ b/tests/bson/bson-binary-constants.phpt @@ -14,6 +14,7 @@ var_dump(Binary::TYPE_MD5); var_dump(Binary::TYPE_ENCRYPTED); var_dump(Binary::TYPE_COLUMN); var_dump(Binary::TYPE_SENSITIVE); +var_dump(Binary::TYPE_VECTOR); var_dump(Binary::TYPE_USER_DEFINED); ?> @@ -29,5 +30,6 @@ int(5) int(6) int(7) int(8) +int(9) int(128) ===DONE=== diff --git a/tests/bson/bson-binary-fromVector-001.phpt b/tests/bson/bson-binary-fromVector-001.phpt new file mode 100644 index 000000000..2ccd522a4 --- /dev/null +++ b/tests/bson/bson-binary-fromVector-001.phpt @@ -0,0 +1,71 @@ +--TEST-- +MongoDB\BSON\Binary::fromVector() construction of various vector types +--FILE-- + +===DONE=== + +--EXPECTF-- +object(MongoDB\BSON\Binary)#%d (%d) { + ["data"]=> + string(18) "%a" + ["type"]=> + int(9) + ["vector"]=> + array(4) { + [0]=> + float(1) + [1]=> + float(-1) + [2]=> + float(0.5) + [3]=> + float(-0.5) + } + ["vectorType"]=> + enum(MongoDB\BSON\VectorType::Float32) +} +object(MongoDB\BSON\Binary)#%d (%d) { + ["data"]=> + string(6) "%a" + ["type"]=> + int(9) + ["vector"]=> + array(4) { + [0]=> + int(-128) + [1]=> + int(0) + [2]=> + int(1) + [3]=> + int(127) + } + ["vectorType"]=> + enum(MongoDB\BSON\VectorType::Int8) +} +object(MongoDB\BSON\Binary)#%d (%d) { + ["data"]=> + string(3) "%a" + ["type"]=> + int(9) + ["vector"]=> + array(4) { + [0]=> + int(1) + [1]=> + int(0) + [2]=> + int(1) + [3]=> + int(0) + } + ["vectorType"]=> + enum(MongoDB\BSON\VectorType::PackedBit) +} +===DONE=== diff --git a/tests/bson/bson-binary-fromVector_error-001.phpt b/tests/bson/bson-binary-fromVector_error-001.phpt new file mode 100644 index 000000000..efb47753c --- /dev/null +++ b/tests/bson/bson-binary-fromVector_error-001.phpt @@ -0,0 +1,24 @@ +--TEST-- +MongoDB\BSON\Binary::fromVector() construction errors for VectorType::Float32 +--FILE-- + 1.0], MongoDB\BSON\VectorType::Float32); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector([1.0, 2], MongoDB\BSON\VectorType::Float32); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +?> +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector to be a list +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector[1] to be a float, int given +===DONE=== diff --git a/tests/bson/bson-binary-fromVector_error-002.phpt b/tests/bson/bson-binary-fromVector_error-002.phpt new file mode 100644 index 000000000..735a76930 --- /dev/null +++ b/tests/bson/bson-binary-fromVector_error-002.phpt @@ -0,0 +1,36 @@ +--TEST-- +MongoDB\BSON\Binary::fromVector() construction errors for VectorType::Int8 +--FILE-- + 1], MongoDB\BSON\VectorType::Int8); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector([1, 2.0], MongoDB\BSON\VectorType::Int8); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector([1, -129], MongoDB\BSON\VectorType::Int8); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector([1, 128], MongoDB\BSON\VectorType::Int8); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +?> +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector to be a list +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector[1] to be an integer, float given +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector[1] to be a signed 8-bit integer, -129 given +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector[1] to be a signed 8-bit integer, 128 given +===DONE=== diff --git a/tests/bson/bson-binary-fromVector_error-003.phpt b/tests/bson/bson-binary-fromVector_error-003.phpt new file mode 100644 index 000000000..f26e09be5 --- /dev/null +++ b/tests/bson/bson-binary-fromVector_error-003.phpt @@ -0,0 +1,30 @@ +--TEST-- +MongoDB\BSON\Binary::fromVector() construction errors for VectorType::PackedBit +--FILE-- + 1], MongoDB\BSON\VectorType::PackedBit); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector([true, 1.0], MongoDB\BSON\VectorType::PackedBit); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector([true, 2], MongoDB\BSON\VectorType::PackedBit); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +?> +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector to be a list +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector[1] to be 0, 1, or a boolean, float given +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Expected vector[1] to be 0 or 1, 2 given +===DONE=== diff --git a/tests/bson/bson-binary-getvectortype-001.phpt b/tests/bson/bson-binary-getvectortype-001.phpt new file mode 100644 index 000000000..bb7719609 --- /dev/null +++ b/tests/bson/bson-binary-getvectortype-001.phpt @@ -0,0 +1,18 @@ +--TEST-- +MongoDB\BSON\Binary::getVectorType() +--FILE-- +getVectorType()); +var_dump(MongoDB\BSON\Binary::fromVector([1, 2, 3, 4], MongoDB\BSON\VectorType::Int8)->getVectorType()); +var_dump(MongoDB\BSON\Binary::fromVector([1, 0, true, false], MongoDB\BSON\VectorType::PackedBit)->getVectorType()); + +?> +===DONE=== + +--EXPECT-- +enum(MongoDB\BSON\VectorType::Float32) +enum(MongoDB\BSON\VectorType::Int8) +enum(MongoDB\BSON\VectorType::PackedBit) +===DONE=== + diff --git a/tests/bson/bson-binary-serialization-002.phpt b/tests/bson/bson-binary-serialization-002.phpt index 1fe9be000..80f4b3212 100644 --- a/tests/bson/bson-binary-serialization-002.phpt +++ b/tests/bson/bson-binary-serialization-002.phpt @@ -9,6 +9,7 @@ $tests = [ ["\0foo", MongoDB\BSON\Binary::TYPE_GENERIC], [hex2bin('123e4567e89b12d3a456426655440000'), MongoDB\BSON\Binary::TYPE_UUID], [md5('foobar', true), MongoDB\BSON\Binary::TYPE_MD5], + [hex2bin('030001020304'), MongoDB\BSON\Binary::TYPE_VECTOR], ]; foreach ($tests as $test) { @@ -94,4 +95,44 @@ object(MongoDB\BSON\Binary)#%d (%d) { int(5) } +object(MongoDB\BSON\Binary)#%d (%d) { + ["data"]=> + string(6) "%a" + ["type"]=> + int(9) + ["vector"]=> + array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + } + ["vectorType"]=> + enum(MongoDB\BSON\VectorType::Int8) +} +string(70) "O:19:"MongoDB\BSON\Binary":2:{s:4:"data";s:6:"%a";s:4:"type";i:9;}" +object(MongoDB\BSON\Binary)#%d (%d) { + ["data"]=> + string(6) "%a" + ["type"]=> + int(9) + ["vector"]=> + array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) + } + ["vectorType"]=> + enum(MongoDB\BSON\VectorType::Int8) +} + ===DONE=== diff --git a/tests/bson/bson-binary-serialization_error-007.phpt b/tests/bson/bson-binary-serialization_error-007.phpt new file mode 100644 index 000000000..eba1b20da --- /dev/null +++ b/tests/bson/bson-binary-serialization_error-007.phpt @@ -0,0 +1,18 @@ +--TEST-- +MongoDB\BSON\Binary unserialization requires valid vector data (__serialize and __unserialize) +--FILE-- + +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Binary vector data is invalid +===DONE=== diff --git a/tests/bson/bson-binary-set_state-001.phpt b/tests/bson/bson-binary-set_state-001.phpt index 84f2468f2..1564e639b 100644 --- a/tests/bson/bson-binary-set_state-001.phpt +++ b/tests/bson/bson-binary-set_state-001.phpt @@ -9,6 +9,7 @@ $tests = [ ["\0foo", MongoDB\BSON\Binary::TYPE_GENERIC], [hex2bin('123e4567e89b12d3a456426655440000'), MongoDB\BSON\Binary::TYPE_UUID], [md5('foobar', true), MongoDB\BSON\Binary::TYPE_MD5], + [hex2bin('030001020304'), MongoDB\BSON\Binary::TYPE_VECTOR], ]; foreach ($tests as $test) { @@ -41,13 +42,18 @@ foreach ($tests as $test) { )) %r\\?%rMongoDB\BSON\Binary::__set_state(array( - 'data' => '>Egè›Ó¤VBfUD' . "\0" . '' . "\0" . '', + 'data' => '%a', 'type' => 4, )) %r\\?%rMongoDB\BSON\Binary::__set_state(array( - 'data' => '8Xö"0¬<‘_0 fCÆ?', + 'data' => '%a', 'type' => 5, )) +%r\\?%rMongoDB\BSON\Binary::__set_state(array( + 'data' => '%a', + 'type' => 9, +)) + ===DONE=== diff --git a/tests/bson/bson-binary-set_state_error-004.phpt b/tests/bson/bson-binary-set_state_error-004.phpt new file mode 100644 index 000000000..34516707b --- /dev/null +++ b/tests/bson/bson-binary-set_state_error-004.phpt @@ -0,0 +1,18 @@ +--TEST-- +MongoDB\BSON\Binary::__set_state() requires valid vector data +--FILE-- + '', 'type' => MongoDB\BSON\Binary::TYPE_VECTOR]); +}, 'MongoDB\Driver\Exception\InvalidArgumentException'), "\n"; + +?> +===DONE=== + +--EXPECT-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +Binary vector data is invalid +===DONE=== diff --git a/tests/bson/bson-binary-toarray-001.phpt b/tests/bson/bson-binary-toarray-001.phpt new file mode 100644 index 000000000..dc551ca25 --- /dev/null +++ b/tests/bson/bson-binary-toarray-001.phpt @@ -0,0 +1,44 @@ +--TEST-- +MongoDB\BSON\Binary::toArray() +--FILE-- +toArray()); +var_dump(MongoDB\BSON\Binary::fromVector([1, 2, 3, 4], MongoDB\BSON\VectorType::Int8)->toArray()); +var_dump(MongoDB\BSON\Binary::fromVector([1, 0, true, false], MongoDB\BSON\VectorType::PackedBit)->toArray()); + +?> +===DONE=== + +--EXPECT-- +array(4) { + [0]=> + float(1) + [1]=> + float(-1) + [2]=> + float(0.5) + [3]=> + float(-0.5) +} +array(4) { + [0]=> + int(1) + [1]=> + int(2) + [2]=> + int(3) + [3]=> + int(4) +} +array(4) { + [0]=> + int(1) + [1]=> + int(0) + [2]=> + int(1) + [3]=> + int(0) +} +===DONE=== diff --git a/tests/bson/bson-binary_error-005.phpt b/tests/bson/bson-binary_error-005.phpt new file mode 100644 index 000000000..b35d8d5d2 --- /dev/null +++ b/tests/bson/bson-binary_error-005.phpt @@ -0,0 +1,35 @@ +--TEST-- +MongoDB\BSON\Binary vector methods argument count errors +--SKIPIF-- + +=', '7.99'); ?> +--FILE-- +toArray(2); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() use ($bv) { + $bv->getVectorType(2); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +echo throws(function() { + MongoDB\BSON\Binary::fromVector(); +}, MongoDB\Driver\Exception\InvalidArgumentException::class), "\n"; + +?> +===DONE=== + +--EXPECTF-- +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +MongoDB\BSON\Binary::toArray() expects exactly 0 %r(argument|parameter)%rs, 1 given +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +MongoDB\BSON\Binary::getVectorType() expects exactly 0 %r(argument|parameter)%rs, 1 given +OK: Got MongoDB\Driver\Exception\InvalidArgumentException +MongoDB\BSON\Binary::fromVector() expects exactly 2 %r(argument|parameter)%rs, 0 given +===DONE=== diff --git a/tests/bson/bson-vectortype-001.phpt b/tests/bson/bson-vectortype-001.phpt new file mode 100644 index 000000000..c72dd2cf4 --- /dev/null +++ b/tests/bson/bson-vectortype-001.phpt @@ -0,0 +1,17 @@ +--TEST-- +MongoDB\BSON\VectorType cases +--FILE-- + +===DONE=== + +--EXPECT-- +enum(MongoDB\BSON\VectorType::Float32) +enum(MongoDB\BSON\VectorType::Int8) +enum(MongoDB\BSON\VectorType::PackedBit) +===DONE===