Squashed 'third_party/rules_rust/' content from commit bf59038ca

git-subtree-dir: third_party/rules_rust
git-subtree-split: bf59038cac11798cbaef9f3bf965bad8182b97fa
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I5a20e403203d670df467ea97dde9a4ac40339a8d
diff --git a/examples/ffi/BUILD.bazel b/examples/ffi/BUILD.bazel
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/examples/ffi/BUILD.bazel
diff --git a/examples/ffi/c_calling_rust/BUILD.bazel b/examples/ffi/c_calling_rust/BUILD.bazel
new file mode 100644
index 0000000..b491126
--- /dev/null
+++ b/examples/ffi/c_calling_rust/BUILD.bazel
@@ -0,0 +1,18 @@
+load("@rules_cc//cc:defs.bzl", "cc_test")
+load("@rules_rust//rust:defs.bzl", "rust_static_library", "rust_test")
+
+rust_static_library(
+    name = "rusty",
+    srcs = ["lib.rs"],
+)
+
+rust_test(
+    name = "rusty_test",
+    crate = ":rusty",
+)
+
+cc_test(
+    name = "main",
+    srcs = ["main.c"],
+    deps = [":rusty"],
+)
diff --git a/examples/ffi/c_calling_rust/lib.rs b/examples/ffi/c_calling_rust/lib.rs
new file mode 100644
index 0000000..2d6fc52
--- /dev/null
+++ b/examples/ffi/c_calling_rust/lib.rs
@@ -0,0 +1,14 @@
+#[no_mangle]
+pub extern "C" fn my_favorite_number() -> i32 {
+    4
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_my_favorite_number() {
+        assert_eq!(4, my_favorite_number());
+    }
+}
diff --git a/examples/ffi/c_calling_rust/main.c b/examples/ffi/c_calling_rust/main.c
new file mode 100644
index 0000000..2a57330
--- /dev/null
+++ b/examples/ffi/c_calling_rust/main.c
@@ -0,0 +1,9 @@
+#include <assert.h>
+#include <stdint.h>
+
+extern int32_t my_favorite_number();
+
+int main(int argc, char** argv) {
+  assert(my_favorite_number() == 4);
+  return 0;
+}
diff --git a/examples/ffi/rust_calling_c/BUILD.bazel b/examples/ffi/rust_calling_c/BUILD.bazel
new file mode 100644
index 0000000..041d1da
--- /dev/null
+++ b/examples/ffi/rust_calling_c/BUILD.bazel
@@ -0,0 +1,62 @@
+load("@rules_rust//rust:defs.bzl", "rust_doc", "rust_library", "rust_test")
+
+package(default_visibility = ["//ffi/rust_calling_c:__subpackages__"])
+
+rust_library(
+    name = "matrix",
+    srcs = [
+        "src/ffi.rs",
+        "src/matrix.rs",
+    ],
+    deps = [
+        "//ffi/rust_calling_c/c:native_matrix",
+        "@libc",
+    ],
+)
+
+rust_test(
+    name = "matrix_test",
+    crate = ":matrix",
+)
+
+rust_doc(
+    name = "matrix_doc",
+    crate = ":matrix",
+)
+
+## Do the same as above, but with a dynamic c library.
+
+rust_library(
+    name = "matrix_dynamically_linked",
+    srcs = [
+        "src/ffi.rs",
+        "src/matrix.rs",
+    ],
+    crate_root = "src/matrix.rs",
+    target_compatible_with = select({
+        # TODO: Make this work on windows
+        "@platforms//os:windows": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    }),
+    deps = [
+        "//ffi/rust_calling_c/c:native_matrix_so",
+        "@libc",
+    ],
+)
+
+rust_test(
+    name = "matrix_dylib_test",
+    crate = ":matrix_dynamically_linked",
+    target_compatible_with = select({
+        # TODO: This test requires --incompatible_macos_set_install_name and Bazel 4.2.0+
+        "@platforms//os:macos": ["@platforms//:incompatible"],
+        # TODO: Make this work on windows
+        "@platforms//os:windows": ["@platforms//:incompatible"],
+        "//conditions:default": [],
+    }),
+)
+
+rust_doc(
+    name = "matrix_dylib_doc",
+    crate = ":matrix_dynamically_linked",
+)
diff --git a/examples/ffi/rust_calling_c/c/BUILD.bazel b/examples/ffi/rust_calling_c/c/BUILD.bazel
new file mode 100644
index 0000000..2cab18b
--- /dev/null
+++ b/examples/ffi/rust_calling_c/c/BUILD.bazel
@@ -0,0 +1,38 @@
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library", "cc_test")
+
+package(default_visibility = ["//ffi/rust_calling_c:__subpackages__"])
+
+cc_library(
+    name = "native_matrix",
+    srcs = ["matrix.c"],
+    hdrs = ["matrix.h"],
+    copts = ["-std=c99"],
+)
+
+cc_test(
+    name = "native_matrix_test",
+    srcs = ["matrix_test.c"],
+    copts = ["-std=c99"],
+    linkstatic = 1,
+    deps = [
+        ":native_matrix",
+    ],
+)
+
+## Do the same as above, but with a dynamic c library.
+
+cc_import(
+    name = "native_matrix_so",
+    hdrs = ["matrix.h"],
+    shared_library = ":libnative_matrix_so.so",
+)
+
+cc_binary(
+    name = "libnative_matrix_so.so",
+    srcs = [
+        "matrix.c",
+        "matrix.h",
+    ],
+    copts = ["-std=c99"],
+    linkshared = True,
+)
diff --git a/examples/ffi/rust_calling_c/c/matrix.c b/examples/ffi/rust_calling_c/c/matrix.c
new file mode 100644
index 0000000..6a4c811
--- /dev/null
+++ b/examples/ffi/rust_calling_c/c/matrix.c
@@ -0,0 +1,123 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "ffi/rust_calling_c/c/matrix.h"
+
+#include <stdio.h>
+#include <string.h>
+
+Matrix* matrix_new(size_t rows, size_t cols, const uint64_t* data) {
+  if (data == NULL) {
+    return NULL;
+  }
+  Matrix* matrix = (Matrix*)malloc(sizeof(*matrix));
+  if (matrix == NULL) {
+    return NULL;
+  }
+  matrix->rows = rows;
+  matrix->cols = cols;
+  matrix->data = (uint64_t*)malloc(rows * cols * sizeof(*(matrix->data)));
+  memcpy(matrix->data, data, rows * cols * sizeof(*data));
+  return matrix;
+}
+
+int matrix_at(const Matrix* matrix, size_t row, size_t col, uint64_t* n) {
+  if (matrix == NULL || matrix->data == NULL || n == NULL) {
+    return 0;
+  }
+  if (row >= matrix->rows || col >= matrix->cols) {
+    return 0;
+  }
+  *n = matrix->data[row * matrix->cols + col];
+  return 1;
+}
+
+int matrix_set(const Matrix* matrix, size_t row, size_t col, uint64_t n) {
+  if (matrix == NULL || matrix->data == NULL) {
+    return 0;
+  }
+  if (row >= matrix->rows || col >= matrix->cols) {
+    return 0;
+  }
+  matrix->data[row * matrix->cols + col] = n;
+  return 1;
+}
+
+void matrix_transpose(Matrix* matrix) {
+  if (matrix == NULL || matrix->data == NULL) {
+    return;
+  }
+
+  size_t len = matrix->rows * matrix->cols;
+  int* visited = (int*)malloc(len * sizeof(*visited));
+  if (visited == NULL) {
+    return;
+  }
+  memset(visited, 0, len * sizeof(*visited));
+
+  // Follow-the-cycles implementation of matrix transposition. Note that we
+  // skip the last element since it always has a cycle of length 1 and thus
+  // does not need to be moved.
+  size_t q = matrix->rows * matrix->cols - 1;
+  for (size_t i = 0; i < q; ++i) {
+    if (visited[i] == 1) {
+      continue;
+    }
+    size_t current_idx = i;
+    size_t next_idx = i;
+    do {
+      visited[current_idx] = 1;
+      next_idx = (current_idx * matrix->cols) % q;
+      if (next_idx == i) {
+        break;
+      }
+
+      uint64_t current_val = matrix->data[current_idx];
+      matrix->data[current_idx] = matrix->data[next_idx];
+      matrix->data[next_idx] = current_val;
+      current_idx = next_idx;
+    } while (1);
+  }
+
+  free(visited);
+  size_t cols = matrix->rows;
+  matrix->rows = matrix->cols;
+  matrix->cols = cols;
+}
+
+int matrix_equal(const Matrix* a, const Matrix* b) {
+  if (a == NULL || b == NULL || a->data == NULL || b->data == NULL) {
+    return 0;
+  }
+  if (a->rows != b->rows || a->cols != b->cols) {
+    return 0;
+  }
+  size_t len = a->rows * a->cols;
+  for (size_t i = 0; i < len; ++i) {
+    if (a->data[i] != b->data[i]) {
+      return 0;
+    }
+  }
+  return 1;
+}
+
+void matrix_free(Matrix* matrix) {
+  if (matrix == NULL) {
+    return;
+  }
+  if (matrix->data != NULL) {
+    free(matrix->data);
+  }
+  free(matrix);
+}
diff --git a/examples/ffi/rust_calling_c/c/matrix.h b/examples/ffi/rust_calling_c/c/matrix.h
new file mode 100644
index 0000000..40797a2
--- /dev/null
+++ b/examples/ffi/rust_calling_c/c/matrix.h
@@ -0,0 +1,48 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef MATRIX_SRC_MATRIX_H_
+#define MATRIX_SRC_MATRIX_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct {
+  size_t rows;
+  size_t cols;
+  uint64_t* data;
+} Matrix;
+
+// Constructs a new Matrix from the given data.
+// Matrix returned contains a copy of the data provided.
+Matrix* matrix_new(size_t rows, size_t cols, const uint64_t* data);
+
+// Fetches the value at the specified row and column.
+// Returns 1 if successful, 0 otherwise.
+int matrix_at(const Matrix* matrix, size_t row, size_t col, uint64_t* n);
+
+// Sets the value at the specified row and column.
+// Returns 1 if successful, 0 otherwise.
+int matrix_set(const Matrix* matrix, size_t row, size_t col, uint64_t n);
+
+// Performs an in-place transposition of the matrix.
+void matrix_transpose(Matrix* matrix);
+
+// Returns 1 if the two matrices are equal, 0 otherwise;
+int matrix_equal(const Matrix* a, const Matrix* b);
+
+// Frees the matrix.
+void matrix_free(Matrix* matrix);
+
+#endif // MATRIX_SRC_MATRIX_H_
diff --git a/examples/ffi/rust_calling_c/c/matrix_test.c b/examples/ffi/rust_calling_c/c/matrix_test.c
new file mode 100644
index 0000000..d7bb76b
--- /dev/null
+++ b/examples/ffi/rust_calling_c/c/matrix_test.c
@@ -0,0 +1,80 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "ffi/rust_calling_c/c/matrix.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void matrix_print(const Matrix* m) {
+  for (size_t i = 0; i < m->rows; ++i) {
+    for (size_t j = 0; j < m->cols; ++j) {
+      uint64_t val = 0;
+      matrix_at(m, i, j, &val);
+      printf("%"PRIu64" ", val);
+    }
+    printf("\n");
+  }
+}
+
+int check_equal(const Matrix* a, const Matrix* b) {
+  int equal = matrix_equal(a, b);
+  if (!equal) {
+    printf("Matrices not equal:\n");
+    printf("a:\n");
+    matrix_print(a);
+    printf("\nb:\n");
+    matrix_print(b);
+  }
+  return equal;
+}
+
+void test_equal() {
+  static uint64_t a_data[] = {11, 12, 13, 14,
+                              21, 22, 23, 24};
+  Matrix* a = matrix_new(2, 4, a_data);
+  assert(a != NULL);
+  assert(check_equal(a, a));
+
+  static uint64_t b_data[] = {13, 14, 15, 16,
+                              22, 23, 24, 25};
+  Matrix* b = matrix_new(2, 4, b_data);
+  assert(b != NULL);
+  assert(!matrix_equal(a, b));
+}
+
+void test_transpose() {
+  static uint64_t matrix_data[] = {11, 12, 13, 14,
+                                   21, 22, 23, 24};
+  Matrix* matrix = matrix_new(2, 4, matrix_data);
+  assert(matrix != NULL);
+  matrix_transpose(matrix);
+
+  static uint64_t expected_transpose_data[] = {11, 21,
+                                               12, 22,
+                                               13, 23,
+                                               14, 24};
+  Matrix* expected_transpose = matrix_new(4, 2, expected_transpose_data);
+
+  assert(check_equal(expected_transpose, matrix));
+}
+
+int main(int argc, char** argv) {
+  test_equal();
+  test_transpose();
+  return EXIT_SUCCESS;
+}
diff --git a/examples/ffi/rust_calling_c/src/ffi.rs b/examples/ffi/rust_calling_c/src/ffi.rs
new file mode 100644
index 0000000..4aa6458
--- /dev/null
+++ b/examples/ffi/rust_calling_c/src/ffi.rs
@@ -0,0 +1,33 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use libc::{c_int, size_t};
+
+#[repr(C)]
+#[derive(Clone, Copy)]
+pub struct Matrix {
+    pub rows: size_t,
+    pub cols: size_t,
+    pub data: *mut u64,
+}
+
+// #[link(name = "native_matrix")] // Don't need this, BUILD file manages linking already.
+extern "C" {
+    pub fn matrix_new(rows: size_t, cols: size_t, data: *const u64) -> *mut Matrix;
+    pub fn matrix_at(matrix: *const Matrix, row: size_t, col: size_t, n: *mut u64) -> c_int;
+    pub fn matrix_set(matrix: *const Matrix, row: size_t, col: size_t, n: u64) -> c_int;
+    pub fn matrix_transpose(matrix: *mut Matrix);
+    pub fn matrix_equal(a: *const Matrix, b: *const Matrix) -> c_int;
+    pub fn matrix_free(matrix: *mut Matrix);
+}
diff --git a/examples/ffi/rust_calling_c/src/matrix.rs b/examples/ffi/rust_calling_c/src/matrix.rs
new file mode 100644
index 0000000..9103179
--- /dev/null
+++ b/examples/ffi/rust_calling_c/src/matrix.rs
@@ -0,0 +1,139 @@
+// Copyright 2017 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+extern crate libc;
+
+mod ffi;
+
+use std::ops;
+use std::ptr;
+
+/// Wrapper around pointer to FFI Matrix struct.
+pub struct Matrix {
+    matrix: *mut ffi::Matrix,
+}
+
+/// Wrapper around low-level FFI Matrix API.
+impl Matrix {
+    /// Constructs a new Matrix from the given data. Matrix returned contains a copy of the data
+    /// provided.
+    ///
+    /// # Panics
+    ///
+    /// If rows * cols does not equal data.len() or if matrix could not be allocated.
+    pub fn new(rows: usize, cols: usize, data: &[u64]) -> Matrix {
+        if data.len() != rows * cols {
+            panic!(
+                "rows * cols ({}) do not equal data.len() ({})",
+                rows * cols,
+                data.len()
+            );
+        }
+
+        let mut data_copy: Vec<u64> = vec![0; data.len()];
+        data_copy.clone_from_slice(data);
+        unsafe {
+            let matrix: *mut ffi::Matrix = ffi::matrix_new(rows, cols, data_copy.as_ptr());
+            if matrix.is_null() {
+                panic!("Failed to allocate Matrix.");
+            }
+            Matrix { matrix }
+        }
+    }
+
+    /// Fetches the value at the specified row and column.
+    pub fn at(&self, row: usize, col: usize) -> Option<u64> {
+        let mut n: u64 = 0;
+        unsafe {
+            if ffi::matrix_at(self.matrix, row, col, &mut n) == 0 {
+                return None;
+            }
+        }
+        Some(n)
+    }
+
+    /// Sets the value at the specified row and column.
+    ///
+    /// # Panics
+    ///
+    /// If row, col is out of bounds.
+    pub fn set(&mut self, row: usize, col: usize, n: u64) {
+        unsafe {
+            if ffi::matrix_set(self.matrix, row, col, n) == 0 {
+                panic!("Row {}, col {} is out of bounds.", row, col);
+            }
+        }
+    }
+
+    /// Returns the number of rows of the matrix.
+    pub fn rows(&self) -> usize {
+        unsafe { (*self.matrix).rows }
+    }
+
+    /// Returns the number of cols of the matrix.
+    pub fn cols(&self) -> usize {
+        unsafe { (*self.matrix).cols }
+    }
+
+    /// Performs an in-place transposition of the matrix.
+    pub fn transpose(&mut self) {
+        unsafe {
+            ffi::matrix_transpose(self.matrix);
+        }
+    }
+
+    /// Checks whether the matrix is equal to the provided Matrix.
+    pub fn equal(&self, other: &Matrix) -> bool {
+        unsafe { ffi::matrix_equal(self.matrix, other.matrix) != 0 }
+    }
+}
+
+impl ops::Drop for Matrix {
+    fn drop(&mut self) {
+        unsafe {
+            ffi::matrix_free(self.matrix);
+        }
+        self.matrix = ptr::null_mut();
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::Matrix;
+
+    #[test]
+    fn test_size() {
+        let matrix = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]);
+        assert_eq!(2, matrix.rows());
+        assert_eq!(4, matrix.cols());
+    }
+
+    #[test]
+    fn test_equal() {
+        let matrix_a = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]);
+        let matrix_b = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]);
+        assert!(matrix_a.equal(&matrix_b));
+
+        let matrix_c = Matrix::new(2, 4, &[12, 13, 14, 15, 23, 24, 25, 26]);
+        assert!(!matrix_a.equal(&matrix_c));
+    }
+
+    #[test]
+    fn test_transpose() {
+        let mut matrix = Matrix::new(2, 4, &[11, 12, 13, 14, 21, 22, 23, 24]);
+        matrix.transpose();
+        let expected = Matrix::new(4, 2, &[11, 21, 12, 22, 13, 23, 14, 24]);
+        assert!(matrix.equal(&expected));
+    }
+}