diff --git a/src/core_ffi/rust_ffi/adapter/common_code.cc b/src/core_ffi/rust_ffi/adapter/common_code.cc index 553c352..dfe4343 100644 --- a/src/core_ffi/rust_ffi/adapter/common_code.cc +++ b/src/core_ffi/rust_ffi/adapter/common_code.cc @@ -1,15 +1,68 @@ #include "rust_ffi/include/common_code.h" +#include #include +using klotski::codec::RawCode; +using klotski::codec::ShortCode; +using klotski::codec::CommonCode; + +using klotski::mover::MaskMover; + +using klotski::ffi::RsShortCode; using klotski::ffi::RsCommonCode; +// TODO: it seems that cxx.rs not support `std::optional` +uint64_t klotski::ffi::common_code_from_str(rust::Str s) { + std::string_view sv {s.data(), s.length()}; + if (const auto ret = CommonCode::from_string(sv); ret.has_value()) { + return ret.value().unwrap(); + } + return 0x10FFFFFFFF; // return invalid value for now +} + +bool klotski::ffi::common_code_check(uint64_t val) { + return CommonCode::check(val); +} + rust::String RsCommonCode::to_string() const noexcept { - return codec::CommonCode::unsafe_create(code).to_string(); + return CommonCode::unsafe_create(code).to_string(); } -// TODO: it seems that cxx.rs not support `std::optional` -RsCommonCode klotski::ffi::from_string(rust::Str s) { - std::string_view sv {s.data(), s.length()}; - return {codec::CommonCode::from_string(sv)->unwrap()}; // TODO: value check +rust::String RsCommonCode::to_shorten_string() const noexcept { + return CommonCode::unsafe_create(code).to_string(true); +} + +RsShortCode RsCommonCode::to_short_code() const noexcept { + return {CommonCode::unsafe_create(code).to_short_code().unwrap()}; +} + +bool RsCommonCode::is_vertical_mirror() const noexcept { + return CommonCode::unsafe_create(code).is_vertical_mirror(); +} + +bool RsCommonCode::is_horizontal_mirror() const noexcept { + return CommonCode::unsafe_create(code).is_horizontal_mirror(); +} + +RsCommonCode RsCommonCode::to_vertical_mirror() const noexcept { + return {CommonCode::unsafe_create(code).to_vertical_mirror().unwrap()}; +} + +RsCommonCode RsCommonCode::to_horizontal_mirror() const noexcept { + return {CommonCode::unsafe_create(code).to_horizontal_mirror().unwrap()}; +} + +rust::Vec RsCommonCode::next_cases() const noexcept { + std::vector result; + auto mover = MaskMover([&result](const RawCode code, uint64_t) { + result.emplace_back(code.to_common_code()); + }); + mover.next_cases(CommonCode::unsafe_create(code).to_raw_code(), 0); + + rust::Vec vec; + for (auto x : result) { + vec.emplace_back(RsCommonCode(x.unwrap())); + } + return vec; } diff --git a/src/core_ffi/rust_ffi/build.rs b/src/core_ffi/rust_ffi/build.rs index 0741961..1931ac0 100644 --- a/src/core_ffi/rust_ffi/build.rs +++ b/src/core_ffi/rust_ffi/build.rs @@ -5,10 +5,12 @@ use cxx_build::CFG; // NOTE: add `CC=clang-20 CXX=clang++-20 CXXFLAGS="-stdlib=libc++"` for cargo command // we should keep cxx crate using clang for `cxx.cc` -// NOTE: also, `RUSTFLAGS="-C linker=clang-20"` should be add to cargo env for using lld +// NOTE: also, `RUSTFLAGS="-C linker=clang-20"` should be added to cargo env for using lld // NOTE: add `CC=clang-20 CXX=clang++-20 CXXFLAGS="-stdlib=libc++" RUSTFLAGS="-C linker=clang-20 -C link-arg=-fuse-ld=lld-20 -C link-arg=-stdlib=libc++"` for using llvm toolchain +// NOTE: it seems that cxx_build link `libstdc++` on linux, we can add `-C link-arg=-lc++ -C link-arg=-lc++abi` for workaround, but it should be fixed in the future. + fn main() { let dst = cmake::Config::new("klotski") // .build_target("klotski_core") diff --git a/src/core_ffi/rust_ffi/include/common_code.h b/src/core_ffi/rust_ffi/include/common_code.h index c40e175..4a004c2 100644 --- a/src/core_ffi/rust_ffi/include/common_code.h +++ b/src/core_ffi/rust_ffi/include/common_code.h @@ -4,6 +4,8 @@ namespace klotski::ffi { -RsCommonCode from_string(rust::Str s); +bool common_code_check(uint64_t val); + +uint64_t common_code_from_str(rust::Str s); } // namespace klotski::ffi diff --git a/src/core_ffi/rust_ffi/src/common_code.rs b/src/core_ffi/rust_ffi/src/common_code.rs index b454f35..3434876 100644 --- a/src/core_ffi/rust_ffi/src/common_code.rs +++ b/src/core_ffi/rust_ffi/src/common_code.rs @@ -2,31 +2,91 @@ mod ffi { #[derive(Debug)] struct RsCommonCode { - code: u64 + code: u64, + } + + #[derive(Debug)] + struct RsShortCode { + code: u32, } unsafe extern "C++" { include!("rust_ffi/include/common_code.h"); + /// only for internal use + fn common_code_check(val: u64) -> bool; + + /// only for internal use + fn common_code_from_str(s: &str) -> u64; + + /// Convert CommonCode to string form. fn to_string(self: &RsCommonCode) -> String; - fn from_string(s: &str) -> RsCommonCode; + /// Convert CommonCode to shorten string form. + fn to_shorten_string(self: &RsCommonCode) -> String; + + /// Convert CommonCode to ShortCode. + fn to_short_code(self: &RsCommonCode) -> RsShortCode; + + /// Whether the layout is vertically symmetrical. + fn is_vertical_mirror(self: &RsCommonCode) -> bool; + + /// Whether the layout is horizontally symmetrical. + fn is_horizontal_mirror(self: &RsCommonCode) -> bool; + + /// Calculate the vertically symmetrical klotski layout. + fn to_vertical_mirror(self: &RsCommonCode) -> RsCommonCode; + + /// Calculate the horizontally symmetrical klotski layout. + fn to_horizontal_mirror(self: &RsCommonCode) -> RsCommonCode; + + /// Obtain all next cases in CommonCode. + fn next_cases(self: &RsCommonCode) -> Vec; + } + + unsafe extern "C++" { + // include!("rust_ffi/include/short_code.h"); + + // fn short_code_from_str(s: &str) -> RsShortCode; + + // TODO: speed_up interface } } +pub use ffi::RsShortCode as ShortCode; pub use ffi::RsCommonCode as CommonCode; impl CommonCode { + /// Check the validity of the original CommonCode. + pub fn check(code: u64) -> bool { + ffi::common_code_check(code) + } + + /// Create CommonCode without any check. pub fn unsafe_create(code: u64) -> CommonCode { CommonCode { code } } + /// Create CommonCode with validity check. + pub fn create(code: u64) -> Option { + if Self::check(code) { + return Some(Self::unsafe_create(code)); + } + None + } + + /// Get the original u64 code. pub fn unwrap(self: &CommonCode) -> u64 { self.code } - pub fn from_string(s: &str) -> CommonCode { - ffi::from_string(s) + /// Create CommonCode from string form. + pub fn from_string(s: &str) -> Option { + let val = ffi::common_code_from_str(s); + if val < 0x10_FFFF_FFFF { + return Some(Self::unsafe_create(val)); + } + None } } @@ -35,3 +95,9 @@ impl PartialEq for CommonCode { self.code == other.code } } + +impl PartialEq for ShortCode { + fn eq(&self, other: &Self) -> bool { + self.code == other.code + } +} diff --git a/src/core_ffi/rust_ffi/src/main.rs b/src/core_ffi/rust_ffi/src/main.rs index 8222a48..09d6a14 100644 --- a/src/core_ffi/rust_ffi/src/main.rs +++ b/src/core_ffi/rust_ffi/src/main.rs @@ -3,9 +3,23 @@ mod common_code; use common_code::CommonCode; fn main() { - let code = CommonCode::from_string("1A9BF0C"); + assert!(CommonCode::check(0x1A9BF0C00)); + let code = CommonCode::create(0x1A9BF0C00).unwrap(); + assert_eq!(code, CommonCode::from_string("1A9BF0C").unwrap()); + assert_eq!(code, CommonCode::create(0x1A9BF0C00).unwrap()); + println!("code: {:?}", code.unwrap()); - println!("str: {}", code.to_string()); - println!("{}", code == CommonCode::unsafe_create(0x1A9BF0C00)); + println!("string: {}", code.to_string()); + println!("shorten_string: {}", code.to_shorten_string()); + + println!("short_code: {:?}", code.to_short_code()); + + println!("is_vertical_mirror: {}", code.is_vertical_mirror()); + println!("is_horizontal_mirror: {}", code.is_horizontal_mirror()); + + println!("vertical_mirror: {:?}", code.to_vertical_mirror()); + println!("horizontal_mirror: {:?}", code.to_horizontal_mirror()); + + println!("next_cases: {:?}", code.next_cases()); }