Skip to content

Commit

Permalink
RFC Human friendly HostImports' builders
Browse files Browse the repository at this point in the history
  • Loading branch information
andreaTP committed Jul 26, 2024
1 parent 3405d0a commit dc3e7cc
Show file tree
Hide file tree
Showing 2 changed files with 337 additions and 0 deletions.
256 changes: 256 additions & 0 deletions runtime/src/main/java/com/dylibso/chicory/runtime/HostImports.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
package com.dylibso.chicory.runtime;

import com.dylibso.chicory.wasm.types.Limits;
import com.dylibso.chicory.wasm.types.MemoryLimits;
import com.dylibso.chicory.wasm.types.MutabilityType;
import com.dylibso.chicory.wasm.types.Table;
import com.dylibso.chicory.wasm.types.Value;
import com.dylibso.chicory.wasm.types.ValueType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.function.IntConsumer;
import java.util.function.IntSupplier;
import java.util.function.IntUnaryOperator;
import java.util.function.LongConsumer;
import java.util.function.LongSupplier;
import java.util.function.LongUnaryOperator;

public class HostImports {
private static final HostFunction[] NO_HOST_FUNCTIONS = new HostFunction[0];
Expand Down Expand Up @@ -137,6 +150,10 @@ public static Builder builder() {
return new Builder();
}

public static Builder builder(HostImports imports) {
return new Builder(imports);
}

public static final class Builder {
private List<HostFunction> functions;
private List<HostGlobal> globals;
Expand All @@ -146,6 +163,245 @@ public static final class Builder {

Builder() {}

Builder(HostImports imports) {
this.functions = new ArrayList<>();
this.globals = new ArrayList<>();
this.memories = new ArrayList<>();
this.tables = new ArrayList<>();
Collections.addAll(this.functions, imports.functions);
Collections.addAll(this.globals, imports.globals);
Collections.addAll(this.memories, imports.memories);
Collections.addAll(this.tables, imports.tables);
}

public static final class ImportBuilder {
private final Builder builder;
private final String moduleName;
private final String fieldName;

ImportBuilder(Builder builder, String moduleName, String fieldName) {
this.builder = builder;
this.moduleName = moduleName;
this.fieldName = fieldName;
}

public Builder withGlobal(Value value) {
return builder.addGlobal(
new HostGlobal(moduleName, fieldName, new GlobalInstance(value)));
}

public Builder withGlobal(MutabilityType mutability, Value value) {
return builder.addGlobal(
new HostGlobal(
moduleName, fieldName, new GlobalInstance(value), mutability));
}

public Builder withMutableGlobal(Value value) {
return builder.addGlobal(
new HostGlobal(
moduleName,
fieldName,
new GlobalInstance(value),
MutabilityType.Var));
}

public Builder withMemory() {
return builder.addMemory(
new HostMemory(
moduleName, fieldName, new Memory(MemoryLimits.defaultLimits())));
}

public Builder withMemory(MemoryLimits limits) {
return builder.addMemory(new HostMemory(moduleName, fieldName, new Memory(limits)));
}

public Builder withMemory(int initial) {
return builder.addMemory(
new HostMemory(
moduleName, fieldName, new Memory(new MemoryLimits(initial))));
}

public Builder withMemory(int initial, int max) {
return builder.addMemory(
new HostMemory(
moduleName, fieldName, new Memory(new MemoryLimits(initial, max))));
}

public Builder withTable() {
return builder.addTable(
new HostTable(
moduleName,
fieldName,
new TableInstance(
new Table(ValueType.FuncRef, Limits.unbounded()))));
}

public Builder withTable(ValueType t) {
return builder.addTable(
new HostTable(
moduleName,
fieldName,
new TableInstance(new Table(t, Limits.unbounded()))));
}

public Builder withTable(Limits limits) {
return builder.addTable(
new HostTable(
moduleName,
fieldName,
new TableInstance(new Table(ValueType.FuncRef, limits))));
}

public Builder withTable(int min) {
return builder.addTable(
new HostTable(
moduleName,
fieldName,
new TableInstance(new Table(ValueType.FuncRef, new Limits(min)))));
}

public Builder withTable(int min, int max) {
return builder.addTable(
new HostTable(
moduleName,
fieldName,
new TableInstance(
new Table(ValueType.FuncRef, new Limits(min, max)))));
}

// TODO: check - this mechanism is limited by the available primitive functional
// interfaces
public Builder withProcedure(Runnable f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
f.run();
return new Value[] {};
},
moduleName,
fieldName,
List.of(),
List.of()));
}

public Builder withProcedure(Function<Instance, Runnable> consumer) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
consumer.apply(instance).run();
return new Value[] {};
},
moduleName,
fieldName,
List.of(),
List.of()));
}

public Builder withSupplier(IntSupplier f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) ->
new Value[] {Value.i32(f.getAsInt())},
moduleName,
fieldName,
List.of(),
List.of(ValueType.I32)));
}

