1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use crate::map::{IndexType, MapManager};
use tokio::runtime::{Runtime, Builder};
use std::os::raw::c_char;
use std::sync::{Once};

pub mod astar;
pub mod errors;
pub mod id;
pub mod map;
pub mod rmacro;

#[repr(C)] // 指定结构体的布局方式为C语言兼容的方式
pub struct CPoint {
    pub x: i32,
    pub y: i32,
}

#[repr(C)]
pub struct CPointArray {
    length: usize,
    data: *const (i32,i32),
    cap: usize,
}

static TOKIO_RUNTIME_INIT: Once = Once::new();
static mut TOKIO_RUNTIME: Option<Runtime> = None;

//修改static mut的操作再call_once中是安全的,所以使用unsafe包裹即可
pub fn init_tokio_runtime(worker_threads: usize) {
    TOKIO_RUNTIME_INIT.call_once(|| {
        unsafe {
            TOKIO_RUNTIME = Some(
                Builder::new_multi_thread()
                    .worker_threads(worker_threads)
                    .build()
                    .unwrap()
            );
        }
    });
}

pub fn get_tokio_runtime() -> &'static Runtime {
    unsafe {
        TOKIO_RUNTIME.as_ref().unwrap()
    }
}

//初始化tokio的runtime
#[no_mangle]
pub extern "C" fn init_runtime(worker_threads: usize) {
    init_tokio_runtime(worker_threads);
}

#[no_mangle]
pub extern "C" fn find_path(map_id:i64, start_point:&CPoint, end_point:&CPoint) -> CPointArray {
    return get_tokio_runtime().block_on(async {
        find(map_id, start_point, end_point).await
    });
}

#[no_mangle]
pub extern "C" fn set_walkable(map_id:i64, point:&CPoint, walkable:i32) -> bool {
    return get_tokio_runtime().block_on(async {
        set_walkable_impl(map_id, point, walkable).await
    });
}

#[no_mangle]
pub extern "C" fn load_map(c_string: *const c_char) -> i64 {
    return get_tokio_runtime().block_on(async {
        let map_file = unsafe { std::ffi::CStr::from_ptr(c_string) };
        load_map_from_file(map_file.to_string_lossy().into_owned()).await
    });
}

#[no_mangle]
pub extern "C" fn load_map_from_string(file_content: *const c_char) -> i64 {
    return get_tokio_runtime().block_on(async {
        let map_file_content = unsafe { std::ffi::CStr::from_ptr(file_content) };
        load_map_from_file_content(map_file_content.to_string_lossy().into_owned()).await
    });
}

#[no_mangle]
pub extern "C" fn free_path(path: CPointArray) {
    free_array(path);
}

async fn load_map_from_file(map_file: String) -> i64 {
    let map = MapManager::get_instance();

    //获取写锁与创建新地图
    let map_id = match map.write() {
        Ok(mut write_lock) => write_lock.new_astar().await,
        Err(err) => {println!("{}", err); return 0}
    };

    //获取读锁
    return match map.read() {
        Ok(read_lock) => {
            match read_lock.load_from_file(&map_id, map_file.to_string()).await {
                Ok(_) => map_id,

                Err(err) => {println!("{}", err);0}
            }
        },
        Err(err) => {println!("{}", err);0}
    };
}

async fn load_map_from_file_content(file_content: String) -> i64 {
    let map = MapManager::get_instance();

    //获取写锁
    let map_id = match map.write() {
        Ok(mut write_lock) => write_lock.new_astar().await,
        Err(err) => {println!("{}", err); return 0}
    };

    //获取读锁
    return match map.read() {
        Ok(read_lock) => {
            match read_lock.load_from_string(&map_id, file_content).await {
                Ok(_) => map_id,
                Err(err) => {println!("{}", err);0}
            }
        },
        Err(err) => {println!("{}", err);0}
    };
}

async fn find(map_id:i64, start_point:&CPoint, end_point:&CPoint) -> CPointArray {
    let map = MapManager::get_instance();

    //获取读锁
    let result = match map.read() {
        Ok(read_lock) => read_lock.find_path(&map_id,(start_point.x, start_point.y), (end_point.x, end_point.y)),
        Err(err) => {println!("{}", err); return CPointArray{ data: &(0, 0), length: 0, cap: 0 }}
    };

    match result {
        Ok(v) => convert_to_c_array(v),
        Err(_e) => CPointArray{ data: &(0, 0), length: 0, cap: 0 },
    }
}

async fn set_walkable_impl(map_id:i64, point:&CPoint, walkable:i32) -> bool {
    let map = MapManager::get_instance();

    //获取写锁
    return match map.write() {
        Ok(write_lock) => write_lock.set_walkable(&map_id, (point.x, point.y), walkable),
        Err(err) => {println!("{}", err); return false}
    }.is_ok();
}

fn convert_to_c_array(mut vec: Vec<(IndexType, IndexType)>) -> CPointArray {
    let ptr = vec.as_mut_ptr();
    let len = vec.len();
    let cap = vec.capacity();

    // 避免 Rust 销毁 vec
    std::mem::forget(vec);

    CPointArray {
        data: ptr,
        length: len,
        cap
    }
}

fn free_array(vec:CPointArray) {
    let xx:Vec<(IndexType, IndexType)> = unsafe { Vec::from_raw_parts(vec.data as *mut (IndexType, IndexType), vec.length, vec.cap) };
    drop(xx);
}