Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PointerWrapper type #140

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
26 changes: 16 additions & 10 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 All @@ -48,22 +47,26 @@ public InvokerTypeMapper(NativeClosureManager closureManager, AsmClassLoader cla
public FromNativeConverter getFromNativeConverter(SignatureType signatureType, FromNativeContext fromNativeContext) {
FromNativeConverter converter;

if (Enum.class.isAssignableFrom(signatureType.getDeclaredType())) {
return EnumConverter.getInstance(signatureType.getDeclaredType().asSubclass(Enum.class));
Class declaredType = signatureType.getDeclaredType();
if (Enum.class.isAssignableFrom(declaredType)) {
return EnumConverter.getInstance(declaredType.asSubclass(Enum.class));

} else if (Struct.class.isAssignableFrom(signatureType.getDeclaredType())) {
return structResultConverterFactory.get(signatureType.getDeclaredType().asSubclass(Struct.class), fromNativeContext);
} else if (Struct.class.isAssignableFrom(declaredType)) {
return structResultConverterFactory.get(declaredType.asSubclass(Struct.class), fromNativeContext);

} else if (closureManager != null && isDelegate(signatureType.getDeclaredType())) {
} else if (PointerWrapper.class.isAssignableFrom(declaredType)) {
return PointerWrapperFromNativeConverter.getInstance(declaredType);

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

} else if (NativeLong.class == signatureType.getDeclaredType()) {
} else if (NativeLong.class == declaredType) {
return NativeLongConverter.getInstance();

} else if (String.class == signatureType.getDeclaredType() || CharSequence.class == signatureType.getDeclaredType()) {
} else if (String.class == declaredType || CharSequence.class == declaredType) {
return StringResultConverter.getInstance(fromNativeContext);

} else if ((Set.class == signatureType.getDeclaredType() || EnumSet.class == signatureType.getDeclaredType()) && (converter = EnumSetConverter.getFromNativeConverter(signatureType, fromNativeContext)) != null) {
} else if ((Set.class == declaredType || EnumSet.class == declaredType) && (converter = EnumSetConverter.getFromNativeConverter(signatureType, fromNativeContext)) != null) {
return converter;

} else {
Expand Down Expand Up @@ -91,6 +94,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));
}

}