Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce rust support #1148

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
cmake_minimum_required ( VERSION 3.17 )

# Support for Rust Programming Language
include(FetchContent)
FetchContent_Declare(
Corrosion
GIT_REPOSITORY https://github.com/corrosion-rs/corrosion.git
GIT_TAG v0.3.5
)
FetchContent_MakeAvailable(Corrosion)

FOREACH (policy CMP0012 CMP0013 CMP0014 CMP0048 CMP0074 CMP0077 CMP0091 CMP0110)
IF (POLICY ${policy})
CMAKE_POLICY ( SET ${policy} NEW )
Expand Down Expand Up @@ -375,6 +384,7 @@ set ( CPACK_PROJECT_CONFIG_FILE "${MANTICORE_BINARY_DIR}/config/CPackOptions.cma
set ( DEFAULT_CTEST_CONFIGURATION_TYPE "Debug" )
include ( CTest )

add_subdirectory ( rust )
add_subdirectory ( src )

if (BUILD_TESTING)
Expand Down Expand Up @@ -428,4 +438,3 @@ feature_summary ( WHAT ENABLED_FEATURES INCLUDE_QUIET_PACKAGES DESCRIPTION "Enab
feature_summary ( WHAT RUNTIME_PACKAGES_FOUND INCLUDE_QUIET_PACKAGES DESCRIPTION "Available runtime features:" )

#feature_summary (WHAT ALL DESCRIPTION "Enabled ALL features4:")

5 changes: 4 additions & 1 deletion dist/build_dockers/cross/external_toolchain/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@ RUN cd / \
&& curl -L https://github.com/Kitware/CMake/releases/download/v$cmakever/cmake-$cmakever-linux-$arch.tar.gz | tar -zx
ENV PATH $PATH:/cmake-$cmakever-linux-x86_64/bin:/cmake-$cmakever-linux-aarch64/bin

# 5-th layer. Everything to build, except actual sysroot archives
# 5-th layer, cargo toolchain for Rust Programming Language
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

# 6-th layer. Everything to build, except actual sysroot archives
ENV CMAKE_GENERATOR=Ninja
ENV CMAKE_TOOLCHAIN_FILE=/sysroot/root/toolchain.cmake
RUN git config --global --add safe.directory '*'
Expand Down
1 change: 1 addition & 0 deletions rust/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory( rust_hello_world )
89 changes: 89 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Rust usage in ManticoreSearch

This directory contains all rust modules, used by ManticoreSearch.
The Simple "hello world" project is a toy example for rust integration into C++, and will be replaced with
something more representive and useful. C++ usage of this example may be like:
```cpp
include "rust_hello_world.h"

int main ( int argc, char ** argv )
{
hello_from_rust();
}
```
# I want to add some Rust code, what do I need to do?

- ```shell
# manticoresearch/rust directory
cargo new lib_name --lib # replace "lib_name" with your name
```
- Edit your Cargo.toml
- ```toml
[lib]
crate-type = ["staticlib"]
```
Set crate type to "staticlib"
- ```toml
[profile.production]
inherits = "release"
lto = true
codegen-units = 1
````
LTO and Codegen Units are options for Rust compiler, usually provides better performance. You may experiment with
them.
Production profile will be linked with ManticoreSearch C++ code.
- Place `CMakeLists.txt` file with followed content
([additional options](https://corrosion-rs.github.io/corrosion/usage.html)):
```
corrosion_import_crate(
MANIFEST_PATH Cargo.toml
PROFILE production
)

target_include_directories(_rust_hello_world INTERFACE include)
add_library(manticore-rs::hello_world ALIAS _rust_hello_world)
```
Change "rust_hello_world" and "hello_world" to yours.
Notice that "rust_hello_world" should be linked to
```
[package]
name = "rust_hello_world"
```
- Make directory named "include" and place header file inside. Refer to rust_hello_world project
example.
- Finally, edit `CMakeLists.txt` file in "rust" directory
```
add_subdirectory( %your_project_name% )
```
with name of your Rust project.
- Edit `src/CMakeLists.txt` to add your Rust code into binary
```text
# RUST SECTION
target_link_libraries ( searchd manticore-rs::hello_world )
# add here your project
```
# Some code agreement

- Notice that "rust_hello_world" project doesn't have tests, because of extreme simplicity. Don't ignore tests.
- __Don't allow your production code to panic!__
No ```unwrap()``` like here:
```rust
let example = std::fs::read_dir("/path/to/file").unwrap();
```
It's ok to your code panic while prototyping, etc., but not in production mode.
- Use cargo clippy to format your code properly.
You may try to use clippy flags, like here:
```shell
cargo clippy \
-W clippy::pedantic \
-W clippy::nursery \
-W clippy::unwrap_used
```
- Some useful tools. Mark them as dev-dependency in Cargo.toml.
- [Doctests](https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html)
- Property testing with [proptest](https://github.com/proptest-rs/proptest)
- Fuzz testing with [cargo-fuzz](https://rust-fuzz.github.io/book/cargo-fuzz.html)
- Mutation testing with [mutagen](https://github.com/llogiq/mutagen), but be careful with that one
- Microbenchmarks. Look at [criterion-rs](https://github.com/bheisler/criterion.rs)
and [iai](https://github.com/bheisler/iai)
- I may forget to mention something. Welcome to https://github.com/manticoresoftware/manticoresearch/issues
7 changes: 7 additions & 0 deletions rust/rust_hello_world/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
corrosion_import_crate(
MANIFEST_PATH Cargo.toml NO_STD
PROFILE production
)

target_include_directories(rust_hello_world INTERFACE include)
add_library(manticore-rs::hello_world ALIAS rust_hello_world)
16 changes: 16 additions & 0 deletions rust/rust_hello_world/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "rust_hello_world"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

[lib]
crate-type = ["staticlib"]

[profile.production]
inherits = "release"
lto = true
codegen-units = 1
12 changes: 12 additions & 0 deletions rust/rust_hello_world/include/rust_hello_world.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef RUST_HELLO_WORLD_H
#define RUST_HELLO_WORLD_H

#include <cstddef>
#include <vector>
extern "C" {

void hello_from_rust();
void const_char_ptr_to_stdout_by_rust(const char *, std::vector<double> *, std::size_t);

}
#endif
32 changes: 32 additions & 0 deletions rust/rust_hello_world/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use core::slice;
use std::ffi::CStr;
use std::os::raw::c_char;
use std::ptr::null;

#[no_mangle]
pub extern "C" fn hello_from_rust() {
println!("Good morning from Rust programming language!");
}

#[no_mangle]
pub unsafe extern "C" fn const_char_ptr_to_stdout_by_rust(
c_str: *const c_char,
data: *mut f64,
len: usize,
) {
let sl = slice::from_raw_parts_mut(data, len);
if c_str.is_null() {
return;
}
unsafe {
let s = CStr::from_ptr(c_str);
println!("From Rust: {:#?}", s);
}
sl.iter_mut()
.enumerate()
.for_each(|(index, x)| *x = index as f64);
println!("From Rust slice: {:#?}", sl);
}

#[cfg(test)]
mod tests {}
3 changes: 3 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,9 @@ trace ( lsearchd )
add_executable ( searchd searchd.cpp )
target_link_libraries ( searchd searchd_ssl lmanticore lsearchd )

# RUST SECTION
target_link_libraries ( searchd manticore-rs::hello_world )

if (NOT STATIC_BINARY)
add_executable ( indexer indexer.cpp )
add_executable ( indextool indextool.cpp )
Expand Down
19 changes: 19 additions & 0 deletions src/searchd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
#include "frontendschema.h"
#include "skip_cache.h"


// services
#include "taskping.h"
#include "taskmalloctrim.h"
Expand All @@ -78,6 +79,7 @@
#include "searchdbuddy.h"
#include "detail/indexlink.h"
#include "detail/expmeter.h"
#include "rust_hello_world.h"

extern "C"
{
Expand Down Expand Up @@ -21467,6 +21469,15 @@ int WINAPI ServiceMain ( int argc, char **argv ) EXCLUDES (MainThread)
}
} // NOLINT ServiceMain() function length

#include <iostream>
#include <vector>

void print(std::vector<double> input)
{
std::cout << input[0] << ' ';
std::cout << input[1] << ' ';
}

inline int mainimpl ( int argc, char **argv )
{
// threads should be initialized before memory allocations
Expand All @@ -21477,6 +21488,14 @@ inline int mainimpl ( int argc, char **argv )
g_pLogger() = sphLog;
sphBacktraceSetBinaryName ( argv[0] );
GeodistInit();
hello_from_rust();
std::vector<double> vec;
vec.push_back(10.0);
vec.push_back(20.0);
std::vector<double> *v_ptr = &vec;
const char* text = "sample text for interop traversal";
const_char_ptr_to_stdout_by_rust ( text, v_ptr, vec.size() );
print(vec);

#if _WIN32
int iNameIndex = -1;
Expand Down
Loading