zekin_data_structure/
person.rs

1//! 程序的person模块, 用来储存和计算旅客的各种信息
2//!
3//! # examples
4//! ``` rust
5//! use std::rc::Rc;
6//! use data_structure::person::*;
7//! use data_structure::city::*;
8//! use data_structure::way::*;
9//!
10//! let mut city_0 = Rc::new(City::new(0, RiskLevel::Low));
11//! let city_1 = Rc::new(City::new(1, RiskLevel::Low));
12//!
13//! let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
14//!
15//! unsafe {
16//!     Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
17//! }
18//!
19//! let person = Person::new(city_0.clone(), city_1, 1, None);
20//! assert!(person.is_ok());
21//!
22//! let person = person.ok().unwrap();
23//! assert_eq!(person.statu, Status::Waiting(city_0));
24//! ```
25
26use crate::algorithm::*;
27use crate::city::*;
28use crate::err::ModuleErr;
29use crate::way::*;
30use getset::Getters;
31use std::rc::Rc;
32use wasm_bindgen::prelude::*;
33
34#[cfg(target_arch = "wasm32")]
35use js_sys::Array;
36
37/// 旅客当前的状态分类,一共有三种状态
38/// 1. Arrived(已到达)
39/// 2. Waiting (等待中)
40/// 3. Taking (乘坐交通工具中)
41#[derive(Debug, Clone, PartialEq, Eq)]
42pub enum Status {
43    /// 已到达
44    ///
45    /// * 其中值为已到达的城市
46    Arrived(Rc<City>),
47    /// 等待中
48    ///
49    /// * 其中值为等待中的城市
50    Waiting(Rc<City>),
51    /// 乘坐交通工具中
52    ///
53    /// * 其中值为正在乘坐的交通工具
54    Taking(Rc<Way>),
55}
56
57#[cfg(target_arch = "wasm32")]
58#[wasm_bindgen]
59#[derive(Debug, Copy, Clone, PartialEq, Eq)]
60pub enum StatusTsBinding {
61    Arrived,
62    Waiting,
63    Taking,
64}
65
66/// 旅客类, 表示旅客的各种基本信息
67#[wasm_bindgen]
68#[derive(Debug, Getters, Clone)]
69pub struct Person {
70    /// 返回旅客的当前状态
71    #[getset(get = "pub")]
72    statu: Status,
73
74    /// 返回旅客的起始城市
75    #[getset(get = "pub")]
76    start_city: Rc<City>,
77
78    /// 返回旅客的目的城市
79    #[getset(get = "pub")]
80    end_city: Rc<City>,
81
82    /// 返回旅客是否有时间限制
83    #[getset(get = "pub")]
84    time_limit: Option<i32>,
85
86    /// 返回旅客预计花费的总时间
87    #[getset(get = "pub")]
88    cost_time: i32,
89
90    /// 返回旅客的出发时间
91    #[getset(get = "pub")]
92    start_time: i32,
93
94    /// 返回旅客此次旅途的总风险
95    #[getset(get = "pub")]
96    total_risk: f64,
97
98    /// 返回旅客此次旅途的详细路程
99    #[getset(get = "pub")]
100    road: Vec<Rc<Way>>,
101}
102
103impl Person {
104    /// Person 的构造函数,创建一个新Person
105    /// # Arguments
106    /// * `start_city` - 旅客的起始城市
107    /// * `end_city` - 旅客的目的城市
108    /// * `start_time` - 旅客的出发时间
109    /// * `time_limit` - 旅客是否有时间限制
110    /// # Returns
111    /// * 一个Result, 程序会自动计算是否有可行的路径,如果有则返回乘客的信息,如果没有,则返回Err
112    pub fn new(
113        start_city: Rc<City>,
114        end_city: Rc<City>,
115        start_time: i32,
116        time_limit: Option<i32>,
117    ) -> Result<Person, ModuleErr> {
118        let r = calculate(start_city.clone(), end_city.clone(), start_time, time_limit)?;
119        Ok(Person {
120            start_city: start_city.clone(),
121            end_city,
122            time_limit,
123            start_time,
124            statu: Status::Waiting(start_city.clone()),
125
126            cost_time: r.end_time() - start_time,
127            total_risk: r.total_risk().clone(),
128            road: r.road().clone(),
129        })
130    }
131
132    /// Person 的移动函数
133    ///
134    /// Person将随所给的时间计算当前移动的进程, 并更新statu,如果Person已经处于Arrived状态,则不会再更新
135    pub fn step(&mut self, now_time: i32) {
136        match self.statu {
137            Status::Arrived(_) => return,
138            _ => {}
139        }
140        let mut pass_time = now_time - self.start_time;
141        let mut time = self.start_time;
142        for way in &self.road {
143            let waiting_time = calculate_time(&(time % 24), way.start_time());
144            if waiting_time > pass_time {
145                self.statu = Status::Waiting(way.start_city().clone());
146                return;
147            }
148            pass_time -= waiting_time;
149            if way.cost_time() > &pass_time {
150                self.statu = Status::Taking(way.clone());
151                return;
152            }
153            pass_time -= way.cost_time();
154            time += waiting_time + way.cost_time();
155        }
156        self.statu = Status::Arrived(self.end_city.clone());
157    }
158}
159
160#[cfg(target_arch = "wasm32")]
161#[wasm_bindgen]
162impl Person {
163    /// 返回旅客的当前状态
164    #[wasm_bindgen(getter = statu)]
165    pub fn get_status_ts_binding(&self) -> StatusTsBinding {
166        match self.statu {
167            Status::Arrived(_) => StatusTsBinding::Arrived,
168            Status::Taking(_) => StatusTsBinding::Taking,
169            Status::Waiting(_) => StatusTsBinding::Waiting,
170        }
171    }
172
173    /// 返回旅客的当前状态的值
174    #[wasm_bindgen(getter = statu_value)]
175    pub fn get_status_value_ts_binding(&self) -> JsValue {
176        match &self.statu {
177            Status::Arrived(a) => JsValue::from(unsafe { (*Rc::into_raw(a.clone())).clone() }),
178            Status::Taking(a) => JsValue::from(unsafe { (*Rc::into_raw(a.clone())).clone() }),
179            Status::Waiting(a) => JsValue::from(unsafe { (*Rc::into_raw(a.clone())).clone() }),
180        }
181    }
182
183    /// 返回旅客的起始城市
184    #[wasm_bindgen(getter = start_city)]
185    pub fn get_start_city_ts_binding(&self) -> City {
186        unsafe { (*Rc::into_raw(self.start_city.clone())).clone() }
187    }
188
189    /// 返回旅客的目的城市
190    #[wasm_bindgen(getter = end_city)]
191    pub fn get_end_city_ts_binding(&self) -> City {
192        unsafe { (*Rc::into_raw(self.end_city.clone())).clone() }
193    }
194
195    /// 返回旅客是否有时间限制
196    #[wasm_bindgen(getter = time_limit)]
197    pub fn get_time_limit_ts_binding(&self) -> Option<i32> {
198        self.time_limit
199    }
200
201    /// 返回旅客预计花费的总时间
202    #[wasm_bindgen(getter = cost_time)]
203    pub fn get_cost_time_ts_binding(&self) -> i32 {
204        self.cost_time
205    }
206
207    /// 返回旅客的出发时间
208    #[wasm_bindgen(getter = start_time)]
209    pub fn get_start_time_ts_binding(&self) -> i32 {
210        self.start_time
211    }
212
213    /// 返回旅客此次旅途的总风险
214    #[wasm_bindgen(getter = total_risk)]
215    pub fn get_total_risk_ts_binding(&self) -> f64 {
216        self.total_risk
217    }
218
219    /// 返回旅客此次旅途的详细路程
220    #[wasm_bindgen(getter = road)]
221    pub fn get_road_ts_binding(&self) -> Array {
222        unsafe {
223            self.road
224                .iter()
225                .map(|i| JsValue::from((*Rc::into_raw(i.clone())).clone()))
226                .collect()
227        }
228    }
229}
230
231#[cfg(test)]
232mod tests {
233    use super::*;
234    #[test]
235    fn calculate_time_from_up_to() {
236        assert_eq!(calculate_time(&20, &10), 14);
237    }
238
239    #[test]
240    fn calculate_time_from_down_to() {
241        assert_eq!(calculate_time(&10, &20), 10);
242    }
243    #[test]
244    fn new_person() {
245        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
246        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
247        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
248        unsafe {
249            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
250        }
251        let person = Person::new(city_0.clone(), city_1, 1, None);
252        assert!(person.is_ok());
253        let person = person.ok().unwrap();
254        assert_eq!(person.statu, Status::Waiting(city_0));
255    }
256
257    #[test]
258    fn step() {
259        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
260        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
261        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
262        unsafe {
263            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
264        }
265        let person = Person::new(city_0.clone(), city_1.clone(), 2, None);
266        assert!(person.is_ok());
267        let mut person = person.ok().unwrap();
268        assert_eq!(person.statu, Status::Waiting(city_0));
269        person.step(4);
270        assert_eq!(person.statu, Status::Taking(way_air.clone()));
271        person.step(7);
272        assert_eq!(person.statu, Status::Arrived(city_1));
273    }
274}
275
276#[cfg(target_arch = "wasm32")]
277#[cfg(test)]
278mod tests_ts_binding {
279    use super::*;
280    use wasm_bindgen_test::*;
281
282    #[wasm_bindgen_test]
283    fn get_status() {
284        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
285        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
286        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
287        unsafe {
288            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
289        }
290        let person = Person::new(city_0.clone(), city_1, 1, None);
291        assert!(person.is_ok());
292        let person = person.ok().unwrap();
293        assert_eq!(person.get_status_ts_binding(), StatusTsBinding::Waiting);
294    }
295
296    #[wasm_bindgen_test]
297    fn get_status_value() {
298        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
299        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
300        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
301        unsafe {
302            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
303        }
304        let person = Person::new(city_0.clone(), city_1, 1, None);
305        assert!(person.is_ok());
306        let person = person.ok().unwrap();
307        assert!(person.get_status_value_ts_binding().is_object())
308    }
309
310    #[wasm_bindgen_test]
311    fn get_time_limit_none() {
312        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
313        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
314        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
315        unsafe {
316            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
317        }
318        let person = Person::new(city_0.clone(), city_1, 1, None);
319        assert!(person.is_ok());
320        let person = person.ok().unwrap();
321        assert_eq!(person.get_time_limit_ts_binding(), person.time_limit);
322    }
323
324    #[wasm_bindgen_test]
325    fn get_time_limit_some() {
326        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
327        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
328        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
329        unsafe {
330            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
331        }
332        let person = Person::new(city_0.clone(), city_1, 1, Some(10));
333        assert!(person.is_ok());
334        let person = person.ok().unwrap();
335        assert_eq!(person.get_time_limit_ts_binding(), person.time_limit);
336    }
337
338    #[wasm_bindgen_test]
339    fn get_cost_time() {
340        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
341        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
342        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
343        unsafe {
344            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
345        }
346        let person = Person::new(city_0.clone(), city_1, 1, Some(10));
347        assert!(person.is_ok());
348        let person = person.ok().unwrap();
349        assert_eq!(person.get_cost_time_ts_binding(), person.cost_time);
350    }
351
352    #[wasm_bindgen_test]
353    fn get_start_city() {
354        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
355        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
356        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
357        unsafe {
358            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
359        }
360        let person = Person::new(city_0.clone(), city_1, 1, Some(10));
361        assert!(person.is_ok());
362        let person = person.ok().unwrap();
363        assert_eq!(
364            person.get_start_city_ts_binding().get_id_ts_binding(),
365            city_0.get_id_ts_binding()
366        );
367    }
368
369    #[wasm_bindgen_test]
370    fn get_end_city() {
371        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
372        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
373        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
374        unsafe {
375            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
376        }
377        let person = Person::new(city_0.clone(), city_1.clone(), 1, Some(10));
378        assert!(person.is_ok());
379        let person = person.ok().unwrap();
380        assert_eq!(
381            person.get_end_city_ts_binding().get_id_ts_binding(),
382            city_1.get_id_ts_binding()
383        );
384    }
385
386    #[wasm_bindgen_test]
387    fn get_start_time() {
388        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
389        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
390        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
391        unsafe {
392            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
393        }
394        let person = Person::new(city_0.clone(), city_1, 1, Some(10));
395        assert!(person.is_ok());
396        let person = person.ok().unwrap();
397        assert_eq!(person.get_start_time_ts_binding(), person.start_time);
398    }
399
400    #[wasm_bindgen_test]
401    fn get_total_risk() {
402        let mut city_0 = Rc::new(City::new(0, String::new(), RiskLevel::Low));
403        let city_1 = Rc::new(City::new(1, String::new(), RiskLevel::Low));
404        let way_air = Rc::new(Way::new(1, Type::Air, city_0.clone(), city_1.clone(), 3, 4));
405        unsafe {
406            Rc::get_mut_unchecked(&mut city_0).add_way(way_air.clone());
407        }
408        let person = Person::new(city_0.clone(), city_1, 1, Some(10));
409        assert!(person.is_ok());
410        let person = person.ok().unwrap();
411        assert_eq!(person.get_total_risk_ts_binding(), person.total_risk);
412    }
413}