Racket [Scheme] / Cocoa Glue – Part III

For the third installment of my glue code between Cocoa and Racket, here is some data type conversion code. It’s all in Racket, using the Objective-C FFI. It includes conversions for strings to NSString and back, as well as converting between lists and NSArray and Racket dictionaries to NSDictionary and NSMutableDictionary. Also included are some helper functions for accessing NSArrays.

Next installment will be my unit tests for this code, so get excited.

cocoa-glue-data-types.rkt:

#lang racket

(provide (all-defined-out))

(require ffi/unsafe
         ffi/unsafe/objc
         ffi/cvector)

(import-class NSString)
(import-class NSArray)
(import-class NSDictionary)
(import-class NSMutableDictionary)

(define-syntax-rule (define-typed-tell fn-id type-id)
  (define-syntax-rule (fn-id obj msg (... ...))
    (tell #:type type-id obj msg (... ...))))

(define-typed-tell tell-int32  _int32)
(define-typed-tell tell-string _string)

(define (objC-tagged p)
  (unless (cpointer-has-tag? p 'id)
    (cpointer-push-tag! p 'id))
  p)

(define (string->NSString str)
  (tell NSString stringWithUTF8String: #:type _string str))

(define (NSString->string ns-string)
  (tell-string ns-string UTF8String))

(define (cvector->NSArray vec)
  (tell NSArray 
        arrayWithObjects: #:type _pointer (cvector-ptr vec)
        count: #:type _int32 (cvector-length vec)))

(define (list->NSArray lst #:type (type _pointer))
  (let ([vec (list->cvector lst type)])
    (cvector->NSArray vec)))

(define (NSArray-length ar)
  (tell-int32 ar count))

(define (NSArray-ref ar n)
  (tell ar objectAtIndex: #:type _int32 n))

(define (NSArray->list array)
  (for/list ((n (in-range (NSArray-length array))))
    (NSArray-ref array n)))

(define (dict-keys dict)
  (dict-map dict (lambda (k v) k)))

(define (dict-values dict)
  (dict-map dict (lambda (k v) v)))

(define (dictionary->NSDictionary dict)
  (tell NSDictionary
        dictionaryWithObjects: (list->NSArray (dict-values dict))
        forKeys: (list->NSArray
                  (map string->NSString (dict-keys dict)))))

(define (dictionary->NSMutableDictionary d)
  (let ([mutable (tell NSMutableDictionary dictionaryWithCapacity: #:type _int32 (dict-count d))])
    (for (((key value) (in-dict d)))
      (tell mutable 
            setObject: value
            forKey: (string->NSString key)))
    mutable))

Leave a Reply

Your email address will not be published. Required fields are marked *