Skip to content

Commit

Permalink
Add PointerWrapper type
Browse files Browse the repository at this point in the history
You can extend PointerWrapper for typesafe pointer. Example:
 public interface TestLib {
      CustomPointer ptr_malloc(@size_t int size);
      void ptr_free(CustomPointer ptr);

      class CustomPointer extends PointerWrapper {
          private CustomPointer(Pointer pointer) {
              super(pointer);
          }
      }
  }
 }

(cherry picked from commit 98ca7da)
  • Loading branch information
goto1134 committed Aug 30, 2017
1 parent 4697272 commit 1b22fbf
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 2 deletions.
33 changes: 33 additions & 0 deletions src/main/java/jnr/ffi/PointerWrapper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package jnr.ffi;

/**
* A wrapper on {@link jnr.ffi.Pointer}
* <p>
* Extend to use as typesafe pointer. Example:
* <pre>
* {@code
* public interface TestLib {
* CustomPointer ptr_malloc(@size_t int size);
* void ptr_free(CustomPointer ptr);
*
* class CustomPointer extends PointerWrapper {
* private CustomPointer(Pointer pointer) {
* super(pointer);
* }
* }
* }
* }
* </pre>
*/
public abstract class PointerWrapper {
private final Pointer pointer;

protected PointerWrapper(Pointer pointer) {
this.pointer = pointer;
}

public Pointer pointer() {
return pointer;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package jnr.ffi.provider.converters;

import jnr.ffi.Pointer;
import jnr.ffi.PointerWrapper;
import jnr.ffi.mapper.FromNativeContext;
import jnr.ffi.mapper.FromNativeConverter;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
* @author Andrew Yefanov.
* @since 30.08.2017.
*/
public class PointerWrapperFromNativeConverter implements FromNativeConverter<PointerWrapper, Pointer> {

private final Constructor<PointerWrapper> constructor;

private PointerWrapperFromNativeConverter(Constructor constructor) {
this.constructor = constructor;
}

public static FromNativeConverter<PointerWrapper, Pointer> getInstance(Class<PointerWrapper> wrapperClass) {
try {
Constructor<PointerWrapper> constructor = wrapperClass.getConstructor(Pointer.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
return new PointerWrapperFromNativeConverter(constructor);
} catch (NoSuchMethodException e) {
throw new RuntimeException(wrapperClass.getName() + " has no constructor that accepts jnr.ffi.Pointer");
}
}

@Override
public PointerWrapper fromNative(Pointer nativeValue, FromNativeContext context) {
try {
return nativeValue == null ? null : constructor.newInstance(nativeValue);
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}

@Override
public Class<Pointer> nativeType() {
return Pointer.class;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package jnr.ffi.provider.converters;

import jnr.ffi.Pointer;
import jnr.ffi.PointerWrapper;
import jnr.ffi.mapper.ToNativeContext;
import jnr.ffi.mapper.ToNativeConverter;

/**
* @author Andrew Yefanov.
* @since 30.08.2017.
*/
public class PointerWrapperToNativeConverter implements ToNativeConverter<PointerWrapper, Pointer> {

public static final PointerWrapperToNativeConverter INSTANCE = new PointerWrapperToNativeConverter();

public static ToNativeConverter<PointerWrapper, Pointer> getInstance() {
return INSTANCE;
}

@Override
public Pointer toNative(PointerWrapper value, ToNativeContext context) {
return value == null ? null : value.pointer();
}

@Override
public Class<Pointer> nativeType() {
return Pointer.class;
}
}
9 changes: 7 additions & 2 deletions src/main/java/jnr/ffi/provider/jffi/InvokerTypeMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@

import jnr.ffi.NativeLong;
import jnr.ffi.Pointer;
import jnr.ffi.PointerWrapper;
import jnr.ffi.Struct;
import jnr.ffi.annotations.Delegate;
import jnr.ffi.byref.ByReference;
import jnr.ffi.mapper.*;
import jnr.ffi.mapper.FromNativeType;
import jnr.ffi.mapper.ToNativeType;
import jnr.ffi.provider.ParameterFlags;
import jnr.ffi.provider.converters.*;

Expand Down Expand Up @@ -54,6 +53,9 @@ public FromNativeConverter getFromNativeConverter(SignatureType signatureType, F
} else if (Struct.class.isAssignableFrom(signatureType.getDeclaredType())) {
return structResultConverterFactory.get(signatureType.getDeclaredType().asSubclass(Struct.class), fromNativeContext);

} else if (PointerWrapper.class.isAssignableFrom(signatureType.getDeclaredType())) {
return PointerWrapperFromNativeConverter.getInstance(signatureType.getDeclaredType());

} else if (closureManager != null && isDelegate(signatureType.getDeclaredType())) {
return ClosureFromNativeConverter.getInstance(fromNativeContext.getRuntime(), signatureType, classLoader, this);

Expand Down Expand Up @@ -91,6 +93,9 @@ public ToNativeConverter getToNativeConverter(SignatureType signatureType, ToNat
} else if (Struct.class.isAssignableFrom(javaType)) {
return StructByReferenceToNativeConverter.getInstance(context);

} else if (PointerWrapper.class.isAssignableFrom(javaType)) {
return PointerWrapperToNativeConverter.getInstance();

} else if (NativeLong.class.isAssignableFrom(javaType)) {
return NativeLongConverter.getInstance();

Expand Down
44 changes: 44 additions & 0 deletions src/test/java/jnr/ffi/PointerWrapperTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package jnr.ffi;

import jnr.ffi.mapper.AnnotatedMappedTypeTest;
import jnr.ffi.types.size_t;
import org.junit.BeforeClass;
import org.junit.Test;

import static junit.framework.TestCase.assertSame;

/**
* @author Andrew Yefanov.
* @since 30.08.2017.
*/
public class PointerWrapperTest {
private static final class CustomPointer extends PointerWrapper {
private CustomPointer(Pointer pointer) {
super(pointer);
}
}

public static interface TestLib {
CustomPointer ptr_malloc(@size_t int size);
void ptr_free(AnnotatedMappedTypeTest.CustomPointer ptr);
}

static AnnotatedMappedTypeTest.TestLib testlib;
static Runtime runtime;

@BeforeClass
public static void setUpClass() throws Exception {
testlib = TstUtil.loadTestLib(AnnotatedMappedTypeTest.TestLib.class);
runtime = Runtime.getRuntime(testlib);
}

@Test
public void returnsInstanceOfCorrectClass() {
assertSame(AnnotatedMappedTypeTest.CustomPointer.class, testlib.ptr_malloc(1).getClass());
}

@Test public void toNative() {
testlib.ptr_free(testlib.ptr_malloc(1));
}

}

0 comments on commit 1b22fbf

Please sign in to comment.