public Builder withSupplier(Function<Instance, IntSupplier> consumer) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
consumer.apply(instance).getAsInt();
return new Value[] {};
},
moduleName,
fieldName,
List.of(),
List.of()));
}

public Builder withSupplier(LongSupplier f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) ->
new Value[] {Value.i64(f.getAsLong())},
moduleName,
fieldName,
List.of(),
List.of(ValueType.I64)));
}

// ... complete me
public Builder withConsumer(IntConsumer f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
f.accept(args[0].asInt());
return new Value[] {};
},
moduleName,
fieldName,
List.of(ValueType.I32),
List.of()));
}

public Builder withConsumer(LongConsumer f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
f.accept(args[0].asLong());
return new Value[] {};
},
moduleName,
fieldName,
List.of(ValueType.I64),
List.of()));
}

// ... complete me
public Builder withFunction(IntUnaryOperator f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
return new Value[] {Value.i32(f.applyAsInt(args[0].asInt()))};
},
moduleName,
fieldName,
List.of(ValueType.I32),
List.of(ValueType.I32)));
}

public Builder withFunction(LongUnaryOperator f) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
return new Value[] {Value.i64(f.applyAsLong(args[0].asLong()))};
},
moduleName,
fieldName,
List.of(ValueType.I64),
List.of(ValueType.I64)));
}

// and now let's see how a fallback might look like
public Builder withFunction(Function<Instance, Function<Value[], Value[]>> consumer) {
return builder.addFunction(
new HostFunction(
(Instance instance, Value... args) -> {
return consumer.apply(instance).apply(args);
},
moduleName,
fieldName,
List.of(ValueType.I64),
List.of(ValueType.I64)));
}
}

public ImportBuilder withNewImport(String moduleName, String fieldName) {
return new ImportBuilder(this, moduleName, fieldName);
}

public Builder withFunctions(List<HostFunction> functions) {
this.functions = functions;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

import com.dylibso.chicory.wasm.types.Limits;
import com.dylibso.chicory.wasm.types.MemoryLimits;
import com.dylibso.chicory.wasm.types.MutabilityType;
import com.dylibso.chicory.wasm.types.Value;
import com.dylibso.chicory.wasm.types.ValueType;
import java.util.Arrays;
import java.util.Collections;
import org.junit.jupiter.api.Nested;
Expand Down Expand Up @@ -177,5 +181,82 @@ void addIndex() {
assertEquals(1, result.index().length);
}
}

@Nested
class DSL {

@Test
void withIndex() {
var moduleName = "module";
var fieldName = "filed";
HostImports.builder()
.withNewImport(moduleName, fieldName)
.withGlobal(Value.i32(1))
.withNewImport(moduleName, fieldName)
.withGlobal(MutabilityType.Var, Value.i32(1))
.withNewImport(moduleName, fieldName)
.withMutableGlobal(Value.i32(1))
.withNewImport(moduleName, fieldName)
.withGlobal(Value.i32(1))
.withNewImport(moduleName, fieldName)
.withMemory()
.withNewImport(moduleName, fieldName)
.withMemory(new MemoryLimits(1))
.withNewImport(moduleName, fieldName)
.withMemory(1)
.withNewImport(moduleName, fieldName)
.withMemory(1, 2)
.withNewImport(moduleName, fieldName)
.withTable()
.withNewImport(moduleName, fieldName)
.withTable(ValueType.ExternRef)
.withNewImport(moduleName, fieldName)
.withTable(new Limits(1))
.withNewImport(moduleName, fieldName)
.withTable(1)
.withNewImport(moduleName, fieldName)
.withTable(1, 2)
.withNewImport(moduleName, fieldName)
.withProcedure(() -> System.out.println("hello world"))
.withNewImport(moduleName, fieldName)
.withProcedure((Instance inst) -> () -> System.out.println("hello world"))
.withNewImport(moduleName, fieldName)
.withSupplier(() -> 1)
.withNewImport(moduleName, fieldName)
.withSupplier((Instance inst) -> () -> 1)
.withNewImport(moduleName, fieldName)
.withSupplier(() -> 2L)
// this doesn't compile now as expected, since we do not handle Double just
// yet
// .withSupplier(() -> { return 0.0 })
.withNewImport(moduleName, fieldName)
.withConsumer(
(int i) -> {
var x = i + 1;
})
.withNewImport(moduleName, fieldName)
.withConsumer(
(long l) -> {
var x = l + 2L;
})
// this doesn't compile now as expected, since we do not handle Double just
// yet
// .withConsumer((double d) -> { var x = d + 2; })
.withNewImport(moduleName, fieldName)
.withFunction((int i) -> i + 1)
.withNewImport(moduleName, fieldName)
.withFunction((long l) -> l + 2L)
// this doesn't compile now as expected, since we do not handle Double just
// yet
// .withFunction((double d) -> d + 2.0)
.withNewImport(moduleName, fieldName)
.withFunction(
(Instance inst) ->
(Value[] args) -> {
return new Value[] {};
})
.build();
}
}
}
}

0 comments on commit dc3e7cc

Please sign in to comment.