Rust functions that accept and return tuples

C has no notion of tuples, but the closest analog is a plain struct. You will need to create individual structs for each unique combination of types. Here, we create a structure that represents two 32-bit unsigned integers.

extern crate libc;

use libc::uint32_t;
use std::convert::From;

// A Rust function that accepts a tuple
fn flip_things_around_rust(tup: (u32, u32)) -> (u32, u32) {
    let (a, b) = tup;
    (b+1, a-1)
}

// A struct that can be passed between C and Rust
#[repr(C)]
pub struct Tuple {
    x: uint32_t,
    y: uint32_t,
}

// Conversion functions
impl From<(u32, u32)> for Tuple {
    fn from(tup: (u32, u32)) -> Tuple {
        Tuple { x: tup.0, y: tup.1 }
    }
}

impl From<Tuple> for (u32, u32) {
    fn from(tup: Tuple) -> (u32, u32) {
        (tup.x, tup.y)
    }
}

// The exported C method
#[no_mangle]
pub extern fn flip_things_around(tup: Tuple) -> Tuple {
    flip_things_around_rust(tup.into()).into()
}

#[allow(dead_code)]
pub extern fn fix_linking_when_not_using_stdlib() { panic!() }

#[repr(C)] is used to inform the compiler that it should arrange the fields of the struct as a C compiler would. The two conversion implementations use std::convert::From to provide ergonomic conversion between the struct and a corresponding tuple.

C

#include <stdio.h>
#include <stdint.h>

typedef struct {
  uint32_t x;
  uint32_t y;
} tuple_t;

extern tuple_t flip_things_around(tuple_t);

int main(void) {
  tuple_t initial = { .x = 10, .y = 20 };
  tuple_t new = flip_things_around(initial);
  printf("(%d,%d)\n", new.x, new.y);
  return 0;
}

Since we are conforming to C-compatible idioms, the implementation is straight-forward. We define a struct with fields that match the types and order of the Rust struct, then create an instance and call the method.

Ruby

require 'ffi'

class Tuple < FFI::Struct
  layout :x, :uint32,
         :y, :uint32

  def to_s
    "(#{self[:x]},#{self[:y]})"
  end
end

module Tuples
  extend FFI::Library
  ffi_lib 'tuples'
  attach_function :flip_things_around, [Tuple.by_value], Tuple.by_value
end

tup = Tuple.new
tup[:x] = 10
tup[:y] = 20

puts Tuples.flip_things_around(tup)

To mirror the structure definition, we create a subclass of FFI::Struct and use layout to specify the field names and types.

When attaching the function, we use by_value to indicate that the struct will be passed directly, without the need for indirection via pointers.

Python

#!/usr/bin/env python3

import sys, ctypes
from ctypes import c_uint32, Structure

class Tuple(Structure):
    _fields_ = [("x", c_uint32),
                ("y", c_uint32)]

    def __str__(self):
        return "({},{})".format(self.x, self.y)

prefix = {'win32': ''}.get(sys.platform, 'lib')
extension = {'darwin': '.dylib', 'win32': '.dll'}.get(sys.platform, '.so')
lib = ctypes.cdll.LoadLibrary(prefix + "tuples" + extension)

lib.flip_things_around.argtypes = (Tuple, )
lib.flip_things_around.restype = Tuple

tup = Tuple(10, 20)

print(lib.flip_things_around(tup))

To mirror the structure definition, we create a subclass of ctypes.Structure and use _fields_ to specify the field names and types.

Haskell

Unfortunately, Haskell does not currently support passing or returning arbitrary structs. Pointer indirection is always required.

Node.js

const ffi = require('ffi');
const struct = require('ref-struct');

const Tuple = struct({
  x: 'uint32',
  y: 'uint32',
});

const lib = ffi.Library('libtuples', {
  flip_things_around: [Tuple, [Tuple]],
});

const tup = new Tuple({x: 10, y: 20});
const result = lib.flip_things_around(tup);
console.log('(%d,%d)', result.x, result.y);

The ref-struct package allows us to build struct types which can be passed to FFI functions.

C#

using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
struct IntTuple {
    public uint x;
    public uint y;

    public static implicit operator Tuple<uint, uint>(IntTuple t)
    {
        return Tuple.Create(t.x, t.y);
    }

    public static implicit operator IntTuple(Tuple<uint, uint> t)
    {
        return new IntTuple { x = t.Item1, y = t.Item2 };
    }
};

class Tuples
{
    [DllImport("tuples")]
    private static extern IntTuple flip_things_around(IntTuple t);

    public static Tuple<uint, uint> FlipThingsAround(Tuple<uint, uint> t)
    {
        return flip_things_around(t);
    }

    static public void Main()
    {
        var tuple = Tuple.Create(10u, 20u);
        var newTuple = Tuples.FlipThingsAround(tuple);
        Console.WriteLine($"({newTuple.Item1},{newTuple.Item2})");
    }
}

To mirror the tuple structure definition, we create a struct using the StructLayout property and define the layout as sequential. We also provide some implicit conversion operators to make going between types fairly seamless.