Skip to content

Commit

Permalink
Add example of FFI with interop between Rust and C.
Browse files Browse the repository at this point in the history
  • Loading branch information
davidzchen committed Feb 17, 2017
1 parent 976f1da commit aaf7740
Show file tree
Hide file tree
Showing 10 changed files with 512 additions and 13 deletions.
7 changes: 7 additions & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ load("//rust:rust.bzl", "rust_repositories")

rust_repositories()

new_git_repository(
name = "libc",
remote = "https://github.com/rust-lang/libc",
tag = "0.2.20",
build_file = "libc.BUILD",
)

# Used for documenting Rust rules.
git_repository(
name = "io_bazel_rules_sass",
Expand Down
35 changes: 35 additions & 0 deletions examples/matrix/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package(default_visibility = ["//visibility:public"])

load("@//rust:rust.bzl", "rust_library", "rust_test")

cc_library(
name = "native_matrix",
srcs = ["src/matrix.c"],
hdrs = ["src/matrix.h"],
)

cc_test(
name = "native_matrix_test",
srcs = ["src/matrix_test.c"],
deps = [
":native_matrix",
],
)

rust_library(
name = "matrix",
srcs = [
"src/ffi.rs",
"src/lib.rs",
"src/matrix.rs",
],
deps = [
":native_matrix",
"@libc//:libc"
],
)

rust_test(
name = "matrix_test",
deps = [":matrix"],
)
35 changes: 35 additions & 0 deletions examples/matrix/src/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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::size_t;
use libc::uint64_t;
use libc::c_int;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Matrix {
pub rows: size_t,
pub cols: size_t,
pub data: *mut uint64_t,
}

#[link(name = "native_matrix")]
extern {
pub fn matrix_new(rows: size_t, cols: size_t, data: *const uint64_t) -> *mut Matrix;
pub fn matrix_at(matrix: *const Matrix, row: size_t, col: size_t, n: *mut uint64_t) -> c_int;
pub fn matrix_set(matrix: *const Matrix, row: size_t, col: size_t, n: uint64_t) -> 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);
}
19 changes: 19 additions & 0 deletions examples/matrix/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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;

pub mod matrix;
124 changes: 124 additions & 0 deletions examples/matrix/src/matrix.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// 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 "matrix/src/matrix.h"

#include <string.h>
#include <stdio.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);
}
43 changes: 43 additions & 0 deletions examples/matrix/src/matrix.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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 <stdlib.h>
#include <stdint.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);
Loading

0 comments on commit aaf7740

Please sign in to comment.