8000 enumtypes: skip generation of "last" members by kleisauke · Pull Request #4520 · libvips/libvips · GitHub
[go: up one dir, main page]

Skip to content

enumtypes: skip generation of "last" members #4520

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

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

kleisauke
Copy link
Member
@kleisauke kleisauke commented May 16, 2025

We probably don't want to expose these "last" members to language bindings.

Generated enumtypes.c diff: https://gist.github.com/kleisauke/97d3e7d01df0a79b4b9179ea201e053e

See also: libvips/pyvips#537.

kleisauke added a commit to kleisauke/pyvips that referenced this pull request May 16, 2025
@jcupitt
Copy link
Member
jcupitt commented May 16, 2025

I suppose we could also just remove the _LAST members and do it at runtime instead. We could have some compatibility defines which fetched the n_values field:

https://docs.gtk.org/gobject/struct.EnumClass.html

We wouldn't be able to get the size of the enum statically, but maybe that's not too bad?

ruby-vips, php-vips etc might need changes too.

Maybe that's too big a change.

@kleisauke
Copy link
Member Author
kleisauke commented May 16, 2025

I think removing the _LAST members would cause a lot of issues downstream, e.g. sharp uses to mean "unset", see:
https://github.com/lovell/sharp/blob/v0.34.1/src/pipeline.h#L380-L381

/* -1 since we always have a "last" member.
*/
for (i = 0; i < genum->n_values - 1; i++) {
for (i = 0; i < genum->n_values; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this change mean that the "last" string literal will no longer accepted by the vips_enum_from_nick function? (There are a couple of places in sharp that rely on this behaviour, which I'm happy to remove if so as it's probably not a good thing to rely on anyway.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot. Yes, this would mean that the "last" string literal will no longer be accepted. See for example:

/* Compile with:
 *   gcc -g -Wall test-enum.c `pkg-config vips --cflags --libs`
 */

#include <vips/vips.h>

int
main(int argc, char *argv[]) {
	if (VIPS_INIT(argv[0]))
		vips_error_exit(NULL);


	int i = vips_enum_from_nick(argv[0], VIPS_TYPE_INTERPRETATION, "last");
	if (i == -1)
		// Error: `enum 'VipsInterpretation' has no member 'last', should be one of: ...`
		vips_error_exit(NULL);

	// This would previously print 30 (VIPS_INTERPRETATION_LAST), rather than bailing out.
	printf("%d\n", i);

	return 0;
}

@kleisauke
Copy link
Member Author

I checked NetVips, php-vips, pyvips, and ruby-vips, none of these language bindings appear to expose these _LAST enum members. However, you might still be able to pass them as string literals, if supported (NetVips no longer supports this).

My only concern is the potential vips_enum_from_nick() API break, though it would guarantee that these _LAST members aren't used further downstream. For example, this would segfault on the master branch:

$ vipsthumbnail zebra.jpg --smartcrop=last
Segmentation fault (core dumped)

due to:

g_assert_not_reached();

But with this PR, it would error with:

$ vipsthumbnail zebra.jpg --smartcrop=last
vipsthumbnail: unable to thumbnail zebra.jpg
vipsthumbnail: enum 'VipsInteresting' has no member 'last', should be one of: none, centre, entropy, attention, low, high, all

@kleisauke
Copy link
Member Author

As an experiment, here's a branch that removes these _LAST enum members instead:
master...kleisauke:enums-remove-last-member

@jcupitt
Copy link
Member
jcupitt commented May 17, 2025

I think we'd need something for uses like:

    if (mode[i] < 0 ||
        mode[i] >= VIPS_BLEND_MODE_LAST) {

Maybe:

// tiny utility func
GEnumClass *vips__get_enum_class(const char *class_name);

#define VIPS_BLEND_MODE_LAST (vips__get_enum_class("VipsBlendMode")->n_values)

Or perhaps just:

// returns n_values
int vips__get_enum_last(const char *class_name);


    if (mode[i] < 0 ||
        mode[i] > vips__get_enum_last("VipsBlendMode")) {

What do you think?

kleisauke added a commit to kleisauke/pyvips that referenced this pull request May 17, 2025
@kleisauke
Copy link
Member Author

You're right. I just pushed commit kleisauke@1f0054e to that branch, since that's probably(?) the only place where it needs to be future-proof.

Note that we sometimes do similar checks elsewhere, for example:

image->BandFmt > VIPS_FORMAT_DPCOMPLEX ||

which is likely safe, I don't expect any new band formats in the near future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0