diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d70e3a5..654efa3 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -35,8 +35,16 @@ jobs:
run: |
python3 -m pip install pip -U
python3 -m pip install setuptools -U
+ cd python
pip3 install .
python3 -c 'import ruapu; print(ruapu.supports("neon")); print(ruapu.supports(isa="avx"))'
+ - name: build-test-rust
+ run: |
+ rustup update stable
+ rustup default stable
+ cd rust
+ cargo build --verbose
+ cargo test --verbose
macos:
runs-on: macos-latest
@@ -50,8 +58,16 @@ jobs:
run: |
python3 -m pip install pip -U
python3 -m pip install setuptools -U
+ cd python
pip3 install .
python3 -c 'import ruapu; print(ruapu.supports("neon")); print(ruapu.supports(isa="avx"))'
+ - name: build-test-rust
+ run: |
+ rustup update stable
+ rustup default stable
+ cd rust
+ cargo build --verbose
+ cargo test --verbose
macos-arm64:
runs-on: macos-14
@@ -65,8 +81,16 @@ jobs:
run: |
python3 -m pip install pip -U
python3 -m pip install setuptools -U
+ cd python
pip3 install .
python3 -c 'import ruapu; print(ruapu.supports("neon")); print(ruapu.supports(isa="avx"))'
+ - name: build-test-rust
+ run: |
+ rustup update stable
+ rustup default stable
+ cd rust
+ cargo build --verbose
+ cargo test --verbose
windows:
runs-on: windows-latest
@@ -86,8 +110,16 @@ jobs:
run: |
python3 -m pip install pip -U
python3 -m pip install setuptools -U
+ cd python
pip3 install .
python3 -c 'import ruapu; print(ruapu.supports("neon")); print(ruapu.supports(isa="avx"))'
+ - name: build-test-rust
+ run: |
+ rustup update stable
+ rustup default stable
+ cd rust
+ cargo build --verbose
+ cargo test --verbose
qemu:
runs-on: ubuntu-latest
diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml
index 237c8da..05de637 100644
--- a/.github/workflows/pypi.yml
+++ b/.github/workflows/pypi.yml
@@ -31,6 +31,7 @@ jobs:
CIBW_BUILD: "cp311*"
CIBW_BUILD_VERBOSITY: 1
with:
+ package-dir: python
output-dir: wheelhouse
- uses: actions/upload-artifact@v4
diff --git a/.gitignore b/.gitignore
index b07d6d1..ff1ae49 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@ build/
dist/
*.egg-info/
*.pyc
+
+# Rust files
+target
diff --git a/README.md b/README.md
index 957e9c3..d214cff 100644
--- a/README.md
+++ b/README.md
@@ -102,7 +102,7 @@ pip3 install ruapu
```shell
# from source code
-pip3 install .
+pip3 install ./python
```
@@ -121,6 +121,36 @@ ruapu.supports(isa="avx2")
|
+### ruapu with Rust
+
+
+
+
+
+Compile ruapu library
+
+```shell
+# from source code
+cd rust
+cargo build --release
+```
+ |
+
+
+Use ruapu in Rust
+
+```rust
+extern crate ruapu;
+
+fn main() {
+ println!("supports neon: {}", ruapu::supports("neon").unwrap());
+ println!("supports avx2: {}", ruapu::supports("avx2").unwrap());
+ println!("rua: {:?}", ruapu::rua());
+}
+```
+ |
+
+
Github-hosted runner result (Linux)
diff --git a/pyproject.toml b/python/pyproject.toml
similarity index 100%
rename from pyproject.toml
rename to python/pyproject.toml
diff --git a/ruapu-py.c b/python/ruapu-binding.c
similarity index 97%
rename from ruapu-py.c
rename to python/ruapu-binding.c
index c6ca524..03c2712 100644
--- a/ruapu-py.c
+++ b/python/ruapu-binding.c
@@ -1,9 +1,9 @@
+#define RUAPU_IMPLEMENTATION
+#include "../ruapu.h"
+
#define PY_SSIZE_T_CLEAN
#include
-#define RUAPU_IMPLEMENTATION
-#include "ruapu.h"
-
static PyObject *ruapu_supports_py(PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = {"isa", NULL};
diff --git a/setup.py b/python/setup.py
similarity index 94%
rename from setup.py
rename to python/setup.py
index 1baaca1..b62f97d 100644
--- a/setup.py
+++ b/python/setup.py
@@ -16,7 +16,7 @@ class bdist_wheel_abi3(bdist_wheel):
ext = Extension(
name = 'ruapu',
- sources = ['ruapu-py.c'],
+ sources = ['ruapu-binding.c'],
py_limited_api = True
)
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
new file mode 100644
index 0000000..82c468a
--- /dev/null
+++ b/rust/Cargo.lock
@@ -0,0 +1,39 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "cc"
+version = "1.0.88"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc"
+
+[[package]]
+name = "claim"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81099d6bb72e1df6d50bb2347224b666a670912bb7f06dbe867a4a070ab3ce8"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "ruapu"
+version = "0.1.0"
+dependencies = [
+ "cc",
+ "claim",
+ "lazy_static",
+]
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
new file mode 100644
index 0000000..5932f1a
--- /dev/null
+++ b/rust/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "ruapu"
+version = "0.1.0"
+edition = "2021"
+
+[build-dependencies]
+cc = "1.0"
+
+[dev-dependencies]
+claim = "0"
+
+[dependencies]
+lazy_static = "1"
diff --git a/rust/build.rs b/rust/build.rs
new file mode 100644
index 0000000..e318b36
--- /dev/null
+++ b/rust/build.rs
@@ -0,0 +1,6 @@
+fn main() {
+ cc::Build::new()
+ .file("src/ruapu-binding.c")
+ .compile("ruapu-rs");
+ println!("cargo:rerun-if-changed=ruapu-binding.c");
+}
diff --git a/rust/examples/ruapu.rs b/rust/examples/ruapu.rs
new file mode 100644
index 0000000..6da90cb
--- /dev/null
+++ b/rust/examples/ruapu.rs
@@ -0,0 +1,7 @@
+extern crate ruapu;
+
+fn main() {
+ println!("supports neon: {}", ruapu::supports("neon").unwrap());
+ println!("supports avx2: {}", ruapu::supports("avx2").unwrap());
+ println!("rua: {:?}", ruapu::rua());
+}
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
new file mode 100644
index 0000000..c8a7e86
--- /dev/null
+++ b/rust/src/lib.rs
@@ -0,0 +1,76 @@
+#[macro_use]
+extern crate lazy_static;
+
+use std::ffi::{CString, CStr, NulError};
+use std::os::raw::c_char;
+use std::sync::Mutex;
+use std::result::Result;
+
+lazy_static! {
+ static ref RUAPU_INITILIASED: Mutex = Mutex::new(false);
+}
+
+extern "C" {
+ fn ruapu_init();
+ fn ruapu_supports(isa: *const c_char) -> i32;
+ fn ruapu_rua() -> *const *const c_char;
+}
+
+fn init_ruapu() {
+ if !*(RUAPU_INITILIASED.lock().unwrap()) {
+ unsafe {
+ ruapu_init();
+ }
+ *(RUAPU_INITILIASED.lock().unwrap()) = true;
+ }
+}
+
+pub fn supports(isa: &str) -> Result {
+ init_ruapu();
+ let isa = CString::new(isa)?;
+ let isa_ptr = isa.as_ptr();
+ unsafe {
+ Ok(ruapu_supports(isa_ptr) != 0)
+ }
+}
+
+pub fn rua() -> Vec {
+ init_ruapu();
+ let mut result = Vec::new();
+ unsafe {
+ let mut i = 0;
+ let ptr = ruapu_rua();
+ loop {
+ let ptr = ptr.offset(i);
+ if *ptr == std::ptr::null() {
+ break;
+ }
+ let c_str = CStr::from_ptr(*ptr);
+ let str = c_str.to_str().unwrap();
+ result.push(str.to_string());
+ i += 1;
+ }
+ }
+ return result;
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use claim::assert_ok;
+
+ #[test]
+ fn test_supports() {
+ assert_ok!(supports("avx2"));
+ assert_ok!(supports("non_exists_feature"));
+ assert_eq!(supports("non_exists_feature").unwrap(), false);
+
+ let supported_features = rua();
+ for feature in supported_features {
+ assert_eq!(supports(&feature).unwrap(), true);
+ }
+
+ let nul_error = supports("neon\0avx2").unwrap_err();
+ assert_eq!(nul_error.into_vec(), b"neon\0avx2");
+ }
+}
diff --git a/rust/src/ruapu-binding.c b/rust/src/ruapu-binding.c
new file mode 100644
index 0000000..b21d5b4
--- /dev/null
+++ b/rust/src/ruapu-binding.c
@@ -0,0 +1,2 @@
+#define RUAPU_IMPLEMENTATION
+#include "../../ruapu.h"