|
1 | | -use pyo3::exceptions::PyValueError; |
2 | | -use pyo3::prelude::*; |
| 1 | +use pyo3::pymodule; |
3 | 2 |
|
4 | | -struct DecodingResult { |
5 | | - value: i64, |
6 | | - offset: u32, |
7 | | -} |
| 3 | +#[pymodule] |
| 4 | +mod gps_data_codec { |
| 5 | + use pyo3::exceptions::PyValueError; |
| 6 | + use pyo3::prelude::*; |
8 | 7 |
|
9 | | -fn decode_unsigned_value_from_string(encoded: &[u8], offset: u32) -> DecodingResult { |
10 | | - let mut value: i64 = 0; |
11 | | - let mut consumed: u32 = 0; |
12 | | - let mut byte: u8 = 0; |
13 | | - while consumed == 0 || byte >= 0x20 { |
14 | | - byte = encoded[(consumed + offset) as usize] - 63; |
15 | | - value |= ((byte & 0x1f) as i64) << (consumed * 5); |
16 | | - consumed += 1; |
| 8 | + struct DecodingResult { |
| 9 | + value: i64, |
| 10 | + offset: u32, |
17 | 11 | } |
18 | | - DecodingResult { |
19 | | - value, |
20 | | - offset: offset + consumed, |
21 | | - } |
22 | | -} |
23 | 12 |
|
24 | | -fn decode_signed_value_from_string(encoded: &[u8], offset: u32) -> DecodingResult { |
25 | | - let tmp_result: DecodingResult = decode_unsigned_value_from_string(encoded, offset); |
26 | | - let tmp_value: i64 = tmp_result.value; |
27 | | - if tmp_value & 1 == 1 { |
28 | | - DecodingResult { |
29 | | - value: !(tmp_value >> 1), |
30 | | - offset: tmp_result.offset, |
| 13 | + fn decode_unsigned_value_from_string(encoded: &[u8], offset: u32) -> DecodingResult { |
| 14 | + let mut value: i64 = 0; |
| 15 | + let mut consumed: u32 = 0; |
| 16 | + let mut byte: u8 = 0; |
| 17 | + while consumed == 0 || byte >= 0x20 { |
| 18 | + byte = encoded[(consumed + offset) as usize] - 63; |
| 19 | + value |= ((byte & 0x1f) as i64) << (consumed * 5); |
| 20 | + consumed += 1; |
31 | 21 | } |
32 | | - } else { |
33 | 22 | DecodingResult { |
34 | | - value: tmp_value >> 1, |
35 | | - offset: tmp_result.offset, |
| 23 | + value, |
| 24 | + offset: offset + consumed, |
36 | 25 | } |
37 | 26 | } |
38 | | -} |
39 | 27 |
|
40 | | -fn encode_unsigned_number(num: u64) -> Vec<u8> { |
41 | | - let mut encoded: Vec<u8> = vec![]; |
42 | | - let mut tmp: u64 = num; |
43 | | - while tmp >= 0x20 { |
44 | | - encoded.push((0x20 | (tmp as u8 & 0x1f)) + 63); |
45 | | - tmp >>= 5; |
| 28 | + fn decode_signed_value_from_string(encoded: &[u8], offset: u32) -> DecodingResult { |
| 29 | + let tmp_result: DecodingResult = decode_unsigned_value_from_string(encoded, offset); |
| 30 | + let tmp_value: i64 = tmp_result.value; |
| 31 | + if tmp_value & 1 == 1 { |
| 32 | + DecodingResult { |
| 33 | + value: !(tmp_value >> 1), |
| 34 | + offset: tmp_result.offset, |
| 35 | + } |
| 36 | + } else { |
| 37 | + DecodingResult { |
| 38 | + value: tmp_value >> 1, |
| 39 | + offset: tmp_result.offset, |
| 40 | + } |
| 41 | + } |
46 | 42 | } |
47 | | - encoded.push(tmp as u8 + 63); |
48 | | - encoded |
49 | | -} |
50 | 43 |
|
51 | | -fn encode_signed_number(num: i64) -> Vec<u8> { |
52 | | - let mut sgn_num: i64 = num << 1; |
53 | | - if num < 0 { |
54 | | - sgn_num = !sgn_num; |
| 44 | + fn encode_unsigned_number(num: u64) -> Vec<u8> { |
| 45 | + let mut encoded: Vec<u8> = vec![]; |
| 46 | + let mut tmp: u64 = num; |
| 47 | + while tmp >= 0x20 { |
| 48 | + encoded.push((0x20 | (tmp as u8 & 0x1f)) + 63); |
| 49 | + tmp >>= 5; |
| 50 | + } |
| 51 | + encoded.push(tmp as u8 + 63); |
| 52 | + encoded |
55 | 53 | } |
56 | | - let unsigned_num = sgn_num as u64; |
57 | | - encode_unsigned_number(unsigned_num) |
58 | | -} |
59 | 54 |
|
60 | | -const YEAR2010: i64 = 1262304000; |
| 55 | + fn encode_signed_number(num: i64) -> Vec<u8> { |
| 56 | + let mut sgn_num: i64 = num << 1; |
| 57 | + if num < 0 { |
| 58 | + sgn_num = !sgn_num; |
| 59 | + } |
| 60 | + let unsigned_num = sgn_num as u64; |
| 61 | + encode_unsigned_number(unsigned_num) |
| 62 | + } |
61 | 63 |
|
62 | | -#[pyfunction] |
63 | | -fn decode(input: String) -> PyResult<Vec<(i64, f64, f64)>> { |
64 | | - let mut vals: [i64; 3] = [YEAR2010, 0, 0]; |
65 | | - let mut bytes_consumed: u32 = 0; |
66 | | - let mut decoding_result: DecodingResult; |
67 | | - let encoded: &[u8] = input.as_bytes(); |
68 | | - let encoded_length: u32 = encoded.len() as u32; |
69 | | - let mut output: Vec<(i64, f64, f64)> = Vec::new(); |
| 64 | + const YEAR2010: i64 = 1262304000; |
70 | 65 |
|
71 | | - while bytes_consumed < encoded_length { |
72 | | - for (i, val) in vals.iter_mut().enumerate() { |
73 | | - if i == 0 && bytes_consumed != 0 { |
74 | | - decoding_result = decode_unsigned_value_from_string(encoded, bytes_consumed); |
75 | | - } else { |
76 | | - decoding_result = decode_signed_value_from_string(encoded, bytes_consumed); |
| 66 | + #[pyfunction] |
| 67 | + fn decode(input: String) -> PyResult<Vec<(i64, f64, f64)>> { |
| 68 | + let mut vals: [i64; 3] = [YEAR2010, 0, 0]; |
| 69 | + let mut bytes_consumed: u32 = 0; |
| 70 | + let mut decoding_result: DecodingResult; |
| 71 | + let encoded: &[u8] = input.as_bytes(); |
| 72 | + let encoded_length: u32 = encoded.len() as u32; |
| 73 | + let mut output: Vec<(i64, f64, f64)> = Vec::new(); |
| 74 | + |
| 75 | + while bytes_consumed < encoded_length { |
| 76 | + for (i, val) in vals.iter_mut().enumerate() { |
| 77 | + if i == 0 && bytes_consumed != 0 { |
| 78 | + decoding_result = decode_unsigned_value_from_string(encoded, bytes_consumed); |
| 79 | + } else { |
| 80 | + decoding_result = decode_signed_value_from_string(encoded, bytes_consumed); |
| 81 | + } |
| 82 | + bytes_consumed = decoding_result.offset; |
| 83 | + *val += decoding_result.value; |
77 | 84 | } |
78 | | - bytes_consumed = decoding_result.offset; |
79 | | - *val += decoding_result.value; |
| 85 | + output.push((vals[0], (vals[1] as f64) / 1e5, (vals[2] as f64) / 1e5)); |
80 | 86 | } |
81 | | - output.push((vals[0], (vals[1] as f64) / 1e5, (vals[2] as f64) / 1e5)); |
| 87 | + Ok(output) |
82 | 88 | } |
83 | | - Ok(output) |
84 | | -} |
85 | 89 |
|
86 | | -#[pyfunction] |
87 | | -fn encode(data: Vec<(f64, f64, f64)>) -> PyResult<String> { |
88 | | - let mut prev_timestamp: i64 = YEAR2010; |
89 | | - let mut prev_latitude: f64 = 0.0; |
90 | | - let mut prev_longitude: f64 = 0.0; |
| 90 | + #[pyfunction] |
| 91 | + fn encode(data: Vec<(f64, f64, f64)>) -> PyResult<String> { |
| 92 | + let mut prev_timestamp: i64 = YEAR2010; |
| 93 | + let mut prev_latitude: f64 = 0.0; |
| 94 | + let mut prev_longitude: f64 = 0.0; |
91 | 95 |
|
92 | | - let mut output: Vec<u8> = vec![]; |
93 | | - let mut is_first: bool = true; |
94 | | - for point_object in data.iter() { |
95 | | - let point_data = point_object; |
96 | | - let timestamp = point_data.0.round() as i64; |
97 | | - let timestamp_diff = timestamp - prev_timestamp; |
98 | | - if is_first { |
99 | | - output.append(&mut encode_signed_number(timestamp_diff)); |
100 | | - is_first = false; |
101 | | - } else { |
102 | | - if timestamp < prev_timestamp { |
103 | | - return Err(PyValueError::new_err("Input data is not sorted")); |
| 96 | + let mut output: Vec<u8> = vec![]; |
| 97 | + let mut is_first: bool = true; |
| 98 | + for point_object in data.iter() { |
| 99 | + let point_data = point_object; |
| 100 | + let timestamp = point_data.0.round() as i64; |
| 101 | + let timestamp_diff = timestamp - prev_timestamp; |
| 102 | + if is_first { |
| 103 | + output.append(&mut encode_signed_number(timestamp_diff)); |
| 104 | + is_first = false; |
| 105 | + } else { |
| 106 | + if timestamp < prev_timestamp { |
| 107 | + return Err(PyValueError::new_err("Input data is not sorted")); |
| 108 | + } |
| 109 | + output.append(&mut encode_unsigned_number(timestamp_diff as u64)); |
104 | 110 | } |
105 | | - output.append(&mut encode_unsigned_number(timestamp_diff as u64)); |
106 | | - } |
107 | 111 |
|
108 | | - let latitude: f64 = point_data.1; |
109 | | - let latitude_diff: i64 = ((latitude - prev_latitude) * 1e5).round() as i64; |
110 | | - output.append(&mut encode_signed_number(latitude_diff)); |
| 112 | + let latitude: f64 = point_data.1; |
| 113 | + let latitude_diff: i64 = ((latitude - prev_latitude) * 1e5).round() as i64; |
| 114 | + output.append(&mut encode_signed_number(latitude_diff)); |
111 | 115 |
|
112 | | - let longitude: f64 = point_data.2; |
113 | | - let longitude_diff: i64 = ((longitude - prev_longitude) * 1e5).round() as i64; |
114 | | - output.append(&mut encode_signed_number(longitude_diff)); |
| 116 | + let longitude: f64 = point_data.2; |
| 117 | + let longitude_diff: i64 = ((longitude - prev_longitude) * 1e5).round() as i64; |
| 118 | + output.append(&mut encode_signed_number(longitude_diff)); |
115 | 119 |
|
116 | | - prev_timestamp += timestamp_diff; |
117 | | - prev_latitude += (latitude_diff as f64) / 1e5; |
118 | | - prev_longitude += (longitude_diff as f64) / 1e5; |
| 120 | + prev_timestamp += timestamp_diff; |
| 121 | + prev_latitude += (latitude_diff as f64) / 1e5; |
| 122 | + prev_longitude += (longitude_diff as f64) / 1e5; |
| 123 | + } |
| 124 | + Ok(unsafe { String::from_utf8_unchecked(output) }) |
119 | 125 | } |
120 | | - Ok(unsafe { String::from_utf8_unchecked(output) }) |
121 | | -} |
122 | | - |
123 | | -#[pymodule] |
124 | | -fn gps_data_codec(m: &Bound<'_, PyModule>) -> PyResult<()> { |
125 | | - m.add_function(wrap_pyfunction!(encode, m)?)?; |
126 | | - m.add_function(wrap_pyfunction!(decode, m)?)?; |
127 | | - |
128 | | - Ok(()) |
129 | 126 | } |
0 commit comments