swiftposixcinterop

Access tuple (defined by libc) using an index


I understand that Swift tuples cannot be indexed at runtime. However, I'm working with the POSIX terminal interface (defined by <termios.h>, which is part of libc).

In the C code, we are able to modify the state of the terminal by doing stuff like this:

termios_struct.c_cc[VMIN] = 0;
termios_struct.c_cc[VTIME] = 0;

Translating that to Swift raises an error, complaining that it cannot access element using subscript for tuple type '(cc_t, cc_t, cc_t ...)' (aka '(UInt8, UInt8, UInt8 ...)'). The actual tuples have about twenty elements, all UInt8.

I guess I could just print the values of VMIN and VTIME (constants defined by <termios.h>), then use their values to directly index the tuples, but I'm not sure their values are consistent across platforms, and it's just generally hacky.

What's the proper way to handle this situation?


Edit: This issue is addressed by this answer to another question, named Using termios in Swift.


Solution

  • Using the answer you referenced as a guide, I came up with the following extension that seems to work.

    extension termios {
        subscript(c_cc index: Int32) -> cc_t {
            get {
                var settings = self
                var res: cc_t = 0
                withUnsafePointer(to: &settings.c_cc) { (tuplePtr) -> Void in
                    tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: self.c_cc)) {
                        res = $0[Int(index)]
                    }
                }
    
                return res
            }
            set {
                var settings = self
                withUnsafeMutablePointer(to: &self.c_cc) { (tuplePtr) -> Void in
                    tuplePtr.withMemoryRebound(to: cc_t.self, capacity: MemoryLayout.size(ofValue: settings.c_cc)) {
                        $0[Int(index)] = newValue
                    }
                }
            }
        }
    }
    

    Here's some sample code:

    var settings = termios()
    print(settings.c_cc)
    settings[c_cc: VMIN] = 1
    print(settings.c_cc)
    print(settings[c_cc: VMIN])
    

    which outputs:

    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0)
    1