2020
2121#include "php_phongo.h"
2222#include "phongo_error.h"
23+ #include "Binary.h"
2324#include "Binary_arginfo.h"
24-
25- #define PHONGO_BINARY_UUID_SIZE 16
25+ #include "BinaryVector_arginfo.h"
2626
2727zend_class_entry * php_phongo_binary_ce ;
2828
29+ static phongo_bson_vector_type_t phongo_binary_get_vector_type_from_data (const uint8_t * data , uint32_t data_len );
30+
2931/* Initialize the object and return whether it was successful. An exception will
3032 * be thrown on error. */
3133static bool php_phongo_binary_init (php_phongo_binary_t * intern , const char * data , size_t data_len , zend_long type )
@@ -40,6 +42,11 @@ static bool php_phongo_binary_init(php_phongo_binary_t* intern, const char* data
4042 return false;
4143 }
4244
45+ if ((type == BSON_SUBTYPE_VECTOR ) && phongo_binary_get_vector_type_from_data ((const uint8_t * ) data , data_len ) == PHONGO_BSON_VECTOR_TYPE_INVALID ) {
46+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT , "Binary vector data is invalid" );
47+ return false;
48+ }
49+
4350 intern -> data = estrndup (data , data_len );
4451 intern -> data_len = data_len ;
4552 intern -> type = (uint8_t ) type ;
@@ -299,6 +306,7 @@ bool phongo_binary_new(zval* object, const char* data, size_t data_len, bson_sub
299306{
300307 php_phongo_binary_t * intern ;
301308
309+ // TODO: Support BinaryVector
302310 object_init_ex (object , php_phongo_binary_ce );
303311
304312 intern = Z_BINARY_OBJ_P (object );
@@ -308,3 +316,250 @@ bool phongo_binary_new(zval* object, const char* data, size_t data_len, bson_sub
308316
309317 return true;
310318}
319+
320+ /* MongoDB\BSON\BinaryVector implementation */
321+
322+ zend_class_entry * php_phongo_binaryvector_ce ;
323+
324+ static PHP_METHOD (MongoDB_BSON_BinaryVector , __construct )
325+ {
326+ php_phongo_binary_t * intern ;
327+ zval * vector ;
328+ zend_long vector_type ;
329+
330+ intern = Z_BINARY_OBJ_P (getThis ());
331+
332+ PHONGO_PARSE_PARAMETERS_START (2 , 2 )
333+ Z_PARAM_ARRAY (vector )
334+ Z_PARAM_LONG (vector_type )
335+ PHONGO_PARSE_PARAMETERS_END ();
336+
337+ if (!zend_array_is_list (Z_ARRVAL_P (vector ))) {
338+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT , "Expected vector to be a list" );
339+ return ;
340+ }
341+
342+ const size_t vector_len = zend_array_count (Z_ARRVAL_P (vector ));
343+
344+ /*
345+ bson_t doc = BSON_INITIALIZER;
346+
347+ php_phongo_zval_to_bson(vector, PHONGO_BSON_NONE, &doc, NULL);
348+
349+ if (EG(exception)) {
350+ return;
351+ }
352+
353+ bson_iter_t iter;
354+ bson_error_t error;
355+
356+ bson_iter_init(&iter, &doc);
357+
358+ if (!BSON_APPEND_VECTOR_INT8_FROM_ARRAY(&bson, "vector", &iter, &err)) {
359+ phongo_throw_exception(PHONGO_ERROR_INVALID_ARGUMENT, "%s", error.message);
360+ return;
361+ }
362+ */
363+
364+ bson_t doc = BSON_INITIALIZER ;
365+
366+ if (vector_type == PHONGO_BSON_VECTOR_TYPE_INT8 ) {
367+ bson_vector_int8_view_t view ;
368+
369+ if (!BSON_APPEND_VECTOR_INT8_UNINIT (& doc , "vector" , vector_len , & view )) {
370+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "BSON_APPEND_VECTOR_INT8_UNINIT failed for vector of size %zu" , vector_len );
371+ RETURN_THROWS ();
372+ }
373+
374+ zval * val ;
375+ size_t i = 0 ;
376+
377+ ZEND_HASH_FOREACH_VAL_IND (Z_ARRVAL_P (vector ), val )
378+ {
379+ if (Z_TYPE_P (val ) != IS_LONG ) {
380+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT , "Expected vector[%zu] to be an integer, %s given" , i , zend_zval_type_name (val ));
381+ RETURN_THROWS ();
382+ }
383+
384+ if (Z_LVAL_P (val ) < INT8_MIN || Z_LVAL_P (val ) > INT8_MAX ) {
385+ 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 ));
386+ RETURN_THROWS ();
387+ }
388+
389+ int8_t v = (int8_t ) Z_LVAL_P (val );
390+
391+ if (!bson_vector_int8_view_write (view , & v , 1 , i )) {
392+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "bson_vector_int8_view_write failed to write vector[%zu]" , i );
393+ RETURN_THROWS ();
394+ }
395+
396+ i += 1 ;
397+ }
398+ ZEND_HASH_FOREACH_END ();
399+ } else {
400+ // TODO: Support PHONGO_BSON_VECTOR_TYPE_FLOAT32 and PHONGO_BSON_VECTOR_TYPE_PACKED_BIT
401+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT , "Unsupported vector type: %" PHONGO_LONG_FORMAT , vector_type );
402+ RETURN_THROWS ();
403+ }
404+
405+ bson_iter_t iter ;
406+
407+ if (bson_iter_init_find (& iter , & doc , "vector" ) && BSON_ITER_HOLDS_BINARY (& iter )) {
408+ uint32_t data_len ;
409+ const uint8_t * data ;
410+
411+ bson_iter_binary (& iter , NULL , & data_len , & data );
412+ php_phongo_binary_init (intern , (const char * ) data , data_len , BSON_SUBTYPE_VECTOR );
413+ }
414+ }
415+
416+ static phongo_bson_vector_type_t phongo_binary_get_vector_type_from_data (const uint8_t * data , uint32_t data_len )
417+ {
418+ if (bson_vector_int8_const_view_init (NULL , data , data_len )) {
419+ return PHONGO_BSON_VECTOR_TYPE_INT8 ;
420+ }
421+
422+ if (bson_vector_float32_const_view_init (NULL , data , data_len )) {
423+ return PHONGO_BSON_VECTOR_TYPE_FLOAT32 ;
424+ }
425+
426+ if (bson_vector_packed_bit_const_view_init (NULL , data , data_len )) {
427+ return PHONGO_BSON_VECTOR_TYPE_PACKED_BIT ;
428+ }
429+
430+ return PHONGO_BSON_VECTOR_TYPE_INVALID ;
431+ }
432+
433+ static phongo_bson_vector_type_t phongo_binary_get_vector_type (const php_phongo_binary_t * intern )
434+ {
435+ return phongo_binary_get_vector_type_from_data ((const uint8_t * ) intern -> data , intern -> data_len );
436+ }
437+
438+ static PHP_METHOD (MongoDB_BSON_BinaryVector , getVectorType )
439+ {
440+ PHONGO_PARSE_PARAMETERS_NONE ();
441+
442+ php_phongo_binary_t * intern = Z_BINARY_OBJ_P (getThis ());
443+ phongo_bson_vector_type_t type = phongo_binary_get_vector_type (intern );
444+
445+ // The vector should always be valid by this point, but check for an error
446+ if (type == PHONGO_BSON_VECTOR_TYPE_INVALID ) {
447+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "Binary vector data is invalid" );
448+ RETURN_THROWS ();
449+ }
450+
451+ RETURN_LONG (type );
452+ }
453+
454+ static PHP_METHOD (MongoDB_BSON_BinaryVector , toArray )
455+ {
456+ PHONGO_PARSE_PARAMETERS_NONE ();
457+
458+ php_phongo_binary_t * intern = Z_BINARY_OBJ_P (getThis ());
459+ phongo_bson_vector_type_t type = phongo_binary_get_vector_type (intern );
460+
461+ // The vector should always be valid by this point, but check for an error
462+ if (type == PHONGO_BSON_VECTOR_TYPE_INVALID ) {
463+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "Binary vector data is invalid" );
464+ RETURN_THROWS ();
465+ }
466+
467+ bson_t doc = BSON_INITIALIZER ;
468+
469+ if (type == PHONGO_BSON_VECTOR_TYPE_INT8 ) {
470+ bson_vector_int8_const_view_t view ;
471+
472+ if (!bson_vector_int8_const_view_init (& view , (const uint8_t * ) intern -> data , intern -> data_len ) ||
473+ !BSON_APPEND_ARRAY_FROM_VECTOR_INT8 (& doc , "vector" , view )) {
474+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "Failed to convert binary vector data to an array" );
475+ bson_destroy (& doc );
476+ RETURN_THROWS ();
477+ }
478+ } else if (type == PHONGO_BSON_VECTOR_TYPE_FLOAT32 ) {
479+ bson_vector_float32_const_view_t view ;
480+
481+ if (!bson_vector_float32_const_view_init (& view , (const uint8_t * ) intern -> data , intern -> data_len ) ||
482+ !BSON_APPEND_ARRAY_FROM_VECTOR_FLOAT32 (& doc , "vector" , view )) {
483+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "Failed to convert binary vector data to an array" );
484+ bson_destroy (& doc );
485+ RETURN_THROWS ();
486+ }
487+ } else if (type == PHONGO_BSON_VECTOR_TYPE_PACKED_BIT ) {
488+ bson_vector_packed_bit_const_view_t view ;
489+
490+ if (!bson_vector_packed_bit_const_view_init (& view , (const uint8_t * ) intern -> data , intern -> data_len ) ||
491+ !BSON_APPEND_ARRAY_FROM_VECTOR_PACKED_BIT (& doc , "vector" , view )) {
492+ phongo_throw_exception (PHONGO_ERROR_UNEXPECTED_VALUE , "Failed to convert binary vector data to an array" );
493+ bson_destroy (& doc );
494+ RETURN_THROWS ();
495+ }
496+ }
497+
498+ php_phongo_bson_state state ;
499+ PHONGO_BSON_INIT_STATE (state );
500+ state .is_visiting_array = true;
501+
502+ if (!php_phongo_bson_to_zval_ex (& doc , & state )) {
503+ // Exception already thrown
504+ bson_destroy (& doc );
505+ zval_ptr_dtor (& state .zchild );
506+ php_phongo_bson_typemap_dtor (& state .map );
507+ RETURN_THROWS ();
508+ }
509+
510+ bson_destroy (& doc );
511+ php_phongo_bson_typemap_dtor (& state .map );
512+
513+ RETURN_ZVAL (& state .zchild , 0 , 1 );
514+ }
515+
516+ static PHP_METHOD (MongoDB_BSON_BinaryVector , __set_state )
517+ {
518+ php_phongo_binary_t * intern ;
519+ HashTable * props ;
520+ zval * array ;
521+
522+ PHONGO_PARSE_PARAMETERS_START (1 , 1 )
523+ Z_PARAM_ARRAY (array )
524+ PHONGO_PARSE_PARAMETERS_END ();
525+
526+ /* This implementation is similar to Binary::__set_state(), except that we
527+ * initialize a BinaryVector object and also validate its data. */
528+ object_init_ex (return_value , php_phongo_binaryvector_ce );
529+
530+ intern = Z_BINARY_OBJ_P (return_value );
531+ props = Z_ARRVAL_P (array );
532+
533+ php_phongo_binary_init_from_hash (intern , props );
534+
535+ if (intern -> type != BSON_SUBTYPE_VECTOR || phongo_binary_get_vector_type (intern ) == PHONGO_BSON_VECTOR_TYPE_INVALID ) {
536+ phongo_throw_exception (PHONGO_ERROR_INVALID_ARGUMENT , "Binary vector data is invalid" );
537+ RETURN_THROWS ();
538+ }
539+ }
540+
541+ /* MongoDB\BSON\BinaryVector object handlers */
542+ static zend_object_handlers php_phongo_handler_binaryvector ;
543+
544+ static zend_object * php_phongo_binaryvector_create_object (zend_class_entry * class_type )
545+ {
546+ php_phongo_binary_t * intern = zend_object_alloc (sizeof (php_phongo_binary_t ), class_type );
547+
548+ zend_object_std_init (& intern -> std , class_type );
549+ object_properties_init (& intern -> std , class_type );
550+
551+ intern -> std .handlers = & php_phongo_handler_binaryvector ;
552+
553+ return & intern -> std ;
554+ }
555+
556+ void php_phongo_binaryvector_init_ce (INIT_FUNC_ARGS )
557+ {
558+ php_phongo_binaryvector_ce = register_class_MongoDB_BSON_BinaryVector (php_phongo_binary_ce );
559+ php_phongo_binaryvector_ce -> create_object = php_phongo_binaryvector_create_object ;
560+
561+ memcpy (& php_phongo_handler_binaryvector , & php_phongo_handler_binary , sizeof (zend_object_handlers ));
562+ // TODO: Override debug and prop handlers to include vector
563+ //php_phongo_handler_binaryvector.get_debug_info = php_phongo_binaryvector_get_debug_info;
564+ //php_phongo_handler_binaryvector.get_properties = php_phongo_binaryvector_get_properties;
565+ }
0 commit comments