pathfinding/
lib.rs

1use crate::map::{IndexType, MapManager};
2use tokio::runtime::{Runtime, Builder};
3use std::os::raw::c_char;
4use std::sync::{Once};
5
6pub mod astar;
7pub mod errors;
8pub mod id;
9pub mod map;
10pub mod rmacro;
11
12#[repr(C)] // 指定结构体的布局方式为C语言兼容的方式
13pub struct CPoint {
14    pub x: i32,
15    pub y: i32,
16}
17
18#[repr(C)]
19pub struct CPointArray {
20    length: usize,
21    data: *const (i32,i32),
22    cap: usize,
23}
24
25static TOKIO_RUNTIME_INIT: Once = Once::new();
26static mut TOKIO_RUNTIME: Option<Runtime> = None;
27
28//修改static mut的操作再call_once中是安全的,所以使用unsafe包裹即可
29pub fn init_tokio_runtime(worker_threads: usize) {
30    TOKIO_RUNTIME_INIT.call_once(|| {
31        unsafe {
32            TOKIO_RUNTIME = Some(
33                Builder::new_multi_thread()
34                    .worker_threads(worker_threads)
35                    .build()
36                    .unwrap()
37            );
38        }
39    });
40}
41
42pub fn get_tokio_runtime() -> &'static Runtime {
43    unsafe {
44        TOKIO_RUNTIME.as_ref().unwrap()
45    }
46}
47
48//初始化tokio的runtime
49#[no_mangle]
50pub extern "C" fn init_runtime(worker_threads: usize) {
51    init_tokio_runtime(worker_threads);
52}
53
54#[no_mangle]
55pub extern "C" fn find_path(map_id:i64, start_point:&CPoint, end_point:&CPoint) -> CPointArray {
56    get_tokio_runtime().block_on(async {
57        find(map_id, start_point, end_point).await
58    })
59}
60
61#[no_mangle]
62pub extern "C" fn set_walkable(map_id:i64, point:&CPoint, walkable:i32) -> bool {
63    get_tokio_runtime().block_on(async {
64        set_walkable_impl(map_id, point, walkable).await
65    })
66}
67
68#[allow(clippy::not_unsafe_ptr_arg_deref)]
69#[no_mangle]
70pub extern "C" fn load_map(c_string: *const c_char) -> i64 {
71    let map_file = unsafe { std::ffi::CStr::from_ptr(c_string) };
72    get_tokio_runtime().block_on(async {
73        load_map_from_file(map_file.to_string_lossy().into_owned()).await
74    })
75}
76
77#[allow(clippy::not_unsafe_ptr_arg_deref)]
78#[no_mangle]
79pub extern "C" fn load_map_from_string(file_content: *const c_char) -> i64 {
80    let map_file_content = unsafe { std::ffi::CStr::from_ptr(file_content) };
81    get_tokio_runtime().block_on(async {
82        load_map_from_file_content(map_file_content.to_string_lossy().into_owned()).await
83    })
84}
85
86#[no_mangle]
87pub extern "C" fn free_path(path: CPointArray) {
88    free_array(path);
89}
90
91async fn load_map_from_file(map_file: String) -> i64 {
92    let map = MapManager::get_instance();
93
94    //获取写锁与创建新地图
95    let map_id = map.write().await.new_astar().await;
96
97    let _ = match map.read().await.load_from_file(&map_id, map_file.to_string()).await {
98        Ok(_) => map_id,
99        Err(err) => {println!("{}", err);0}
100    }; map_id
101}
102
103async fn load_map_from_file_content(file_content: String) -> i64 {
104    let map = MapManager::get_instance();
105
106    //获取写锁
107    let map_id = map.write().await.new_astar().await;
108
109    let _ = match map.read().await.load_from_string(&map_id, file_content).await {
110        Ok(_) => map_id,
111        Err(err) => {println!("{}", err);0}
112    }; map_id
113}
114
115async fn find(map_id:i64, start_point:&CPoint, end_point:&CPoint) -> CPointArray {
116    let map = MapManager::get_instance();
117
118    //获取读锁
119    let result = map.read().await.find_path(&map_id,(start_point.x, start_point.y), (end_point.x, end_point.y)).await;
120
121    match result {
122        Ok(v) => convert_to_c_array(v),
123        Err(_e) => CPointArray{ data: &(0, 0), length: 0, cap: 0 },
124    }
125}
126
127async fn set_walkable_impl(map_id:i64, point:&CPoint, walkable:i32) -> bool {
128    let map = MapManager::get_instance();
129    //获取写锁
130    let result = map.write().await.set_walkable(&map_id, (point.x, point.y), walkable).await;
131    result.is_ok()
132}
133
134fn convert_to_c_array(mut vec: Vec<(IndexType, IndexType)>) -> CPointArray {
135    let ptr = vec.as_mut_ptr();
136    let len = vec.len();
137    let cap = vec.capacity();
138
139    // 避免 Rust 销毁 vec
140    std::mem::forget(vec);
141
142    CPointArray {
143        data: ptr,
144        length: len,
145        cap
146    }
147}
148
149fn free_array(vec:CPointArray) {
150    let xx:Vec<(IndexType, IndexType)> = unsafe { Vec::from_raw_parts(vec.data as *mut (IndexType, IndexType), vec.length, vec.cap) };
151    drop(xx);
152}