Skip to content

Find a proper solution for variadic methods when available. #407

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

Closed
emilio opened this issue Jan 19, 2017 · 1 comment
Closed

Find a proper solution for variadic methods when available. #407

emilio opened this issue Jan 19, 2017 · 1 comment

Comments

@emilio
Copy link
Contributor

emilio commented Jan 19, 2017

In rust you can't define variadic methods, at least as of right now.

If that changes, we would be able to generate the convenience methods we use for the rest of methods. See #402 (comment).

cc @kkimdev

@pvdrz
Copy link
Contributor

pvdrz commented Sep 15, 2022

As of today, Rust does not support variadic functions unless they are extern, free ones. I've been thinking about different ways to solve this, each one of them with their advantages and disadvantages, let's say we have an extern function like this:

extern "C" {
    fn foo_bar(foo: &Foo, a: A, ...);
}

Then we could either:

Use macros

One option would be to add a variadic_call macro to the generated bindings:

variadic_call!(foo.bar(a, v0, v1, v2)) // desugars to bar(&foo, v0, v1, v2)

This isn't great as we wouldn't be able to do all the deref tricks such as handling &mut foo &foo and so on. As usual, macros would also make the code less readable and we wouldn't win anything tbh.

Use tuples

This would be way more convoluted but it would allow the users to do

foo.bar(a, (10,));
foo.bar(a, (10, b"hello"));
foo.bar(a, (10, b"hello", false));

The exposed method would look like this

impl Foo {
    /// Call `bar` with variadic arguments using tuples.
    ///
    /// A call with no variadic arguments would use `()` as: `foo.bar(a, ())`.
    unsafe fn bar(&self, a: A, varargs: impl VarArgs) {
        varargs.call_foo_bar(self, a)
    }
}

Then the definition and implementations of VarArgs would be

trait VarArgs {
    /// There should be one method in this trait for each variadic method.
    #[doc(hidden)]
    unsafe fn call_foo_bar(self, foo: &Foo, a: A);
}

// This would be either macro generated or generated by bindgen up to a certain tuple length.
impl VarArgs for () {
    unsafe fn call_foo_bar(self, foo: &Foo, a: A) {
        foo_bar(foo, a)
    }
}

impl<T1> VarArgs for (T1,) {
    unsafe fn call_foo_bar(self, foo: &Foo, a: A) {
        foo_bar(foo, a, self.0)
    }
}

impl<T1, T2> VarArgs for (T1, T2) {
    unsafe fn call_foo_bar(self, foo: &Foo, a: A) {
        foo_bar(foo, a, self.0, self.1)
    }
}

The disadvantage here is having to expose this VarArgs trait but I think with some good documentation it would work nicely.

Let me know what you think :)

@pvdrz pvdrz closed this as not planned Won't fix, can't repro, duplicate, stale Nov 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants