---
title: "Working with R and JS Types"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Working with R and JS Types}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(QuickJSR)
```

## Mappings and Conversions Between R and JS Types

`QuickJSR` uses the respective `C` APIs of `R` and `QuickJS` in order to pass values between the two. This allows for increased efficiency in passing and returning values (as no serialisation or de-serialisation is required) and also allows for greater flexibility in working with R closures, functions, and environments in JS code.

`QuickJSR` aims to broadly follow the conventions of `jsonlite` in terms of how R types are converted to JS types and vice-versa. 

### Primitive & Scalar Types

The following table outlines the basic mappings of primitive types between R and JS types:

| R Type | JS Type |
|--------|---------|
| NULL   | null    |
| logical| boolean |
| integer| number  |
| double | number  |
| character| string|
| date   | date    |
| POSIXct| date    |
| factor | string  |

Note that the handling of `Date`/`POSIXct` types differs from `jsonlite`, where they are converted to strings. In `QuickJSR`, they are treated directly as `Date` objects in JS.

### Container Types

The following table outlines the basic mappings of container types between R and JS types:

| R Type | JS Type |
|--------|---------|
| named list   | object  |
| unnamed list | array   |
| vector       | array   |
| array        | array   |
| matrix       | 2D number array   |
| data.frame   | array of objects  |

Examples of the `matrix` and `data.frame` conversions are shown below:

```{r}
m <- matrix(1:6, nrow = 2)
cat(to_json(m))
```

```{r}
df <- data.frame(a = 1:3, b = c("x", "y", "z"))
cat(to_json(df))
```

Note that the `to_json()` function operates by converting R objects to their JS equivalents, and then calling `JSON.stringify()` on the result. This allows you to explore how different types are being converted to JS.

### Functions and Closures

Functions and closures can be passed between R and JS code. In JS, functions are represented as `Function` objects, and can be called directly from JS code. 

```{r}
ctx <- JSContext$new()
ctx$source(code = "function callRFunction(f, x, y) { return f(x, y); }")

ctx$call("callRFunction", function(x, y) x + y, 1, 2)
ctx$call("callRFunction", function(x, y) paste0(x, ",", y), "a", "b")
```


## Working with R Environments

R environments are represented in JS as a custom class: `REnv`. The `REnv` class simply wraps the pointer to the R environment, and provides methods for getting and setting values - this means that there is only a 'cost' for conversion when values or accessed or updated.

Environment values can be accessed using either `env.value` or `env["value"]` syntax:

```{r}
ctx$source(code = 'function env_test(env) { return env.a + env["b"]; }')
env <- new.env()
env$a <- 1
env$b <- 2
ctx$call("env_test", env)
```

Values in the environment can also be updated from JS code:

```{r}
ctx$source(code = "function env_update(env) { env.a = 10; env.b = 20; }")
ctx$call("env_update", env)
env$a
env$b
```

## Accessing Package Namespaces & Functions

`QuickJSR` automatically adds a global object `R` to each context, which can be used to access the namespaces of installed packages - and subsequently extract and use functions and objects from them. 

```{r}
qjs_eval('R.package("base").getwd()')
```