How to access python class from C extension? - c

I have my extension for Python written in C. Currently I need to process in a function of my extension objects of a type declared in some external pure python module (Say, its name is ext_module). First of all I need to ensure that input object type corresponds some class from ext_module. How can I implement this?
Some additional code:
static PyObject * extensionFunction( PyObject* self, PyObject *args ) {
const char *inputString = NULL;
PyObject *inputList = NULL;
if ( 0 == PyArg_ParseTuple( args, "sO", &inputString, &inputList ) ) {
return NULL;
}
if ( 0 != PyList_Check( inputList ) ) {
// here I need to check whether the list items are instances of ext_module.ExtClass
} else {
PyErr_SetString( PyExc_TypeError, "extensionFunction: expected list" );
return NULL;
}
// process arguments
Py_RETURN_NONE;
}
Actually I can just try to call the expected methods and get an exception NotImplementedError, but I'm not sure if this is correct approach.

Related

Kotlin/Native to C dylib : How to access class members in a instance object which returned by a method?

I am trying to learn Kotlin/Native C interop
I exported some Kotlin classes as C dynamic Lib and succeeded in access methods with primitive return types
But When trying to access class members in a instance object which returned by a method, the object contains something named as pinned
Code sample:
#Serializable
data class Persons (
val results: Array<Result>,
val info: Info
)
class RandomUserApiJS {
fun getPersonsDirect() : Persons {
return runBlocking {
RandomUserApi().getPersons()
}
}
}
Now when using them in C codeblocks,
In this image, note that the persons obj only showing a field named pinned and no other member functions found.
Since I don't know that much in C/C++ and can't investigate further.
Please help me to understand to access instance members of Kotlin Class in exported C lib?
Header file for ref:
https://gist.github.com/RageshAntony/a0b9007376084fa8b213b022b58f9886
for your gist
https://gist.github.com/RageshAntony/a0b9007376084fa8b213b022b58f9886
I modified the following:
// I comment this annotation
// #Serializable
data class Persons(
val results: List<Result>,
val info: Info,
/**
* the Result's properties too many
* I will use a simple data class for this example
* how to get c array from Persons (also suitable any iterable)
*/
val testList: List<Simple>,
) {
public fun toJson() = Json.encodeToString(this)
companion object {
public fun fromJson(json: String) = Json.decodeFromString<Persons>(json)
}
val arena = Arena()
fun getTestListForC(size: CPointer<IntVar>): CPointer<COpaquePointerVar> {
size.pointed.value = testList.size
return arena.allocArray<COpaquePointerVar>(testList.size) {
this.value = StableRef.create(testList[it]).asCPointer()
}
}
fun free() {
arena.clear()
}
}
/**
* kotlin <-> c bridge is primitive type
* like int <-> Int
* like char* <-> String
* so the Simple class has two primitive properties
*/
data class Simple(
val name: String,
val age: Int,
)
#include <stdio.h>
#include "libnative_api.h"
int main(int argc, char **argv) {
libnative_ExportedSymbols* lib = libnative_symbols();
libnative_kref_MathNative mn = lib->kotlin.root.MathNative.MathNative();
const char *a = lib->kotlin.root.MathNative.mul(mn,5,6); // working
printf ("Math Resullt %s\n",a);
libnative_kref_RandomUserApiJS pr = lib->kotlin.root.RandomUserApiJS.RandomUserApiJS();
libnative_kref_Persons persons = lib->kotlin.root.RandomUserApiJS.getPersonsDirect(pr);
// when accessing above persons obj, only a field 'pinned' availabe, nothing else
int size;
libnative_kref_Simple* list = (libnative_kref_Simple *)lib->kotlin.root.Persons.getTestListForC(persons, &size);
printf("size = %d\n", size);
for (int i = 0; i < size; ++i) {
const char *name = lib->kotlin.root.Simple.get_name(list[i]);
int age = lib->kotlin.root.Simple.get_age(list[i]);
printf("%s\t%d\n", name, age);
}
lib->kotlin.root.Persons.free(persons);
return 0;
}
// for output
Math Resullt The answer is 30
size = 3
name1 1
name2 2
name3 3
But I don't think calling kotlin lib through C is a good behavior, because kotlin native is not focused on improving performance for now, in my opinion, all functions that can be implemented with kotlin native can find solutions implemented in pure c, So I'm more focused on how to access the c lib from kotlin. Of course, it's a good solution if you absolutely need to access klib from c, but I'm still not very satisfied with it, then I may create a github template to better solve kotlin-interop from c.But that's not the point of this answer.

How to access JSON data passed to c in jni?

