javaandroidcswigtypemaps

Swig how to define a typemap that converts a C typedefined Boolean to java boolean


I'm using swig to create a glue between C and Java (Android). I have defined a type Boolean in C and used like this : (MyGlue.h)

typedef enum boolean {
    TRUE = 0x1,
    FALSE = 0x0
} Boolean;

Boolean booleanValue = TRUE;

Boolean isRunning() {
    return booleanValue;
}

Then in Java I want to do the following:

if(MyGlue.isRunning) {
    ..do something..
}

the problem I have is that MyGlue.isRunning returns an int

Can I make a swig typemap that converts an int to a boolean value?

I have tried the following, but I did not fully grasp the usage of a swig typmap: in my swig config file added the follwing

%typemap(out) Boolean {
    $result = boolean($1);
}

I'm not getting what I want, besides I don't know where to put the conversion from int to boolean like (return_value != 0) that I suppose I need to specify somewhere in the typemap.

Is it possible to achieve this conversion with swig so externally I deal with booleans and not with ints?


Solution

  • You're on the right track with the typemaps and in fact you could do it using in/out typemaps, but you'd also need to set the jstype/jnitype/jtype typemaps too in order to change the signature of generated methods.

    In general with Java typemaps there's a conversion from C->JNI intermediate->Final Java types. If you were to write a typemap yourself then doing it at just the "Final Java types" phase would be the simplest place to write code with fewest typemaps needed. I've put together an example to show you what that's like. In practice it means changing just javain, javaout and jstype typemaps:

    %module test 
    
    %{
    #include "test.h"
    %}
    
    %typemap(jstype) enum boolean "boolean"
    
    %typemap(javacode) enum boolean %{
      public boolean toBoolean() {
        return this == TRUE;
      }
    %}
    
    %typemap(javaout) enum boolean {
      return $javaclassname.swigToEnum($jnicall).toBoolean();
    }
    
    %typemap(javain) enum boolean "($javainput?Boolean.TRUE:Boolean.FALSE).swigValue()"
    
    %include "test.h"
    

    This code is a little verbose really - the javain typemap could have been written as simply $javainput?0:1 and javaout could have been similarly simple instead of relying on the SWIG generated enum at all. I wrote it like that mostly just to show how it could interact with more complex enums. So we could have written:

    %module test 
    
    %{
    #include "test.h"
    %}
    
    %typemap(jstype) enum boolean "boolean"
    
    %typemap(javaout) enum boolean {
      return $jnicall != 0;
    }
    
    %typemap(javain) enum boolean "$javainput?1:0"
    
    %include "test.h"
    

    Which has hard-coded magic numbers that will always work here because you explicitly gave exactly two enum members values of 0 and 1, but if you aren't 100% certain that's always correct for more general enum wrapping could lead to some weird bugs.

    I hinted earlier that we could write typemaps that pass it as a jboolean all the way from native code down to the proxy classes that users use. That's true and would require no conversion of types along the way obviously, however in reality we can draw upon existing SWIG library support for the C++ bool type, even with our custom enum. (This works mostly because the C style cast from enum boolean -> jboolean works as we'd hope for 0/1 values).

    So we can in fact simply write:

    %module test 
    
    %{
    #include "test.h"
    %}
    
    %apply bool { enum boolean };
    
    %include "test.h"
    

    Which copies the bool typemaps into enum boolean typemaps for us. If for whatever reason you did want to tweak some/part of those typemaps you could still use that as a basis for doing this and just change what you needed to where it mattered.

    (At this stage I've run the above examples through SWIG and inspected but not compiled the output as I don't have a JDK to hand for testing it properly right now)

    Bottom line: try all three suggestions and look at the generated testJNI.java, test.java and test_wrap.c files to understand what impact each typemap had on the generated code.