From b69d5361f152aa18dddeaf370a896a1148b7d880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Svoboda?= Date: Thu, 1 Dec 2022 15:07:30 +0100 Subject: [PATCH] WIP: Add cxx --- .../rust-rofi_voxel/CMakeLists.txt | 15 ++++- softwareComponents/rust-rofi_voxel/Cargo.toml | 14 ++++ .../binding_include/voxel_reconfig.hpp | 12 ++++ .../binding_src/voxel_reconfig_binding.cpp | 52 +++++++++++++++ .../binding_test/voxel_reconfig.cpp | 66 +++++++++++++++++++ softwareComponents/rust-rofi_voxel/build.rs | 12 ++++ .../rust-rofi_voxel/src/cpp_json_bindings.rs | 23 +++++++ softwareComponents/rust-rofi_voxel/src/lib.rs | 3 + 8 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 softwareComponents/rust-rofi_voxel/binding_include/voxel_reconfig.hpp create mode 100644 softwareComponents/rust-rofi_voxel/binding_src/voxel_reconfig_binding.cpp create mode 100644 softwareComponents/rust-rofi_voxel/binding_test/voxel_reconfig.cpp create mode 100644 softwareComponents/rust-rofi_voxel/build.rs create mode 100644 softwareComponents/rust-rofi_voxel/src/cpp_json_bindings.rs diff --git a/softwareComponents/rust-rofi_voxel/CMakeLists.txt b/softwareComponents/rust-rofi_voxel/CMakeLists.txt index d4c7266a8..6bdd9977e 100644 --- a/softwareComponents/rust-rofi_voxel/CMakeLists.txt +++ b/softwareComponents/rust-rofi_voxel/CMakeLists.txt @@ -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) diff --git a/softwareComponents/rust-rofi_voxel/Cargo.toml b/softwareComponents/rust-rofi_voxel/Cargo.toml index 96e6d59c4..0c77717a9 100644 --- a/softwareComponents/rust-rofi_voxel/Cargo.toml +++ b/softwareComponents/rust-rofi_voxel/Cargo.toml @@ -1,11 +1,18 @@ [package] name = "rofi_voxel" version = "0.1.0" +authors = [ "Ondřej Svoboda " ] 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" @@ -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 } diff --git a/softwareComponents/rust-rofi_voxel/binding_include/voxel_reconfig.hpp b/softwareComponents/rust-rofi_voxel/binding_include/voxel_reconfig.hpp new file mode 100644 index 000000000..1177e8743 --- /dev/null +++ b/softwareComponents/rust-rofi_voxel/binding_include/voxel_reconfig.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +#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 > >; +} diff --git a/softwareComponents/rust-rofi_voxel/binding_src/voxel_reconfig_binding.cpp b/softwareComponents/rust-rofi_voxel/binding_src/voxel_reconfig_binding.cpp new file mode 100644 index 000000000..286c60531 --- /dev/null +++ b/softwareComponents/rust-rofi_voxel/binding_src/voxel_reconfig_binding.cpp @@ -0,0 +1,52 @@ +#include "voxel_reconfig.hpp" + +#include +#include + +#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 diff --git a/softwareComponents/rust-rofi_voxel/binding_test/voxel_reconfig.cpp b/softwareComponents/rust-rofi_voxel/binding_test/voxel_reconfig.cpp new file mode 100644 index 000000000..746c1c892 --- /dev/null +++ b/softwareComponents/rust-rofi_voxel/binding_test/voxel_reconfig.cpp @@ -0,0 +1,66 @@ +#include "voxel_reconfig.hpp" + +#include + +#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 ); + } +} diff --git a/softwareComponents/rust-rofi_voxel/build.rs b/softwareComponents/rust-rofi_voxel/build.rs new file mode 100644 index 000000000..0f94dda34 --- /dev/null +++ b/softwareComponents/rust-rofi_voxel/build.rs @@ -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(); +} diff --git a/softwareComponents/rust-rofi_voxel/src/cpp_json_bindings.rs b/softwareComponents/rust-rofi_voxel/src/cpp_json_bindings.rs new file mode 100644 index 000000000..c710a5c11 --- /dev/null +++ b/softwareComponents/rust-rofi_voxel/src/cpp_json_bindings.rs @@ -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>; + } +} + +fn voxel_reconfiguration(init_json: &str, goal_json: &str) -> Result, failure::Error> { + let init = serde_json::from_str::(init_json)?; + let goal = serde_json::from_str::(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::, _>>()?) +} diff --git a/softwareComponents/rust-rofi_voxel/src/lib.rs b/softwareComponents/rust-rofi_voxel/src/lib.rs index af449f61e..78605c4e7 100644 --- a/softwareComponents/rust-rofi_voxel/src/lib.rs +++ b/softwareComponents/rust-rofi_voxel/src/lib.rs @@ -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;