Skip to content
Merged
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
15 changes: 15 additions & 0 deletions internal/introspection/introspection.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ static void collect_argument(VipsObject* object, GParamSpec* pspec,
arg->int_default = 0;
arg->double_default = 0.0;
arg->string_default = NULL;
arg->has_range = 0;
arg->minimum = 0.0;
arg->maximum = 0.0;
arg->is_image = 0;
arg->is_buffer = 0;
arg->is_array = 0;
Expand Down Expand Up @@ -165,24 +168,36 @@ static void collect_argument(VipsObject* object, GParamSpec* pspec,
arg->has_default = 1;
arg->default_type = 2; // int
arg->int_default = pspec_int->default_value;
arg->has_range = 1;
arg->minimum = pspec_int->minimum;
arg->maximum = pspec_int->maximum;
}
else if (G_IS_PARAM_SPEC_UINT(pspec)) {
GParamSpecUInt *pspec_uint = G_PARAM_SPEC_UINT(pspec);
arg->has_default = 1;
arg->default_type = 2; // int
arg->int_default = (gint)pspec_uint->default_value;
arg->has_range = 1;
arg->minimum = pspec_uint->minimum;
arg->maximum = pspec_uint->maximum;
}
else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) {
GParamSpecDouble *pspec_double = G_PARAM_SPEC_DOUBLE(pspec);
arg->has_default = 1;
arg->default_type = 3; // double
arg->double_default = pspec_double->default_value;
arg->has_range = 1;
arg->minimum = pspec_double->minimum;
arg->maximum = pspec_double->maximum;
}
else if (G_IS_PARAM_SPEC_FLOAT(pspec)) {
GParamSpecFloat *pspec_float = G_PARAM_SPEC_FLOAT(pspec);
arg->has_default = 1;
arg->default_type = 3; // double
arg->double_default = (gdouble)pspec_float->default_value;
arg->has_range = 1;
arg->minimum = pspec_float->minimum;
arg->maximum = pspec_float->maximum;
}
else if (G_IS_PARAM_SPEC_STRING(pspec)) {
GParamSpecString *pspec_string = G_PARAM_SPEC_STRING(pspec);
Expand Down
3 changes: 3 additions & 0 deletions internal/introspection/introspection.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ typedef struct {
gint int_default;
gdouble double_default;
char *string_default;
int has_range;
gdouble minimum;
gdouble maximum;
} ArgInfo;

// Get all arguments of an operation
Expand Down
37 changes: 37 additions & 0 deletions internal/introspection/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ type Argument struct {
Flags int
IsEnum bool
EnumType string
EnumValues []int
HasRange bool
Minimum float64
Maximum float64
NInputFrom string
DefaultValue interface{}
}
Expand Down Expand Up @@ -218,6 +222,9 @@ func (v *Introspection) DiscoverOperationArguments(opName string) ([]Argument, e
IsSource: isSource,
IsTarget: isTarget,
Flags: int(arg.flags),
HasRange: int(arg.has_range) != 0,
Minimum: float64(arg.minimum),
Maximum: float64(arg.maximum),
}

// Check if this is an enum or flags type
Expand All @@ -242,6 +249,7 @@ func (v *Introspection) DiscoverOperationArguments(opName string) ([]Argument, e
if goArg.IsEnum {
enumName := C.GoString(C.g_type_name(arg.type_val))
goArg.EnumType = v.getGoEnumName(enumName)
goArg.EnumValues = getEnumValues(arg.type_val)
v.addEnumType(enumName, goArg.EnumType)
}
if isArray && isInput && required && !isAffineMatrix {
Expand Down Expand Up @@ -459,6 +467,35 @@ func (v *Introspection) DiscoverOperationArguments(opName string) ([]Argument, e
return goArgs, nil
}

func getEnumValues(gtype C.GType) []int {
typeName := C.g_type_name(gtype)
if typeName == nil {
return nil
}

cTypeName := C.CString(C.GoString(typeName))
defer C.free(unsafe.Pointer(cTypeName))

isFlags := C.int(0)
if C.is_type_flags(gtype) != 0 {
isFlags = 1
}

var count C.int
values := C.get_enum_or_flag_values(cTypeName, &count, isFlags)
if values == nil || count <= 0 {
return nil
}
defer C.free_enum_values(values, count)

valueSlice := (*[1 << 30]C.EnumValueInfo)(unsafe.Pointer(values))[:count:count]
result := make([]int, 0, int(count))
for _, value := range valueSlice {
result = append(result, int(value.value))
}
return result
}

// Helper function to extract default values based on type
func (v *Introspection) extractDefaultValue(arg C.ArgInfo, goType string) interface{} {
// Check if there's a default value
Expand Down
64 changes: 64 additions & 0 deletions internal/introspection/operation_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package introspection

import "testing"

func TestDiscoverOperationArgumentMetadata(t *testing.T) {
introspection := NewIntrospection(false)
args, err := introspection.DiscoverOperationArguments("icc_transform")
if err != nil {
t.Fatal(err)
}

intent := findArgument(t, args, "intent")
if !intent.IsEnum || intent.EnumType != "Intent" {
t.Fatalf("intent metadata = %+v, want Intent enum", intent)
}
if intent.DefaultValue != 1 {
t.Fatalf("intent default = %v, want 1", intent.DefaultValue)
}
if !containsInt(intent.EnumValues, 0) {
t.Fatalf("intent enum values = %v, want zero-valued member", intent.EnumValues)
}

blackPointCompensation := findArgument(t, args, "black_point_compensation")
if blackPointCompensation.DefaultValue != false {
t.Fatalf("black point compensation default = %v, want false", blackPointCompensation.DefaultValue)
}

inputProfile := findArgument(t, args, "input_profile")
if inputProfile.HasRange {
t.Fatalf("string input_profile unexpectedly has numeric range: %+v", inputProfile)
}

thumbnailArgs, err := introspection.DiscoverOperationArguments("thumbnail")
if err != nil {
t.Fatal(err)
}
thumbnailHeight := findArgument(t, thumbnailArgs, "height")
if !thumbnailHeight.HasRange {
t.Fatal("thumbnail height has no numeric range metadata")
}
if thumbnailHeight.Maximum < thumbnailHeight.Minimum {
t.Fatalf("thumbnail height range = [%v, %v]", thumbnailHeight.Minimum, thumbnailHeight.Maximum)
}
}

func findArgument(t *testing.T, args []Argument, name string) Argument {
t.Helper()
for _, arg := range args {
if arg.Name == name {
return arg
}
}
t.Fatalf("argument %q not found", name)
return Argument{}
}

func containsInt(values []int, wanted int) bool {
for _, value := range values {
if value == wanted {
return true
}
}
return false
}
Loading