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));
+ }
+}