Skip to content

Commit

Permalink
Proof of concept helper binding generation (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
lopcode authored Aug 19, 2024
1 parent 383bc2d commit 55b6f41
Show file tree
Hide file tree
Showing 17 changed files with 10,554 additions and 133 deletions.
12 changes: 12 additions & 0 deletions .run/Generate helpers.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Generate helpers" type="JetRunConfigurationType">
<option name="MAIN_CLASS_NAME" value="vipsffm.GenerateHelpers" />
<module name="vips-ffm.helper-generator.main" />
<shortenClasspath name="NONE" />
<option name="VM_PARAMETERS" value="--enable-preview" />
<method v="2">
<option name="Gradle.BeforeRunTask" enabled="true" tasks="compileJava" externalProjectPath="$PROJECT_DIR$/core" vmOptions="" scriptParameters="" />
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
3 changes: 3 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugins {
kotlin("jvm") version "2.0.10" apply false
}
48 changes: 48 additions & 0 deletions core/src/main/java/app/photofox/vipsffm/helper/VipsInvoker.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package app.photofox.vipsffm.helper;

import app.photofox.vipsffm.generated.VipsRaw;

import java.lang.foreign.Arena;
import java.lang.foreign.MemoryLayout;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.ValueLayout;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class VipsInvoker {

public static MemoryLayout[] makeInvokerVarargLayouts(VipsOption... args) {
List<ValueLayout> layouts = new ArrayList<>();
var listArgs = Arrays.stream(args).toList();
listArgs.forEach((arg) -> {
layouts.add(VipsRaw.C_POINTER);
switch (arg) {
case VipsStringOption _ -> layouts.add(VipsRaw.C_POINTER);
case VipsIntOption _ -> layouts.add(VipsRaw.C_INT);
}
});
layouts.add(VipsRaw.C_POINTER);
return layouts.toArray(MemoryLayout[]::new);
}

public static Object[] makeInvokerVarargObjects(Arena arena, VipsOption... args) {
var invokeArgs = new ArrayList<>();
var listArgs = Arrays.stream(args).toList();
listArgs.forEach((arg) -> {
var keyCString = arena.allocateFrom(arg.key());
invokeArgs.add(keyCString);
switch (arg) {
case VipsStringOption stringOption -> {
var valueCString = arena.allocateFrom(stringOption.value());
invokeArgs.add(valueCString);
}
case VipsIntOption intOption -> {
invokeArgs.add(intOption.value());
}
}
});
invokeArgs.add(MemorySegment.NULL);
return invokeArgs.toArray(Object[]::new);
}
}
40 changes: 40 additions & 0 deletions core/src/main/java/app/photofox/vipsffm/helper/VipsValidation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package app.photofox.vipsffm.helper;

import app.photofox.vipsffm.generated.VipsRaw;

import java.lang.foreign.*;

public class VipsValidation {

public static boolean isValidPointer(MemorySegment memorySegment) {
return memorySegment != MemorySegment.NULL && memorySegment.address() != 0;
}

public static boolean isValidResult(int result) {
return result == 0;
}

public static void throwVipsError(String commandName) throws VipsError {
var errorBuffer = VipsRaw.vips_error_buffer();
if (!isValidPointer(errorBuffer)) {
throw new VipsError("failed to run vips command " + commandName);
}

var errorString = errorBuffer.getString(0);
throw new VipsError("failed to run vips command " + commandName + ": " + errorString);
}

public static void throwInvalidInputError(String commandName, String argName) throws VipsError {
throw new VipsError("invalid input provided to command " + commandName + " argument " + argName);
}

public static void throwInvalidOutputError(String commandName, String argName) throws VipsError {
var errorBuffer = VipsRaw.vips_error_buffer();
if (!isValidPointer(errorBuffer)) {
throw new VipsError("failed to run vips command " + commandName);
}

var errorString = errorBuffer.getString(0);
throw new VipsError("invalid output pointer from command " + commandName + " argument " + argName + ": " + errorString);
}
}
2 changes: 2 additions & 0 deletions generate_ffm_bindings.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,5 @@ set -x
--library "vips" \
@includes_filtered.txt \
"$LIBVIPS_ENTRY_PATH"

./gradlew clean helper-generator:run
50 changes: 50 additions & 0 deletions helper-generator/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@file:Suppress("UnstableApiUsage")

import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

plugins {
kotlin("jvm")
application
}

repositories {
mavenCentral()
}

dependencies {
implementation(project(":core"))
implementation(platform("org.slf4j:slf4j-bom:2.0.16"))
implementation("com.squareup:javapoet:1.13.0")
implementation("org.slf4j:slf4j-api")
implementation("org.slf4j:slf4j-simple")
}

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(22))
}
}

testing {
suites {
val test by getting(JvmTestSuite::class) {
useKotlinTest("2.0.0")
testType = TestSuiteType.UNIT_TEST
}
}
}

tasks.withType<Test> {
testLogging {
events = TestLogEvent.values().toSet() - TestLogEvent.STARTED
exceptionFormat = TestExceptionFormat.FULL
}
outputs.upToDateWhen { false }
}

application {
mainClass = "vipsffm.GenerateHelpers"
applicationDefaultJvmArgs = listOf("--enable-preview")
tasks.run.get().workingDir = rootProject.projectDir
}
Loading

0 comments on commit 55b6f41

Please sign in to comment.