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

Add cxx for binding between Rust and C++ with CMake #274

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
15 changes: 14 additions & 1 deletion softwareComponents/rust-rofi_voxel/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
cmake_minimum_required(VERSION 3.15)

add_rust_library(rofi_voxel)
add_rust_library(rofi_voxel FEATURES cpp_json_bindings CXX_LIB_NAME rofi_voxel_cpp_json_bindings)
add_rust_tests(test-rofi_voxel ALL_FEATURES)


set(BINDING_SRCS
binding_src/voxel_reconfig_binding.cpp
)
add_library(voxel_reconfig ${BINDING_SRCS})
target_link_libraries(voxel_reconfig PRIVATE rofi_voxel configurationWithJson)
target_link_libraries(voxel_reconfig PUBLIC atoms voxel)
target_include_directories(voxel_reconfig PUBLIC binding_include)

file(GLOB BINDING_TEST_SRC binding_test/*.cpp)
add_executable(test-binding_voxel_reconfig ${BINDING_TEST_SRC})
target_link_libraries(test-binding_voxel_reconfig PRIVATE Catch2WithMain voxel_reconfig)
14 changes: 14 additions & 0 deletions softwareComponents/rust-rofi_voxel/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
[package]
name = "rofi_voxel"
version = "0.1.0"
authors = [ "Ondřej Svoboda <[email protected]>" ]
edition = "2021"
publish = false
repository = "https://github.com/paradise-fi/RoFI"

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

[features]
default = [ "cpp_json_bindings" ]
cpp_json_bindings = [ "dep:serde_json", "dep:failure", "dep:cxx", "dep:cxx-build" ]

[dependencies]
amplify = "3.13.0"
bimap = "0.6.2"
Expand All @@ -17,3 +24,10 @@ rs-graph = "0.20.1"
serde = { version = "1.0", features = ["derive"] }
smallvec = "1.8.1"
static_assertions = "1.1.0"

cxx = { version = "1.0", optional = true }
serde_json = { version = "1.0", optional = true }
failure = { version = "0.1.8", optional = true }

[build-dependencies]
cxx-build = { version = "1.0", optional = true }
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <vector>

#include "atoms/result.hpp"
#include "voxel.hpp"

namespace rofi::voxel
{
auto voxel_reconfig( const rofi::voxel::VoxelWorld & init, const rofi::voxel::VoxelWorld & goal )
-> atoms::Result< std::vector< rofi::voxel::VoxelWorld > >;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include "voxel_reconfig.hpp"

#include <cstdint>
#include <ranges>

#include "configuration/serialization.hpp"
#include "cpp_json_bindings.rs.h"


namespace rofi::voxel
{
auto voxel_reconfig( const rofi::voxel::VoxelWorld & init, const rofi::voxel::VoxelWorld & goal )
-> atoms::Result< std::vector< rofi::voxel::VoxelWorld > >
{
using namespace std::string_literals;
namespace serialization = rofi::configuration::serialization;

auto initJson = nlohmann::json( init ).dump();
auto goalJson = nlohmann::json( goal ).dump();

auto result = std::vector< rofi::voxel::VoxelWorld >();

try {
auto rustResult = voxel_reconfiguration( initJson, goalJson );
std::ranges::copy( rustResult, std::back_insert_iterator( rustResult ) );
} catch ( const nlohmann::json::exception & e ) {
return atoms::result_error( "Error while parsing json from Rust voxel reconfiguration ("s
+ e.what() + ")" );
}

// auto resultJson = nlohmann::json();
// try {
// resultJson = nlohmann::json::parse( resultPtr );
// } catch ( const nlohmann::json::exception & e ) {
// rust_free_cstring( resultPtr );
// return atoms::result_error( "Error while parsing json from Rust voxel reconfiguration ("s
// + e.what() + ")" );
// }
// rust_free_cstring( resultPtr );

// try {
// return atoms::result_value( resultJson.get< std::vector< VoxelWorld > >() );
// } catch ( const nlohmann::json::exception & e ) {
// return atoms::result_error( "Error while getting VoxelWorlds from json ("s + e.what()
// + ")" );
// }

// return atoms::result_error( "Not implemented"s );
return atoms::result_value( result );
}

} // namespace rofi::voxel
66 changes: 66 additions & 0 deletions softwareComponents/rust-rofi_voxel/binding_test/voxel_reconfig.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#include "voxel_reconfig.hpp"

#include <catch2/catch.hpp>

#include "configuration/rofiworld.hpp"
#include "configuration/universalModule.hpp"
#include "voxel.hpp"


using namespace rofi::configuration;

TEST_CASE( "No error" )
{
SECTION( "Single module - default" )
{
auto world = RofiWorld();

auto & um = world.insert( UniversalModule( 1, 0_deg, 0_deg, 0_deg ) );
connect< RigidJoint >( um.connectors()[ 0 ], Vector{ 0, 0, 0 }, matrices::identity );
REQUIRE( world.validate() );

auto voxelWorld = rofi::voxel::VoxelWorld::fromRofiWorld( world );
REQUIRE( voxelWorld );

auto result = rofi::voxel::voxel_reconfig( *voxelWorld, *voxelWorld );
REQUIRE( result );

CHECK( result->size() == 0 );
}

SECTION( "Single module - one move" )
{
auto initWorld = RofiWorld();
auto & initUm = initWorld.insert( UniversalModule( 1, 0_deg, 0_deg, 0_deg ) );
connect< RigidJoint >( initUm.connectors()[ 0 ], Vector{ 0, 0, 0 }, matrices::identity );
REQUIRE( initWorld.validate() );
auto initVoxelWorld = rofi::voxel::VoxelWorld::fromRofiWorld( initWorld );
REQUIRE( initVoxelWorld );

auto goalWorld = RofiWorld();
auto & goalUm = goalWorld.insert( UniversalModule( 1, 0_deg, 0_deg, 0_deg ) );
connect< RigidJoint >( goalUm.connectors()[ 0 ], Vector{ 0, 0, 0 }, matrices::identity );
SECTION( "Move alpha" )
{
goalUm.setAlpha( GENERATE( 90_deg, -90_deg ) );
}
SECTION( "Move beta" )
{
goalUm.setBeta( GENERATE( 90_deg, -90_deg ) );
}
SECTION( "Move gamma" )
{
goalUm.setGamma( GENERATE( 90_deg, -90_deg ) );
}

REQUIRE( goalWorld.validate() );
auto goalVoxelWorld = rofi::voxel::VoxelWorld::fromRofiWorld( goalWorld );
REQUIRE( goalVoxelWorld );


auto result = rofi::voxel::voxel_reconfig( *initVoxelWorld, *goalVoxelWorld );
REQUIRE( result );

CHECK( result->size() == 1 );
}
}
12 changes: 12 additions & 0 deletions softwareComponents/rust-rofi_voxel/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn build_cpp_json_bindings() {
cxx_build::bridge("src/cpp_json_bindings.rs")
.shared_flag(true)
.out_dir(std::env::var_os("CXX_OUT_DIR").expect("CXX_OUT_DIR is not set"))
.compile("rofi_voxel_cpp_json_bindings");

println!("cargo:rerun-if-changed=src/cpp_json_bindings.rs");
}

fn main() {
build_cpp_json_bindings();
}
23 changes: 23 additions & 0 deletions softwareComponents/rust-rofi_voxel/src/cpp_json_bindings.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use crate::*;

#[cxx::bridge(namespace = "rofi::voxel")]
mod ffi {
extern "Rust" {
fn voxel_reconfiguration(init_json: &str, goal_json: &str) -> Result<Vec<String>>;
}
}

fn voxel_reconfiguration(init_json: &str, goal_json: &str) -> Result<Vec<String>, failure::Error> {
let init = serde_json::from_str::<serde::VoxelWorld>(init_json)?;
let goal = serde_json::from_str::<serde::VoxelWorld>(goal_json)?;

let (init, _min_pos) = init.to_world_and_min_pos()?;
let (goal, _min_pos) = goal.to_world_and_min_pos()?;

let reconfig_sequence = reconfiguration::compute_reconfiguration_moves(&init, goal)?;

Ok(reconfig_sequence
.iter()
.map(|world| serde_json::to_string(&serde::VoxelWorld::from_world(world)))
.collect::<Result<Vec<_>, _>>()?)
}
3 changes: 3 additions & 0 deletions softwareComponents/rust-rofi_voxel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ pub mod connectivity;
pub mod module_move;
pub mod module_repr;
pub mod reconfiguration;

#[cfg(feature = "cpp_json_bindings")]
mod cpp_json_bindings;