polyline_iter/
lib.rs

1/// Iterator over geographic coordinates (latitude/longitude pairs) decoded from a polyline-encoded string.
2///
3/// Supports both formats:
4/// - polyline5: Google Maps standard format with 5 decimal places precision
5/// - polyline6: Higher precision format with 6 decimal places, used by routing engines like OSRM and Valhalla
6///
7/// For details on the encoding algorithm, see:
8/// https://developers.google.com/maps/documentation/utilities/polylinealgorithm
9///
10/// ```
11/// let iter = polyline_iter::decode(6, "avs_iB}xlxWissBw|zEu``AsxgCyoaAm_z@");
12/// assert_eq!(
13///     iter.collect::<Vec<_>>(),
14///     vec![
15///         (55.585137, 12.999583),
16///         (55.644854, 13.112187),
17///         (55.678161, 13.182229),
18///         (55.712222, 13.212444),
19///     ]
20/// );
21///
22/// // Count points without collecting them
23/// assert_eq!(polyline_iter::decode(5, "avs_iB}xlxWissBw|zEu``AsxgCyoaAm_z@").count(), 4);
24///
25/// // Iterator approach allows to transcode polyline to another precision without intermediate allocations.
26/// let polyline5 = polyline_iter::encode(5, polyline_iter::decode(6, "avs_iB}xlxWissBw|zEu``AsxgCyoaAm_z@"));
27/// assert_eq!(polyline5, "cngrIk~inAgtJw~TeoEwtL{sE{{D");
28/// assert_eq!(
29///     polyline_iter::decode(5, &polyline5).collect::<Vec<_>>(),
30///     vec![
31///         (55.58514, 12.99958),
32///         (55.64486, 13.11218),
33///         (55.67817, 13.18222),
34///         (55.71223, 13.21244)
35///     ],
36/// );
37/// ```
38pub struct PolylineIter<'a> {
39    polyline: &'a [u8],
40    scale: f64,
41    /// Last processed latitude, multiplied by the scale.
42    lat: i32,
43    /// Last processed longitude, multiplied by the scale.
44    lon: i32,
45}
46
47impl<'a> PolylineIter<'a> {
48    /// Creates a new iterator over points decoded from a polyline.
49    /// The precision is the number of decimal places in the coordinates, which is 5 for polyline5 and 6 for polyline6.
50    #[inline(always)]
51    pub fn new(precision: u8, polyline: &'a str) -> Self {
52        assert!(precision <= 7, "i32 can hold up to 180 * 10^7");
53        PolylineIter {
54            polyline: polyline.as_bytes(),
55            lat: 0,
56            lon: 0,
57            scale: 10.0_f64.powi(precision as i32),
58        }
59    }
60
61    #[inline(always)]
62    fn varint_decode(&mut self) -> Option<u32> {
63        let mut result = 0;
64        for i in 0..self.polyline.len().min(7) {
65            // Casting here to i32 here to provide bad value instead of overflow panicking on bad input.
66            let chunk = (self.polyline[i] as i32) - 63;
67            result |= (chunk & 0x1f) << (i * 5); // no shift overflow as i < 7
68            if chunk & 0x20 == 0 {
69                self.polyline = &self.polyline[i + 1..];
70                return Some(result as u32);
71            }
72        }
73        None
74    }
75
76    /// O(n) operation to count the number of points in the polyline without consuming the iterator.
77    pub fn len(&self) -> usize {
78        self.polyline
79            .iter()
80            .filter(|&&byte| (byte as i8 - 63) & 0x20 == 0)
81            .count()
82            / 2 // Each point has 2 numbers
83    }
84
85    /// Checks if the polyline contains no points.
86    pub fn is_empty(&self) -> bool {
87        self.polyline
88            .iter()
89            .filter(|&&byte| (byte as i8 - 63) & 0x20 == 0)
90            .nth(1)
91            .is_none()
92    }
93}
94
95impl Iterator for PolylineIter<'_> {
96    type Item = (f64, f64);
97
98    fn next(&mut self) -> Option<Self::Item> {
99        let lat_change = self.varint_decode()?;
100        let lon_change = self.varint_decode()?;
101        self.lat += zigzag_decode(lat_change);
102        self.lon += zigzag_decode(lon_change);
103        let lat = self.lat as f64 / self.scale;
104        let lon = self.lon as f64 / self.scale;
105        Some((lat, lon))
106    }
107
108    fn size_hint(&self) -> (usize, Option<usize>) {
109        // There are at least polyline.len() / 12 points as each i32 is encoded in 5 bits per char.
110        // And at most polyline.len() / 2 points if each number (2 per point) is encoded only by a single char.
111        let len = self.polyline.len();
112        (len / 12, Some(len / 2))
113    }
114
115    fn count(self) -> usize {
116        self.len()
117    }
118}
119
120/// Decodes a polyline-encoded string into an iterator over geographic coordinates (latitude/longitude pairs).
121///
122/// This is a convenience function that wraps [`PolylineIter::new()`] and returns an iterator over points.
123/// The precision parameter specifies the number of decimal places in the coordinates (5 for polyline5,
124/// 6 for polyline6), with a maximum value of 7 which corresponds to ~1cm precision at the equator.
125///
126/// ```
127/// use polyline_iter::decode;
128///
129/// // Decode a polyline5 string (Google Maps standard format)
130/// let points: Vec<_> = decode(5, "angrIk~inAgwDybH").collect();
131/// assert_eq!(points, vec![(55.58513, 12.99958), (55.61461, 13.04627)]);
132///
133/// // Decode a polyline6 string (higher precision format)
134/// let points: Vec<_> = decode(6, "avs_iB}xlxWissBw|zEu``AsxgCyoaAm_z@").collect();
135/// assert_eq!(
136///     points,
137///     vec![
138///         (55.585137, 12.999583),
139///         (55.644854, 13.112187),
140///         (55.678161, 13.182229),
141///         (55.712222, 13.212444),
142///     ]
143/// );
144///
145/// // Count points without collecting them
146/// assert_eq!(decode(5, "angrIk~inAgwDybH").count(), 2);
147/// ```
148#[inline(always)]
149pub fn decode(precision: u8, polyline: &str) -> PolylineIter<'_> {
150    PolylineIter::new(precision, polyline)
151}
152
153/// Encodes a sequence of points (latitude, longitude pairs) into a polyline string with the given precision.
154/// The precision parameter specifies the number of decimal places in the coordinates (5 for polyline5,
155/// 6 for polyline6), with a maximum value of 7 which corresponds to ~1cm precision at the equator.
156///
157/// ```
158/// // Encode an array of latitude/longitude coordinates with precision 5 (standard for Google Maps)
159/// assert_eq!(polyline_iter::encode(5, [(55.58513, 12.99958), (55.61461, 13.04627)]),"angrIk~inAgwDybH");
160///
161/// // `encode()` accepts any iterator that produce (lat,lon)
162/// let iter = (1..5).map(|i| (55.5 + 0.1 * i as f64, 12.9 + 0.1 * i as f64));
163/// assert_eq!(polyline_iter::encode(5, iter), "_kjrI_ajnA_pR_pR_pR_pR_pR_pR");
164///
165/// // And it can be used with slices as well (convert iter of references to iter of values with `copied()`)
166/// let points = vec![
167///     (55.58513, 12.99958),
168///     (55.61461, 13.04627),
169///     (55.64485, 13.11219),
170///     (55.67816, 13.18223),
171///     (55.71840, 13.22343),
172/// ];
173/// assert_eq!(polyline_iter::encode(5, points[1..3].iter().copied()), "ifmrIebsnA_|D_{K");
174/// ```
175pub fn encode(precision: u8, points: impl IntoIterator<Item = (f64, f64)>) -> String {
176    assert!(precision <= 7, "i32 can hold up to 180 * 10^7");
177
178    let scale = 10.0_f64.powi(precision as i32);
179    let mut result = String::with_capacity(16);
180
181    let mut prev = (0.0, 0.0);
182    for point in points {
183        let lat_change = ((point.0 - prev.0) * scale).round() as i32;
184        let lon_change = ((point.1 - prev.1) * scale).round() as i32;
185
186        varint32_encode5(zigzag_encode(lat_change), &mut result);
187        varint32_encode5(zigzag_encode(lon_change), &mut result);
188
189        prev = point;
190    }
191    result
192}
193
194/// Encodes a sequence of points into a space-efficient binary format.
195///
196/// This binary format stores 7 bits per byte instead of the 5 bits used by the standard polyline
197/// format, resulting in approximately 20-30% smaller size. The format is not URL-safe and is
198/// intended for binary storage contexts like databases, protobuf, or file formats.
199///
200/// # Performance
201///
202/// Uses bit interleaving to optimize for small coordinate changes, which are common in geographic
203/// paths. This technique saves an additional 10-15% space compared to naive binary encoding.
204///
205/// # Examples
206///
207/// ```
208/// // Encode points in binary format
209/// let points = [(55.58513, 12.99958), (55.61461, 13.04627)];
210/// let binary_data = polyline_iter::encode_binary(5, points);
211///
212/// // Binary format is more compact than text
213/// let text_polyline = polyline_iter::encode(5, points);
214/// assert!(binary_data.len() < text_polyline.len());
215///
216/// // Round-trip encoding/decoding
217/// let decoded_points: Vec<_> = polyline_iter::decode_binary(5, &binary_data).collect();
218/// assert_eq!(decoded_points, points);
219///
220/// // Convert existing polyline to binary format
221/// let polyline = "angrIk~inAgwDybH_|D_{K";
222/// let binary = polyline_iter::encode_binary(5, polyline_iter::decode(5, polyline));
223/// ```
224pub fn encode_binary(precision: u8, points: impl IntoIterator<Item = (f64, f64)>) -> Vec<u8> {
225    assert!(precision <= 7, "i32 can hold up to 180 * 10^7");
226
227    let scale = 10.0_f64.powi(precision as i32);
228    let mut result = Vec::with_capacity(16);
229
230    let mut prev = (0.0, 0.0);
231    for point in points {
232        let lat_change = ((point.0 - prev.0) * scale).round() as i32;
233        let lon_change = ((point.1 - prev.1) * scale).round() as i32;
234
235        // When storing 7 bits per byte, there are good chances that many of bits in the last byte will be unused.
236        // By interleaving the bits of lat and lon changes, we sum up their significant bits and encode them together
237        // as a single u64 value, thus reducing the total number of bytes used.
238        // Without interleaving, at least 2 bytes per point are used even for the smallest coordinate change.
239        // With interleaving, small changes in both lat and lon can be stored in a single byte.
240        // It's saves around 10-15% of space on average in real-world scenarios compared to naive varint encoding.
241        let interleaved = bitwise_merge(zigzag_encode(lat_change), zigzag_encode(lon_change));
242        varint64_encode7(interleaved, &mut result);
243
244        prev = point;
245    }
246    result
247}
248
249/// Decodes points from a space-efficient binary polyline format.
250///
251/// This function decodes binary data created by [`encode_binary()`]. The binary format
252/// is not compatible with standard polyline strings - use [`decode()`] for those.
253///
254/// ```
255/// // Decode binary polyline data
256/// let polyline = "angrIk~inAgwDybH_|D_{K";
257/// let binary_data = polyline_iter::encode_binary(5, polyline_iter::decode(5, polyline));
258///
259/// let points: Vec<_> = polyline_iter::decode_binary(5, &binary_data).collect();
260///
261/// // Binary format is lossless
262/// let reconstructed = polyline_iter::encode(5, points);
263/// assert_eq!(polyline, reconstructed);
264/// ```
265pub fn decode_binary(precision: u8, polyline: &[u8]) -> BinaryPolylineIter<'_> {
266    BinaryPolylineIter::new(precision, polyline)
267}
268
269/// Iterator over geographic coordinates decoded from binary polyline data.
270///
271/// Created by [`decode_binary()`]. This iterator provides the same interface as
272/// [`PolylineIter`] but works with the space-efficient binary format.
273///
274/// # Examples
275///
276/// ```
277/// let binary_data = polyline_iter::encode_binary(6, [(55.585137, 12.999583)]);
278/// let mut iter = polyline_iter::decode_binary(6, &binary_data);
279///
280/// assert_eq!(iter.len(), 1);
281/// assert_eq!(iter.next(), Some((55.585137, 12.999583)));
282/// assert!(iter.is_empty());
283/// ```
284pub struct BinaryPolylineIter<'a> {
285    polyline: &'a [u8],
286    scale: f64,
287    /// Last processed latitude, multiplied by the scale.
288    lat: i32,
289    /// Last processed longitude, multiplied by the scale.
290    lon: i32,
291}
292
293impl<'a> BinaryPolylineIter<'a> {
294    #[inline(always)]
295    pub fn new(precision: u8, polyline: &'a [u8]) -> Self {
296        assert!(precision <= 7, "i32 can hold up to 180 * 10^7");
297        BinaryPolylineIter {
298            polyline,
299            lat: 0,
300            lon: 0,
301            scale: 10.0_f64.powi(precision as i32),
302        }
303    }
304
305    #[inline(always)]
306    fn varint_decode(&mut self) -> Option<u64> {
307        let mut result = 0;
308        for i in 0..self.polyline.len().min(9) {
309            let chunk = self.polyline[i] as u64;
310            result |= (chunk & 0x7f) << (i * 7); // no shift overflow as i < 5
311            if chunk & 0x80 == 0 {
312                self.polyline = &self.polyline[i + 1..];
313                return Some(result);
314            }
315        }
316        None
317    }
318
319    /// O(n) operation to count the number of points in the polyline without consuming the iterator.
320    pub fn len(&self) -> usize {
321        self.polyline
322            .iter()
323            .filter(|&&byte| byte & 0x80 == 0)
324            .count()
325    }
326
327    /// Checks if the polyline contains no points.
328    pub fn is_empty(&self) -> bool {
329        !self.polyline.iter().any(|&byte| byte & 0x80 == 0)
330    }
331}
332
333impl Iterator for BinaryPolylineIter<'_> {
334    type Item = (f64, f64);
335
336    fn next(&mut self) -> Option<Self::Item> {
337        let (lat_change, lon_change) = bitwise_split(self.varint_decode()?);
338        self.lat += zigzag_decode(lat_change);
339        self.lon += zigzag_decode(lon_change);
340        let lat = self.lat as f64 / self.scale;
341        let lon = self.lon as f64 / self.scale;
342        Some((lat, lon))
343    }
344
345    fn size_hint(&self) -> (usize, Option<usize>) {
346        // There are at least polyline.len() / 10 points as each i32 is encoded in 5 bits per char.
347        // And at most polyline.len() / 2 points if each number (2 per point) is encoded only by a single char.
348        let len = self.polyline.len();
349        (len / 10, Some(len / 2))
350    }
351
352    fn count(self) -> usize {
353        self.len()
354    }
355}
356
357/// Zigzag encoded numbers store the sign in the least significant bit, which this function moves to the sign bit.
358fn zigzag_decode(i: u32) -> i32 {
359    (i >> 1) as i32 ^ -((i & 1) as i32)
360}
361
362/// Moves the sign bit from the most significant bit to the least significant bit,
363/// thus reducing number of significant bits for negative numbers.
364fn zigzag_encode(value: i32) -> u32 {
365    (value << 1) as u32 ^ (value >> 31) as u32
366}
367
368/// Encodes the value into a variable-length format, storing 5 bits per byte to keep
369/// all bytes URL-compatible (from 63 to 126).
370fn varint32_encode5(mut value: u32, buffer: &mut String) {
371    while value >= 0x20 {
372        let byte = char::from_u32(((value & 0x1F) | 0x20) + 63).unwrap();
373        buffer.push(byte);
374        value >>= 5;
375    }
376    let byte = char::from_u32(value + 63).unwrap();
377    buffer.push(byte);
378}
379
380/// Encodes the value into a variable-length format, storing 7 bits per byte.
381fn varint64_encode7(mut value: u64, buffer: &mut Vec<u8>) {
382    while value >= 0x80 {
383        let byte = (value & 0x7F) as u8 | 0x80;
384        buffer.push(byte);
385        value >>= 7;
386    }
387    buffer.push(value as u8);
388}
389
390/// Merges bits from two 32-bit integers into a 64-bit integer, shuffling bits from
391/// x = 'ABCD EFGH IJKL MNOP' and y = 'abcd efgh ijkl mnop' to 'aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP'.
392/// So if `x` and `y` have low number of significant bits, the result will have low number of significant bits.
393fn bitwise_merge(x: u32, y: u32) -> u64 {
394    perfect_shuffle(((y as u64) << 32) | (x as u64))
395}
396
397/// Reverse operation to [`bitwise_merge`], splitting a 64-bit integer into two 32-bit integers.
398fn bitwise_split(v: u64) -> (u32, u32) {
399    let unshuffle = perfect_unshuffle(v);
400    (unshuffle as u32, (unshuffle >> 32) as u32)
401}
402
403/// Perform a perfect shuffle of the bits of 64-bit integer, shuffling bits from
404/// 'abcd efgh ijkl mnop ABCD EFGH IJKL MNOP' to 'aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP'.
405/// See http://www.icodeguru.com/Embedded/Hacker's-Delight/047.htm
406fn perfect_shuffle(mut x: u64) -> u64 {
407    x = ((x & 0x00000000FFFF0000) << 16) | (x >> 16) & 0x00000000FFFF0000 | x & 0xFFFF00000000FFFF;
408    x = ((x & 0x0000FF000000FF00) << 8) | (x >> 8) & 0x0000FF000000FF00 | x & 0xFF0000FFFF0000FF;
409    x = ((x & 0x00F000F000F000F0) << 4) | (x >> 4) & 0x00F000F000F000F0 | x & 0xF00FF00FF00FF00F;
410    x = ((x & 0x0C0C0C0C0C0C0C0C) << 2) | (x >> 2) & 0x0C0C0C0C0C0C0C0C | x & 0xC3C3C3C3C3C3C3C3;
411    x = ((x & 0x2222222222222222) << 1) | (x >> 1) & 0x2222222222222222 | x & 0x9999999999999999;
412
413    x
414}
415
416/// Reverse operation to [`perfect_shuffle`] unshuffles the bits of 64-bit integer from
417/// 'aAbB cCdD eEfF gGhH iIjJ kKlL mMnN oOpP' to 'abcd efgh ijkl mnop ABCD EFGH IJKL MNOP'.
418/// Reverse operation to [`perfect_shuffle`].
419/// See http://www.icodeguru.com/Embedded/Hacker's-Delight/047.htm
420fn perfect_unshuffle(mut x: u64) -> u64 {
421    x = ((x & 0x2222222222222222) << 1) | (x >> 1) & 0x2222222222222222 | x & 0x9999999999999999;
422    x = ((x & 0x0C0C0C0C0C0C0C0C) << 2) | (x >> 2) & 0x0C0C0C0C0C0C0C0C | x & 0xC3C3C3C3C3C3C3C3;
423    x = ((x & 0x00F000F000F000F0) << 4) | (x >> 4) & 0x00F000F000F000F0 | x & 0xF00FF00FF00FF00F;
424    x = ((x & 0x0000FF000000FF00) << 8) | (x >> 8) & 0x0000FF000000FF00 | x & 0xFF0000FFFF0000FF;
425    x = ((x & 0x00000000FFFF0000) << 16) | (x >> 16) & 0x00000000FFFF0000 | x & 0xFFFF00000000FFFF;
426
427    x
428}
429
430#[cfg(test)]
431mod tests {
432    use super::*;
433    use pretty_assertions::assert_eq;
434
435    /// Checks if the polyline contains only valid characters and ends with a complete point.
436    fn check_polyline(polyline: &str) -> bool {
437        let bytes = polyline.as_bytes();
438        let mut stop_bytes = 0;
439        for &byte in bytes {
440            if (byte as u32) < 63 || (byte as u32) > 127 {
441                return false;
442            }
443            if (byte - 63) & 0x20 == 0 {
444                stop_bytes += 1;
445            }
446        }
447        // The polyline is valid if it ends with a complete point.
448        stop_bytes % 2 == 0 && bytes.last().map(|b| b & 0x20 == 0).unwrap_or(true)
449    }
450
451    #[test]
452    fn zigzag() {
453        assert_eq!(zigzag_decode(0), 0);
454        assert_eq!(zigzag_decode(1), -1);
455        assert_eq!(zigzag_decode(2), 1);
456        assert_eq!(zigzag_decode(3), -2);
457        assert_eq!(zigzag_decode(4), 2);
458        assert_eq!(zigzag_decode(5), -3);
459        assert_eq!(zigzag_decode(6), 3);
460        assert_eq!(zigzag_decode(7), -4);
461        assert_eq!(zigzag_decode(8), 4);
462        assert_eq!(zigzag_decode(9), -5);
463        assert_eq!(zigzag_decode(10), 5);
464        assert_eq!(zigzag_decode(11), -6);
465        assert_eq!(zigzag_decode(12), 6);
466        assert_eq!(zigzag_decode(13), -7);
467        assert_eq!(zigzag_decode(14), 7);
468        assert_eq!(zigzag_decode(15), -8);
469
470        assert_eq!(zigzag_encode(0), 0);
471        assert_eq!(zigzag_encode(-1), 1);
472        assert_eq!(zigzag_encode(1), 2);
473        assert_eq!(zigzag_encode(-2), 3);
474        assert_eq!(zigzag_encode(2), 4);
475        assert_eq!(zigzag_encode(-3), 5);
476        assert_eq!(zigzag_encode(3), 6);
477        assert_eq!(zigzag_encode(-4), 7);
478        assert_eq!(zigzag_encode(4), 8);
479        assert_eq!(zigzag_encode(-5), 9);
480        assert_eq!(zigzag_encode(5), 10);
481        assert_eq!(zigzag_encode(-6), 11);
482        assert_eq!(zigzag_encode(6), 12);
483        assert_eq!(zigzag_encode(-7), 13);
484        assert_eq!(zigzag_encode(7), 14);
485        assert_eq!(zigzag_encode(-8), 15);
486    }
487
488    #[test]
489    fn empty_polyline() {
490        assert_eq!(decode(5, "").next(), None);
491        assert_eq!(encode(5, []), "");
492
493        assert_eq!(decode(6, "").next(), None);
494        assert_eq!(encode(6, []), "");
495    }
496
497    #[test]
498    fn single_point() {
499        assert_eq!(encode(5, [(0.0, 0.0)]), "??");
500        assert_eq!(decode(5, "??").collect::<Vec<_>>(), [(0.0, 0.0)]);
501        assert_eq!(encode(6, [(0.0, 0.0)]), "??");
502        assert_eq!(decode(6, "??").collect::<Vec<_>>(), [(0.0, 0.0)]);
503
504        let point = (55.71218211778275, 13.21561509233427);
505        assert_eq!(encode(5, [point]), "ch`sIsdtoA");
506        assert_eq!(
507            decode(5, "ch`sIsdtoA").collect::<Vec<_>>(),
508            [(55.71218, 13.21562)]
509        );
510        assert_eq!(encode(6, [point]), "kzkgiB}vreX");
511        assert_eq!(
512            decode(6, "kzkgiB}vreX").collect::<Vec<_>>(),
513            [(55.712182, 13.215615)]
514        );
515        assert_eq!(encode(7, [point]), "yp_se`@mnda{F");
516        assert_eq!(
517            decode(7, "yp_se`@mnda{F").collect::<Vec<_>>(),
518            [(55.7121821, 13.2156151)]
519        );
520
521        let point = (37.82070486887192, -122.47866012130189);
522        assert_eq!(encode(5, [point]), "kzyeFrrpjV");
523        assert_eq!(
524            decode(5, "kzyeFrrpjV").collect::<Vec<_>>(),
525            [(37.82070, -122.47866)]
526        );
527        assert_eq!(encode(6, [point]), "aqkcgAfcorhF");
528        assert_eq!(
529            decode(6, "aqkcgAfcorhF").collect::<Vec<_>>(),
530            [(37.820705, -122.478660)]
531        );
532
533        let point = (-54.906532713928094, -65.99208264367125);
534        assert_eq!(encode(5, [point]), "x|bnInaxqK");
535        assert_eq!(
536            decode(5, "x|bnInaxqK").collect::<Vec<_>>(),
537            [(-54.90653, -65.99208)]
538        );
539        assert_eq!(encode(6, [point]), "hifvgBdxyz|B");
540        assert_eq!(
541            decode(6, "hifvgBdxyz|B").collect::<Vec<_>>(),
542            [(-54.906533, -65.992083)]
543        );
544
545        let point = (-37.88209074375984, 144.79631245265494);
546        assert_eq!(encode(5, [point]), "`zefF}owrZ");
547        assert_eq!(
548            decode(5, "`zefF}owrZ").collect::<Vec<_>>(),
549            [(-37.88209, 144.79631)]
550        );
551        assert_eq!(encode(6, [point]), "tmcggAohtdsG");
552        assert_eq!(
553            decode(6, "tmcggAohtdsG").collect::<Vec<_>>(),
554            [(-37.882091, 144.796312)]
555        );
556    }
557
558    #[test]
559    fn multiple_points() {
560        let polyline = "angrIk~inAgwDybH_|D_{KeoEwtLozFo`Gre@tcA";
561        assert!(check_polyline(polyline));
562        assert_eq!(decode(5, polyline).count(), 6);
563
564        let mut iter = decode(5, polyline);
565        assert_eq!(iter.next(), Some((55.58513, 12.99958)));
566        assert_eq!(iter.next(), Some((55.61461, 13.04627)));
567        assert_eq!(iter.next(), Some((55.64485, 13.11219)));
568        assert_eq!(iter.next(), Some((55.67816, 13.18223)));
569        assert_eq!(iter.next(), Some((55.71840, 13.22343)));
570        assert_eq!(iter.next(), Some((55.71222, 13.21244)));
571        assert_eq!(iter.next(), None);
572
573        // If polyline is decoded with wrong precision, the points will be x10 times smaller or bigger.
574        let mut iter = decode(6, polyline);
575        assert_eq!(iter.next(), Some((5.558513, 1.299958)));
576        assert_eq!(iter.next(), Some((5.561461, 1.304627)));
577        assert_eq!(iter.next(), Some((5.564485, 1.311219)));
578        assert_eq!(iter.next(), Some((5.567816, 1.318223)));
579        assert_eq!(iter.next(), Some((5.571840, 1.322343)));
580        assert_eq!(iter.next(), Some((5.571222, 1.321244)));
581        assert_eq!(iter.next(), None);
582
583        // Forward and backward transcoding should give the same result
584        let polyline = "gzkgiBgwreX{@sI~HcBwBoi@sXvBsIcBgJSwGg@wGg@cG{@{JoAwGSkC{@ce@gOwj@oKsb@cBoFz@gEjC?~RRb[f@v[Sz@kHnAoA_l@SsIR?";
585        assert_eq!(encode(6, decode(6, polyline)), polyline);
586
587        // Transcoding polyline to another precision
588        assert_eq!(
589            encode(5, decode(6, polyline)),
590            "ch`sIsdtoAEa@^IKgCqAJa@Ic@A[C[CYEe@G[AMEyBs@kCg@qBIWDSL?~@@xABzAAD]FGoCAa@@?"
591        );
592
593        assert_eq!(
594            encode(
595                6,
596                // decoded with wrong precision, but then corrected by `* 10.0`
597                decode(7, polyline).map(|(lat, lon)| (lat * 10.0, lon * 10.0))
598            ),
599            polyline
600        );
601    }
602
603    #[test]
604    #[should_panic]
605    fn decode_bad_precision() {
606        decode(8, "");
607    }
608
609    #[test]
610    #[should_panic]
611    fn encode_bad_precision() {
612        encode(8, []);
613    }
614
615    #[test]
616    fn broken_string() {
617        // incomplete point
618        assert_eq!(decode(5, "?").next(), None);
619        assert_eq!(decode(5, "?").is_empty(), true);
620        assert_eq!(decode(5, "?").len(), 0);
621
622        // Last point is missing a lon change, so the whole points will be skipped.
623        let polyline = "_p~iF~ps|U_ulLnnqC_mqNvxq";
624        assert!(!check_polyline(polyline)); // the polyline is not valid, but still can be decoded.
625        let mut iter = decode(5, polyline);
626        assert_eq!(iter.len(), 2);
627        assert_eq!(iter.is_empty(), false);
628        assert_eq!(iter.next(), Some((38.5, -120.2)));
629        assert_eq!(iter.len(), 1);
630        assert_eq!(iter.is_empty(), false);
631        assert_eq!(iter.next(), Some((40.7, -120.95)));
632        assert_eq!(iter.len(), 0);
633        assert_eq!(iter.is_empty(), true);
634        assert_eq!(iter.next(), None);
635
636        let mut iter = decode(6, polyline);
637        assert_eq!(iter.len(), 2);
638        assert_eq!(iter.is_empty(), false);
639        assert_eq!(iter.next(), Some((3.85, -12.02)));
640        assert_eq!(iter.len(), 1);
641        assert_eq!(iter.is_empty(), false);
642        assert_eq!(iter.next(), Some((4.07, -12.095)));
643        assert_eq!(iter.len(), 0);
644        assert_eq!(iter.is_empty(), true);
645        assert_eq!(iter.next(), None);
646        assert_eq!(iter.len(), 0);
647        assert_eq!(iter.is_empty(), true);
648
649        assert_eq!(iter.next(), None); // just to make sure it does not panic
650        assert_eq!(iter.is_empty(), true);
651    }
652
653    #[test]
654    fn invalid_symbols() {
655        // `!` (33) is not a valid symbol for a polyline because it is not in the range [63, 127].
656        let polyline = "!!!!";
657        assert!(!check_polyline(polyline));
658        let mut iter = decode(5, polyline);
659        assert_eq!(iter.next(), None);
660
661        // Now let's add `!` in the middle of a valid polyline.
662        let polyline = "_p~iF~ps|U_ulLnnqC!_mqNvxq";
663        assert!(!check_polyline(polyline)); // the polyline is not valid, but still can be decoded.
664        let mut iter = decode(5, polyline);
665        assert_eq!(iter.next(), Some((38.5, -120.2)));
666        assert_eq!(iter.next(), Some((40.7, -120.95)));
667        assert_eq!(iter.next(), None);
668
669        // And let's check that it handles overflowing varint properly.
670        let polyline = "||||||||||||||||||||||||||||||||"; // '|' = 124, (124-63) & 0x20 = 0x20 (continuation bit set)
671        let mut iter = decode(5, polyline);
672        assert_eq!(iter.next(), None); // Should return None because varint_decode fails
673    }
674
675    #[test]
676    fn size_hint() {
677        let iter = decode(5, "_p~iF~ps|U_ulLnnqC_mqNvxq`@");
678        // Size hint should not be precise as the number of points depends the distance between them.
679        assert!(iter.size_hint().0 <= 3);
680        assert!(iter.size_hint().1.unwrap() >= 3);
681        assert_eq!(iter.count(), 3);
682    }
683
684    #[test]
685    fn perfect_shuffle_test() {
686        assert_eq!(perfect_shuffle(0b0), 0b0);
687        assert_eq!(perfect_shuffle(0b1), 0b1);
688
689        assert_eq!(perfect_shuffle(0b1111), 0b01010101);
690        assert_eq!(perfect_unshuffle(0b01010101), 0b1111);
691
692        assert_eq!(perfect_shuffle(0b11111111), 0b0101010101010101);
693        assert_eq!(perfect_unshuffle(0b0101010101010101), 0b11111111);
694
695        assert_eq!(
696            perfect_shuffle(0b1111_1111_1111_1111),
697            0b0101_0101_0101_0101_0101_0101_0101_0101
698        );
699        assert_eq!(
700            perfect_unshuffle(0b0101_0101_0101_0101_0101_0101_0101_0101),
701            0b1111_1111_1111_1111
702        );
703
704        assert_eq!(
705            perfect_shuffle(0b0000_0000_0000_0000_1111_1111_0000_0000),
706            0b0101_0101_0101_0101_0000_0000_0000_0000
707        );
708        assert_eq!(
709            perfect_unshuffle(0b0101_0101_0101_0101_0000_0000_0000_0000),
710            0b0000_0000_0000_0000_1111_1111_0000_0000
711        );
712    }
713
714    #[test]
715    fn bitwise_merge_test() {
716        assert_eq!(bitwise_merge(0b0, 0b0), 0b00);
717        assert_eq!(bitwise_split(0b00), (0b0, 0b0));
718
719        assert_eq!(bitwise_merge(0b1, 0b0), 0b01);
720        assert_eq!(bitwise_split(0b01), (0b1, 0b0));
721
722        assert_eq!(bitwise_merge(0b0, 0b1), 0b10);
723        assert_eq!(bitwise_split(0b10), (0b0, 0b1));
724
725        assert_eq!(bitwise_merge(0b1, 0b1), 0b11);
726        assert_eq!(bitwise_split(0b11), (0b1, 0b1));
727
728        assert_eq!(bitwise_merge(0b00000000, 0b11111111), 0b10101010_10101010);
729        assert_eq!(bitwise_split(0b10101010_10101010), (0b00000000, 0b11111111));
730
731        assert_eq!(bitwise_merge(0b11111111, 0b00000000), 0b01010101_01010101);
732        assert_eq!(bitwise_split(0b01010101_01010101), (0b11111111, 0b00000000));
733
734        assert_eq!(bitwise_merge(0b00001111, 0b00001111), 0b00000000_11111111);
735        assert_eq!(bitwise_split(0b00000000_11111111), (0b00001111, 0b00001111));
736
737        assert_eq!(
738            bitwise_merge(0b11111111_11111111_11111111_11111111, 0b0),
739            0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101
740        );
741        assert_eq!(
742            bitwise_split(
743                0b01010101_01010101_01010101_01010101_01010101_01010101_01010101_01010101
744            ),
745            (0b11111111_11111111_11111111_11111111, 0b0)
746        );
747
748        assert_eq!(
749            bitwise_merge(0xF00FF00F, 0x0FF00FF0),
750            0b01010101_10101010_10101010_01010101_01010101_10101010_10101010_01010101
751        );
752        assert_eq!(
753            bitwise_split(
754                0b01010101_10101010_10101010_01010101_01010101_10101010_10101010_01010101
755            ),
756            (0xF00FF00F, 0x0FF00FF0)
757        );
758    }
759
760    #[test]
761    fn encode_decode_binary() {
762        let polyline = "angrIk~inAgwDybH_|D_{KeoEwtLozFo`Gre@tcA";
763        let points: Vec<_> = decode(5, polyline).collect();
764
765        let compressed = encode_binary(5, points.iter().copied());
766        let decompressed: Vec<_> = decode_binary(5, &compressed).collect();
767        assert_eq!(decompressed, points);
768        assert_eq!(polyline.len(), 40);
769        assert_eq!(compressed.len(), 27);
770
771        assert_eq!(decode_binary(5, &compressed).count(), points.len());
772    }
773}