My java program passes JSONObject to native program like this:
import org.json.simple.JSONObject;
class json{
static{
System.loadLibrary("json");
}
private native void json(JSONObject j);
public static void main(String args[]){
json js = new json();
JSONObject j = new JSONObject();
j.put("name","someone");
j.put("age", 15);
js.json(j);
}
}
how to access these data in c?
#include<stdio.h>
#include<jni.h>
#include "json.h"
#include "cJSON.h"
JNIEXPORT void JNICALL Java_json_json(JNIEnv *env, jobject obj, jobject j){
return;
}
i couldn't find any reference on how to access json data from jobject in c.
I'm new to jni. is there any other way to do it?
Accessing the JSON data from the C code via JNI is not much different from accessing it via Java. In Java you would write:
System.out.println("name = " + j.get("name"));
System.out.println("age = " + j.get("age"));
The C code is basically the same, just much more verbose, since
You need to get the class object to call methods on them
You need to construct jstring instances for the keys passed to get
You must convert the jstring you get from j.get("name") to a C string
You must release that string after use
You must manually unbox the java.lang.Integer that you get
The code below does just that:
#include<stdio.h>
#include<jni.h>
#include "json.h"
// Notice that "cJSON.h" is not needed
JNIEXPORT void JNICALL Java_json_json(JNIEnv *env, jobject obj, jobject json) {
// Get the Class object for JSONObject.
jclass JSONObjectClass = (*env)->GetObjectClass(env, json);
// Get the ID of the "get" method that we must call.
// Notice that due to type erasure, both the parameter and the return value
// are just plain Objects in the type signature.
jmethodID getID = (*env)->GetMethodID(env, JSONObjectClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
if (getID == NULL) return;
// Create java.lang.String instances for the keys we pass to j.get.
jstring nameKey = (*env)->NewStringUTF(env, "name");
jstring ageKey = (*env)->NewStringUTF(env, "age");
if (nameKey == NULL || ageKey == NULL) return;
// Actually get the name object. Since we know that the value added
// in the Java code is a string, we just cast the jobject to jstring.
jstring name = (jstring) (*env)->CallObjectMethod(env, json, getID, nameKey);
if (name == NULL) return;
// Get a C string that can be used with the usual C functions.
const char *name_cstr = (*env)->GetStringUTFChars(env, name, NULL);
if (name_cstr == NULL) return;
printf("name = %s\n", name_cstr);
// Once done, the string must be released.
(*env)->ReleaseStringUTFChars(env, name, name_cstr);
name_cstr = NULL;
// Get the java.lang.Integer object representing the age.
jobject ageObj = (*env)->CallObjectMethod(env, json, getID, ageKey);
if (ageObj == NULL) return;
// Unbox the java.lang.Integer manually.
jclass IntegerClass = (*env)->GetObjectClass(env, ageObj);
jmethodID intValueID = (*env)->GetMethodID(env, IntegerClass, "intValue", "()I");
if (intValueID == NULL) return;
jint age = (*env)->CallIntMethod(env, ageObj, intValueID);
printf("age = %d\n", (int) age);
}
More complicated use is done the same way: Check what you would write in Java, and find a way to call the same methods with the same values in C using the JNI functions.

Extracting jansson JSON data

I am using the C jansson library http://www.digip.org/jansson/
It's quite easy to use https://jansson.readthedocs.org/en/2.7/tutorial.html#the-program
But I cannot get a simple int out of my JSON string. I can successfully receive and load a string of JSON (as in I get no errors, nothing is null) but when I use the jansson get functions to get an int, my int is always 0 even though using steps and breakpoints, the jansson function process an in is not returning 0.
The JSON string looks like this:
{"type":3}
Here is the code:
static void foo(json_t *jsonRoot) {
// json root is error checked even before this, and is not null
if (jsonRoot == NULL) {
return;
}
// Trying to get type = 3
json_t *j_type;
int type = 0;
j_type = json_object_get(jsonRoot, "type");
if (!json_is_integer(j_type)) {
printf("Not an int!\n");
return;
} else {
// I get in to the else
// json_integer_value has a its own internal check and
// will return 0 if the value is not an int, but it is not
// returning 0. It is running the macro json_to_integer(json)->value
type = json_integer_value(j_type);
}
printf("type is %d\n", type);
// type is 0
}
My issue was with strtoll. I had to redefine it.

Pointers, functions and arrays in D Programming Language

I'm writing a method to output to several output streams at once, the way I got it set up right now is that I have a LogController, LogFile and LogConsole, the latter two are implementations of the Log interface.
What I'm trying to do right now adding a method to the LogController that attaches any implementation of the Log interface.
How I want to do this is as follows: in the LogController I have an associative array, in which I store pointers to Log objects. When the writeOut method of the LogController is called, I want it to then run over the elements of the array and call their writeOut methods too. The latter I can do, but the previous is proving to be difficult.
Mage/Utility/LogController.d
module Mage.Utility.LogController;
import std.stdio;
interface Log {
public void writeOut(string s);
}
class LogController {
private Log*[string] m_Logs;
public this() {
}
public void attach(string name, ref Log l) {
foreach (string key; m_Logs.keys) {
if (name is key) return;
}
m_Logs[name] = &l;
}
public void writeOut(string s) {
foreach (Log* log; m_Logs) {
log.writeOut(s);
}
}
}
Mage/Utility/LogFile.d
module Mage.Utility.LogFile;
import std.stdio;
import std.datetime;
import Mage.Utility.LogController;
class LogFile : Log {
private File fp;
private string path;
public this(string path) {
this.fp = File(path, "a+");
this.path = path;
}
public void writeOut(string s) {
this.fp.writefln("[%s] %s", this.timestamp(), s);
}
private string timestamp() {
return Clock.currTime().toISOExtString();
}
}
I've already tried multiple things with the attach functions, and none of them. The build fails with the following error:
Mage\Root.d(0,0): Error: function Mage.Utility.LogController.LogController.attach (string name, ref Log l) is not callable using argument types (string, LogFile)
This is the incriminating function:
public void initialise(string logfile = DEFAULT_LOG_FILENAME) {
m_Log = new LogController();
LogFile lf = new LogFile(logfile);
m_Log.attach("Log File", lf);
}
Can anyone tell me where I'm going wrong here? I'm stumped and I haven't been able to find the answer anywhere. I've tried a multitude of different solutions and none of them work.
Classes and interfaces in D are reference types, so Log* is redundant - remove the *. Similarly, there is no need to use ref in ref Log l - that's like taking a pointer by reference in C++.
This is the cause of the error message you posted - variables passed by reference must match in type exactly. Removing the ref should solve the error.

Class Array in D

Can I create a class array in D? Something like:
interface A {}
class AA: A {}
class AB: A {}
class AC: A {}
ClassList!A list = new ClassList!A {AA, AB, AC};
void testf(ulong testv) {
A a = new list[testv];
}
Yes, that's possible, though not necessarily exactly how you have it there. You can make a list of types with a type tuple:
import std.typetuple;
alias list = TypeTuple!(AA, AB, AC);
But, you can't index it like an array at runtime; trying new list[n] will be a compile time error. Instead, you'll create a helper function that loops over it and returns the instance, like this:
foreach(index, type; list)
if(index == testv) {
a = new type();
break;
}
The way that compiles is foreach(foo; compile_time_list) actually becomes a big unrolled loop. The generated code is as if you wrote:
if(0 == testv) { a = new AA(); goto end; }
if(1 == testv) { a = new AB(); goto end; }
if(2 == testv) { a = new AC(); goto end; }
end:
So that works with runtime values, bridging the gap between the compile time list and the array index you want.
It's worth noting that this isn't necessarily the most efficient, but unless your class list has like a thousand entries, i doubt that would matter. Another option for more speed is to generate a switch statement at compile time from your list, then mix that in. The switch statement will compile to a more efficient lookup table. But odds are the simple loop is fine.
Anyway, putting it together, we get:
import std.stdio;
interface A {}
class AA: A {}
class AB: A {}
class AC: A {}
import std.typetuple;
alias list = TypeTuple!(AA, AB, AC);
void testf(ulong testv) {
A a;
foreach(index, type; list)
if(index == testv) {
a = new type();
break;
}
if(a is null)
writeln("bad type index");
else {
writeln(typeid(cast(Object) a), " was created");
}
}
void main() {
testf(0);
testf(1);
testf(2);
testf(3);
}
Result:
$ ./test50
test50.AA was created
test50.AB was created
test50.AC was created
bad type index
just what we wanted.
BTW, the typeid(cast(Object) a) might look weird, that's fetching the dynamic class of the type. It has to cast to Object first because otherwise, it would print the interface name. Since D interfaces aren't necessarily D classes (they can also be COM objects or C++ classes), the typeid isn't always available. A cast to Object ensures that it is a D class and thus grabs the run time type details.
EDIT: I saw you asked on the newsgroup as well for checking the base class in the loop. Here's how to do that:
You could write your own tuple template for it, or just let the
compile fail on the factory function: the A a = new T(); will
fail if A isn't a base class or interface of T.
Putting the check in the list could look like this:
bool checkClassList(Base, T...)() {
foreach(t; T) {
static if(!is(t : Base))
static assert(0, t.stringof ~ " is not a child of " ~ Base.stringof);
}
return true;
}
template ClassList(Base, T...) if(checkClassList!(Base, T)) {
alias ClassList = T;
}
Usage:
alias list = ClassList!(A, AA, AB, AC); // good
add:
class B {}
alias list = ClassList!(A, AA, AB, AC, B);
and get error:
test50.d(12): Error: static assert "B is not a child of A"
test50.d(19): instantiated from here: checkClassList!(A, AA, AB, AC, B)

Resources