@@ -493,6 +493,7 @@ static PyObject *py_loader_port_invoke(PyObject *self, PyObject *var_args)
493
493
/* Obtain Python loader implementation */
494
494
impl = loader_get_impl (py_loader_tag );
495
495
496
+ /* TODO: Remove this check when we implement this: https://github.com/metacall/core/issues/231 */
496
497
if (impl == NULL )
497
498
{
498
499
PyErr_SetString (PyExc_ValueError , "Invalid Python loader instance, MetaCall Port must be used from MetaCall CLI" );
@@ -622,6 +623,7 @@ static PyObject *py_loader_port_await(PyObject *self, PyObject *var_args)
622
623
/* Obtain Python loader implementation */
623
624
impl = loader_get_impl (py_loader_tag );
624
625
626
+ /* TODO: Remove this check when we implement this: https://github.com/metacall/core/issues/231 */
625
627
if (impl == NULL )
626
628
{
627
629
PyErr_SetString (PyExc_ValueError , "Invalid Python loader instance, MetaCall Port must be used from MetaCall CLI" );
@@ -778,6 +780,184 @@ static PyObject *py_loader_port_inspect(PyObject *self, PyObject *args)
778
780
return result ;
779
781
}
780
782
783
+ static PyObject * py_loader_port_value_create_ptr (PyObject * self , PyObject * args )
784
+ {
785
+ static const char format [] = "O:metacall_value_create_ptr" ;
786
+ PyObject * pointer ;
787
+
788
+ (void )self ;
789
+
790
+ /* Parse arguments */
791
+ if (!PyArg_ParseTuple (args , (char * )format , & pointer ))
792
+ {
793
+ PyErr_SetString (PyExc_TypeError , "Invalid number of arguments, use it like: metacall_value_create_ptr(None); or metacall_value_create_ptr(previous_allocated_ptr);" );
794
+ return py_loader_port_none ();
795
+ }
796
+
797
+ if (!PyCapsule_CheckExact (pointer ) && pointer != Py_None )
798
+ {
799
+ PyErr_SetString (PyExc_TypeError , "Invalid parameter type in first argument must be None or a PyCapsule (i.e a previously allocated pointer)" );
800
+ return py_loader_port_none ();
801
+ }
802
+
803
+ if (pointer == Py_None )
804
+ {
805
+ return py_loader_impl_capsule_new_null ();
806
+ }
807
+ else
808
+ {
809
+ /* Get capsule pointer */
810
+ const char * name = PyCapsule_GetName (pointer );
811
+ void * pointer_addr = PyCapsule_GetPointer (pointer , name );
812
+
813
+ /* Return a copy of the capsule */
814
+ return PyCapsule_New (pointer_addr , name , NULL );
815
+ }
816
+ }
817
+
818
+ static const char py_loader_capsule_reference_id [] = "__metacall_capsule_reference__" ;
819
+
820
+ static void py_loader_port_value_reference_destroy (PyObject * capsule )
821
+ {
822
+ void * ref = PyCapsule_GetPointer (capsule , py_loader_capsule_reference_id );
823
+ void * v = PyCapsule_GetContext (capsule );
824
+
825
+ metacall_value_destroy (ref );
826
+ metacall_value_destroy (v );
827
+ }
828
+
829
+ static PyObject * py_loader_port_value_reference (PyObject * self , PyObject * args )
830
+ {
831
+ static const char format [] = "O:metacall_value_reference" ;
832
+ PyObject * obj ;
833
+ loader_impl impl ;
834
+ void * v , * ref ;
835
+ PyObject * capsule ;
836
+
837
+ (void )self ;
838
+
839
+ /* Parse arguments */
840
+ if (!PyArg_ParseTuple (args , (char * )format , & obj ))
841
+ {
842
+ PyErr_SetString (PyExc_TypeError , "Invalid number of arguments, use it like: metacall_value_reference(obj);" );
843
+ goto error_none ;
844
+ }
845
+
846
+ /* Obtain Python loader implementation */
847
+ impl = loader_get_impl (py_loader_tag );
848
+
849
+ /* TODO: When using the port outside MetaCall this is going to segfault for functions and similar
850
+ * structures that require py loader internal structure to be initialized. For those cases, we
851
+ * must implement this: https://github.com/metacall/core/issues/231
852
+ */
853
+ v = py_loader_impl_capi_to_value (impl , obj , py_loader_impl_capi_to_value_type (impl , obj ));
854
+
855
+ if (v == NULL )
856
+ {
857
+ PyErr_SetString (PyExc_ValueError , "Failed to convert the Python object to MetaCall value." );
858
+ goto error_none ;
859
+ }
860
+
861
+ ref = metacall_value_reference (v );
862
+
863
+ if (ref == NULL )
864
+ {
865
+ PyErr_SetString (PyExc_ValueError , "Failed to create the reference from MetaCall value." );
866
+ goto error_value ;
867
+ }
868
+
869
+ capsule = PyCapsule_New (ref , py_loader_capsule_reference_id , & py_loader_port_value_reference_destroy );
870
+
871
+ if (capsule == NULL )
872
+ {
873
+ goto error_ref ;
874
+ }
875
+
876
+ if (PyCapsule_SetContext (capsule , v ) != 0 )
877
+ {
878
+ goto error_ref ;
879
+ }
880
+
881
+ return capsule ;
882
+
883
+ error_ref :
884
+ metacall_value_destroy (ref );
885
+ error_value :
886
+ metacall_value_destroy (v );
887
+ error_none :
888
+ return py_loader_port_none ();
889
+ }
890
+
891
+ static PyObject * py_loader_port_value_dereference (PyObject * self , PyObject * args )
892
+ {
893
+ static const char format [] = "O:metacall_value_dereference" ;
894
+ PyObject * capsule ;
895
+ const char * name = NULL ;
896
+ void * ref , * v ;
897
+ loader_impl impl ;
898
+ PyObject * result ;
899
+
900
+ (void )self ;
901
+
902
+ /* Parse arguments */
903
+ if (!PyArg_ParseTuple (args , (char * )format , & capsule ))
904
+ {
905
+ PyErr_SetString (PyExc_TypeError , "Invalid number of arguments, use it like: metacall_value_dereference(ptr);" );
906
+ return py_loader_port_none ();
907
+ }
908
+
909
+ /* Check if it is a valid reference */
910
+ if (!PyCapsule_CheckExact (capsule ))
911
+ {
912
+ PyErr_SetString (PyExc_TypeError , "Invalid parameter type in first argument must be a PyCapsule (i.e a previously allocated pointer)" );
913
+ return py_loader_port_none ();
914
+ }
915
+
916
+ /* Check if it is a valid MetaCall reference */
917
+ name = PyCapsule_GetName (capsule );
918
+
919
+ if (name != py_loader_capsule_reference_id )
920
+ {
921
+ PyErr_SetString (PyExc_TypeError , "Invalid reference, argument must be a PyCapsule from MetaCall" );
922
+ return py_loader_port_none ();
923
+ }
924
+
925
+ /* Get the reference */
926
+ ref = PyCapsule_GetPointer (capsule , name );
927
+
928
+ if (ref == NULL )
929
+ {
930
+ return py_loader_port_none ();
931
+ }
932
+
933
+ /* Get the value */
934
+ v = metacall_value_dereference (ref );
935
+
936
+ /* Validate the result */
937
+ if (v != PyCapsule_GetContext (capsule ))
938
+ {
939
+ PyErr_SetString (PyExc_TypeError , "Invalid reference, the PyCapsule context does not match the dereferenced value" );
940
+ return py_loader_port_none ();
941
+ }
942
+
943
+ /* Obtain Python loader implementation */
944
+ impl = loader_get_impl (py_loader_tag );
945
+
946
+ /* TODO: When using the port outside MetaCall this is going to segfault for functions and similar
947
+ * structures that require py loader internal structure to be initialized. For those cases, we
948
+ * must implement this: https://github.com/metacall/core/issues/231
949
+ */
950
+ result = py_loader_impl_value_to_capi (impl , value_type_id (v ), v );
951
+
952
+ if (result == NULL )
953
+ {
954
+ PyErr_SetString (PyExc_ValueError , "Failed to convert the MetaCall value to Python object." );
955
+ return py_loader_port_none ();
956
+ }
957
+
958
+ return result ;
959
+ }
960
+
781
961
static PyMethodDef metacall_methods [] = {
782
962
{ "metacall_load_from_file" , py_loader_port_load_from_file , METH_VARARGS ,
783
963
"Loads a script from file." },
@@ -793,6 +973,12 @@ static PyMethodDef metacall_methods[] = {
793
973
"Get information about all loaded objects." },
794
974
{ "metacall" , py_loader_port_invoke , METH_VARARGS ,
795
975
"Call a function anonymously." },
976
+ { "metacall_value_create_ptr" , py_loader_port_value_create_ptr , METH_VARARGS ,
977
+ "Create a new value of type Pointer." },
978
+ { "metacall_value_reference" , py_loader_port_value_reference , METH_VARARGS ,
979
+ "Create a new value of type Pointer." },
980
+ { "metacall_value_dereference" , py_loader_port_value_dereference , METH_VARARGS ,
981
+ "Get the data which a value of type Pointer is pointing to." },
796
982
{ NULL , NULL , 0 , NULL }
797
983
};
798
984
0 commit comments