Sunday, April 11, 2021

Making It Easier To Experiment With Compiled Swift Code In R

The previous two posts have (calmly) launched the way to use compiled Swift code in R, however they’ve concerned a bunch of “scary” command line machinations and incantations.

One characteristic of {Rcpp} I’ve all the time is the cppFunction() (“r-lib” zealots have the same cpp11::cpp_function()) which lets one experiment with C[++] code in R with as little friction as attainable. To make it simpler to begin experimenting with Swift, I’ve constructed an extraordinarily fragile swift_function() in {swiftr} that intends to copy this performance. Explaining will probably be simpler with an instance.

Studying Property Lists in R With Swift

macOS depends closely on property lists for a lot of, many issues. These might be plain textual content (XML) or binary recordsdata and there are command-line instruments and Python libraries (usable by way of {reticulate}) that may learn them together with the nice ‘ol XML::readKeyValueDB(). We’re going to create a Swift perform to learn property lists and return JSON which we will use again in R by way of {jsonlite}.

This time round there’s no must create further recordsdata, simply set up {swiftr} and your favourite R IDE and enter the next (expository is after the code):

library(swiftr)

swift_function(
  code="

func ignored() {
  print("""
this will likely be ignored by swift_function() however you might use non-public
features as helpers for the primary public Swift perform which will likely be 
made accessible to R.
""")
}  

@_cdecl ("read_plist")
public func read_plist(path: SEXP) -> SEXP {

  var out: SEXP = R_NilValue

  do {
    // learn within the uncooked plist
    let plistRaw = strive Information(contentsOf: URL(fileURLWithPath: String(cString: R_CHAR(STRING_ELT(path, 0)))))

    // convert it to a PropertyList  
    let plist = strive PropertyListSerialization.propertyList(from: plistRaw, choices: [], format: nil) as! [String:Any]

    // serialize it to JSON
    let jsonData = strive JSONSerialization.knowledge(withJSONObject: plist , choices: .prettyPrinted)

    // setup the JSON string return
    String(knowledge: jsonData, encoding: .utf8)?.withCString { 
      cstr in out = Rf_mkString(cstr) 
    }

  } catch {
    debugPrint("(error)")
  }

  return(out)

}
")

This new swift_function() perform — for the second (the API is completely going to alter) — is outlined as:

swift_function(
  code,
  env = globalenv(),
  imports = c("Basis"),
  cache_dir = tempdir()
)

the place:

  • code is a size 1 character vector of Swift code
  • env is the surroundings to show the perform in (defaults to the worldwide surroundings)
  • imports is a personality vector of any further Swift frameworks that must be imported
  • cache_dir is the place all of the non permanent recordsdata will likely be created and compiled dynlib will likely be saved. It defaults to a short lived listing so specify your personal listing (that exists) if you wish to maintain the recordsdata round after you shut the R session

People aware of cppFunction() will discover some (on-purpose) similarities.

The perform expects you to show solely one public Swift perform which additionally (for the second) must have the @_cdecl decorator earlier than it. You’ll be able to have as many different legitimate Swift helper features as you want, however are restricted to at least one perform that will likely be was an R perform automagically.

On this instance, swift_function() will see public func read_plist(path: SEXP) -> SEXP { and be capable of determine

  • the perform identify (read_plist)
  • the variety of parameters (all of them must be SEXP, for now)
  • the names of the parameters

A whole supply file with all of the imports will likely be created and a pre-built bridging header (which comes alongside for the journey with {swiftr}) will likely be included within the compilation step and a dylib will likely be constructed and loaded into the R session. Lastly, an R perform that wraps a .Name() will likely be created and can have the perform identify of the Swift perform in addition to all of the parameter names (if any).

Within the case of our instance, above, the constructed R perform is:

perform(path) {
  .Name("read_plist", path)
}

There’s a superb probability you’re utilizing RStudio, so we will take a look at this with it’s property listing, or you’ll be able to substitute some other utility’s property listing (or any .plist you will have) to check this out:

read_plist("/Purposes/RStudio.app/Contents/Data.plist") %>% 
  jsonlite::fromJSON() %>% 
  str(1)
## Checklist of 32
##  $ NSPrincipalClass                     : chr "NSApplication"
##  $ NSCameraUsageDescription             : chr "R desires to entry the digital camera."
##  $ CFBundleIdentifier                   : chr "org.rstudio.RStudio"
##  $ CFBundleShortVersionString           : chr "1.4.1093-1"
##  $ NSBluetoothPeripheralUsageDescription: chr "R desires to entry bluetooth."
##  $ NSRemindersUsageDescription          : chr "R desires to entry the reminders."
##  $ NSAppleEventsUsageDescription        : chr "R desires to run AppleScript."
##  $ NSHighResolutionCapable              : logi TRUE
##  $ LSRequiresCarbon                     : logi TRUE
##  $ NSPhotoLibraryUsageDescription       : chr "R desires to entry the photograph library."
##  $ CFBundleGetInfoString                : chr "RStudio 1.4.1093-1, © 2009-2020 RStudio, PBC"
##  $ NSLocationWhenInUseUsageDescription  : chr "R desires to entry location info."
##  $ CFBundleInfoDictionaryVersion        : chr "6.0"
##  $ NSSupportsAutomaticGraphicsSwitching : logi TRUE
##  $ CSResourcesFileMapped                : logi TRUE
##  $ CFBundleVersion                      : chr "1.4.1093-1"
##  $ OSAScriptingDefinition               : chr "RStudio.sdef"
##  $ CFBundleLongVersionString            : chr "1.4.1093-1"
##  $ CFBundlePackageType                  : chr "APPL"
##  $ NSContactsUsageDescription           : chr "R desires to entry contacts."
##  $ NSCalendarsUsageDescription          : chr "R desires to entry calendars."
##  $ NSMicrophoneUsageDescription         : chr "R desires to entry the microphone."
##  $ CFBundleDocumentTypes                :'knowledge.body':  16 obs. of  8 variables:
##  $ NSPhotoLibraryAddUsageDescription    : chr "R desires write entry to the photograph library."
##  $ NSAppleScriptEnabled                 : logi TRUE
##  $ CFBundleExecutable                   : chr "RStudio"
##  $ CFBundleSignature                    : chr "Rstd"
##  $ NSHumanReadableCopyright             : chr "RStudio 1.4.1093-1, © 2009-2020 RStudio, PBC"
##  $ CFBundleName                         : chr "RStudio"
##  $ LSApplicationCategoryType            : chr "public.app-category.developer-tools"
##  $ CFBundleIconFile                     : chr "RStudio.icns"
##  $ CFBundleDevelopmentRegion            : chr "English"

FIN

A source_swift() perform is on the horizon as is including a ton of checks/validations to swift_function(). I’ll possible be including a few of the SEXP and R Swift utility features I’ve demonstrated within the [unfinished] e-book to make it pretty painless to interface Swift and R code on this new and forthcoming perform.

As typical, kick the tyres, submit characteristic requests and bugs in any discussion board that’s snug and keep sturdy, put on a 😷, and socially distanced when out and about.

*** It is a Safety Bloggers Community syndicated weblog from rud.is authored by hrbrmstr. Learn the unique put up at: https://rud.is/b/2021/01/26/making-it-easier-to-experiment-with-compiled-swift-code-in-r/

Latest news

Related news

LEAVE A REPLY

Please enter your comment!
Please enter your name here