## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(rzig)
compiler <- find_zig(required = FALSE)
has_zig <- isTRUE(compiler$supported)

## ----create-------------------------------------------------------------------
path <- file.path(tempdir(), "exportspkg")
create_rzig_package(path, tests = FALSE)
main_zig <- file.path(path, "src", "rzig", "src", "main.zig")

## ----options, comment = ""----------------------------------------------------
cat(
  "",
  "/// Shrink values towards zero.",
  "/// @param x A numeric vector.",
  "/// @param amount The amount to subtract from each absolute value.",
  "/// @default amount 0.5",
  "/// @return The shrunk values, invisibly.",
  "/// @export name=shrink invisible",
  "pub fn shrink_zig(ctx: *rzig.Ctx, x: []const f64, amount: f64) rzig.Error![]f64 {",
  "    const out = try ctx.alloc(f64, x.len);",
  "    for (x, out) |value, *slot| {",
  "        const size = @max(@abs(value) - amount, 0);",
  "        slot.* = if (value < 0) -size else size;",
  "    }",
  "    return out;",
  "}",
  sep = "\n", file = main_zig, append = TRUE
)

## ----internal, comment = ""---------------------------------------------------
cat(
  "",
  "/// The weighted mean, for weighted_mean().",
  "/// @export internal",
  "pub fn weighted_mean_zig(x: []const f64, w: []const f64) rzig.Error!f64 {",
  "    if (x.len != w.len) return rzig.raise(\"x and w differ in length\", .{});",
  "    var total: f64 = 0;",
  "    var weights: f64 = 0;",
  "    for (x, w) |value, weight| {",
  "        total += value * weight;",
  "        weights += weight;",
  "    }",
  "    return total / weights;",
  "}",
  sep = "\n", file = main_zig, append = TRUE
)
writeLines(c(
  "#' The weighted mean",
  "#'",
  "#' @param x A numeric vector.",
  "#' @param w Non-negative weights of the same length.",
  "#' @return A number.",
  "#' @export",
  "weighted_mean <- function(x, w = rep(1, length(x))) {",
  "  stopifnot(is.numeric(x), is.numeric(w), all(w >= 0))",
  "  weighted_mean_zig(as.double(x), as.double(w))",
  "}"
), file.path(path, "R", "weighted.R"))

## ----class, comment = ""------------------------------------------------------
cat(
  "",
  "/// A running mean.",
  "/// @class",
  "pub const RunningMean = struct {",
  "    total: f64 = 0,",
  "    count: usize = 0,",
  "",
  "    /// Create an empty running mean.",
  "    pub fn init() RunningMean {",
  "        return .{};",
  "    }",
  "",
  "    /// Add values.",
  "    pub fn add(self: *RunningMean, values: []const f64) void {",
  "        for (values) |value| self.total += value;",
  "        self.count += values.len;",
  "    }",
  "",
  "    /// The mean of the values added so far.",
  "    pub fn mean(self: *const RunningMean) f64 {",
  "        return self.total / @as(f64, @floatFromInt(self.count));",
  "    }",
  "};",
  sep = "\n", file = main_zig, append = TRUE
)

## ----scan---------------------------------------------------------------------
scan_exports(path)

## ----document-----------------------------------------------------------------
bindings <- document(path)
cat(bindings$wrappers)

## ----namespace----------------------------------------------------------------
cat("export(weighted_mean)\n", file = file.path(path, "NAMESPACE"), append = TRUE)
cat(readLines(file.path(path, "NAMESPACE")), sep = "\n")

## ----build, eval = has_zig----------------------------------------------------
build <- build_zig(path)
library(build$package, character.only = TRUE, lib.loc = build$library)
shrink(c(-2, 0.2, 3))
print(shrink(c(-2, 0.2, 3), amount = 1))
weighted_mean(c(1, 2, 3), c(1, 1, 2))
exists("weighted_mean_zig", envir = asNamespace("exportspkg"))
"weighted_mean_zig" %in% getNamespaceExports("exportspkg")
m <- RunningMean()
m$add(c(1, 2, 3))
m$add(10)
m$mean()
m

## ----cleanup, include = FALSE-------------------------------------------------
if (has_zig) unloadNamespace("exportspkg")
unlink(path, recursive = TRUE)

