Skip to content

Commit 2500b0e

Browse files
authored
Update Rust package to 1.0.0 (#89)
* 1.0.0 version * 2021 edition * clippy fixes * README for crates.io (in addition to lib.rs docs) * --original-precision added to CLI application --------- Signed-off-by: Christian Vetter <christian.vetter@here.com>
1 parent c7e9772 commit 2500b0e

5 files changed

Lines changed: 105 additions & 87 deletions

File tree

rust/Cargo.toml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
[package]
22
name = "flexpolyline"
3-
version = "0.1.0"
3+
version = "1.0.0"
4+
readme = "README.md"
45
description = "Flexible Polyline encoding: a lossy compressed representation of a list of coordinate pairs or triples"
56
authors = ["HERE Europe B.V."]
67
repository = "https://github.com/heremaps/flexible-polyline.git"
78
license = "MIT"
89
keywords = ["polyline", "encoding"]
9-
edition = "2018"
10-
11-
[dependencies]
12-
13-
[dev-dependencies]
14-
rand = "0.6.5"
10+
edition = "2021"
1511

1612
[[bin]]
1713
name = "flexpolyline"
1814
path = "src/cli.rs"
15+
16+
[dev_dependencies]
17+
rand = "0.8.5"

rust/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Flexible Polyline encoding
2+
3+
The flexible polyline encoding is a lossy compressed representation of a list of coordinate
4+
pairs or coordinate triples. It achieves that by:
5+
6+
1. Reducing the decimal digits of each value.
7+
2. Encoding only the offset from the previous point.
8+
3. Using variable length for each coordinate delta.
9+
4. Using 64 URL-safe characters to display the result.
10+
11+
The encoding is a variant of [Encoded Polyline Algorithm Format]. The advantage of this encoding
12+
over the original are the following:
13+
14+
* Output string is composed by only URL-safe characters, i.e. may be used without URL encoding
15+
as query parameters.
16+
* Floating point precision is configurable: This allows to represent coordinates with precision
17+
up to microns (5 decimal places allow meter precision only).
18+
* It allows to encode a 3rd dimension with a given precision, which may be a level, altitude,
19+
elevation or some other custom value.
20+
21+
## Specification
22+
23+
See [Specification].
24+
25+
[Encoded Polyline Algorithm Format]: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
26+
[Specification]: https://github.com/heremaps/flexible-polyline#specifications
27+
28+
## Example
29+
30+
```rust
31+
use flexpolyline::{Polyline, Precision};
32+
33+
// encode
34+
let coordinates = vec![
35+
(50.1022829, 8.6982122),
36+
(50.1020076, 8.6956695),
37+
(50.1006313, 8.6914960),
38+
(50.0987800, 8.6875156),
39+
];
40+
41+
let polyline = Polyline::Data2d {
42+
coordinates,
43+
precision2d: Precision::Digits5,
44+
};
45+
46+
let encoded = polyline.encode().unwrap();
47+
assert_eq!(encoded, "BFoz5xJ67i1B1B7PzIhaxL7Y");
48+
49+
// decode
50+
let decoded = Polyline::decode("BFoz5xJ67i1B1B7PzIhaxL7Y").unwrap();
51+
assert_eq!(
52+
decoded,
53+
Polyline::Data2d {
54+
coordinates: vec![
55+
(50.10228, 8.69821),
56+
(50.10201, 8.69567),
57+
(50.10063, 8.69150),
58+
(50.09878, 8.68752)
59+
],
60+
precision2d: Precision::Digits5
61+
}
62+
);
63+
```

rust/examples/random.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ fn main() {
3737
coordinates: (0..num_coords)
3838
.map(|_| {
3939
(
40-
(rng.gen_range(-range_lat, range_lat) / divisor) as f64
40+
(rng.gen_range(-range_lat..=range_lat) / divisor) as f64
4141
/ 10_i64.pow(15) as f64,
42-
(rng.gen_range(-range_lon, range_lon) / divisor) as f64
42+
(rng.gen_range(-range_lon..=range_lon) / divisor) as f64
4343
/ 10_i64.pow(15) as f64,
44-
(rng.gen_range(-range_z, range_z) / divisor) as f64
44+
(rng.gen_range(-range_z..=range_z) / divisor) as f64
4545
/ 10_i64.pow(14) as f64,
4646
)
4747
})
@@ -55,9 +55,9 @@ fn main() {
5555
coordinates: (0..num_coords)
5656
.map(|_| {
5757
(
58-
(rng.gen_range(-range_lat, range_lat) / divisor) as f64
58+
(rng.gen_range(-range_lat..=range_lat) / divisor) as f64
5959
/ 10_i64.pow(15) as f64,
60-
(rng.gen_range(-range_lon, range_lon) / divisor) as f64
60+
(rng.gen_range(-range_lon..=range_lon) / divisor) as f64
6161
/ 10_i64.pow(15) as f64,
6262
)
6363
})

rust/src/cli.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,18 @@ fn from_str(data: &str) -> flexpolyline::Polyline {
106106
}
107107

108108
fn main() {
109+
// Manually parse command line arguments to avoid adding any addditional dependencies
109110
let args: Vec<String> = std::env::args().collect();
110-
if args.len() != 2 || (args[1] != "encode" && args[1] != "decode") {
111-
eprintln!("Usage: flexpolyline encode|decode");
111+
let original_precision_arg = "--original-precision".to_string();
112+
if (args.len() != 2 && args.len() != 3)
113+
|| (args[1] != "encode" && args[1] != "decode")
114+
|| (args.len() == 3 && args[2] != original_precision_arg)
115+
{
116+
eprintln!("Usage: flexpolyline encode|decode [{original_precision_arg}]");
112117
eprintln!(" input: stdin");
113118
eprintln!(" output: stdout");
119+
eprintln!(" Options:");
120+
eprintln!(" {original_precision_arg}: Print decoded polyline with encoded precision");
114121
std::process::exit(1);
115122
}
116123

@@ -132,7 +139,11 @@ fn main() {
132139
let input = line.unwrap();
133140
let polyline = flexpolyline::Polyline::decode(&input)
134141
.unwrap_or_else(|e| panic!("Failed to decode {}: {}", input, e));
135-
println!("{:.15}", polyline);
142+
if args.get(2) == Some(&original_precision_arg) {
143+
println!("{polyline}");
144+
} else {
145+
println!("{polyline:.15}");
146+
}
136147
}
137148
}
138149
}

rust/src/lib.rs

Lines changed: 17 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,4 @@
1-
//! # Flexible Polyline encoding
2-
//!
3-
//! The flexible polyline encoding is a lossy compressed representation of a list of coordinate
4-
//! pairs or coordinate triples. It achieves that by:
5-
//!
6-
//! 1. Reducing the decimal digits of each value.
7-
//! 2. Encoding only the offset from the previous point.
8-
//! 3. Using variable length for each coordinate delta.
9-
//! 4. Using 64 URL-safe characters to display the result.
10-
//!
11-
//! The encoding is a variant of [Encoded Polyline Algorithm Format]. The advantage of this encoding
12-
//! over the original are the following:
13-
//!
14-
//! * Output string is composed by only URL-safe characters, i.e. may be used without URL encoding
15-
//! as query parameters.
16-
//! * Floating point precision is configurable: This allows to represent coordinates with precision
17-
//! up to microns (5 decimal places allow meter precision only).
18-
//! * It allows to encode a 3rd dimension with a given precision, which may be a level, altitude,
19-
//! elevation or some other custom value.
20-
//!
21-
//! ## Specification
22-
//!
23-
//! See [Specification].
24-
//!
25-
//! [Encoded Polyline Algorithm Format]: https://developers.google.com/maps/documentation/utilities/polylinealgorithm
26-
//! [Specification]: https://github.com/heremaps/flexible-polyline#specifications
27-
//!
28-
//! ## Example
29-
//!
30-
//! ```rust
31-
//! use flexpolyline::{Polyline, Precision};
32-
//!
33-
//! // encode
34-
//! let coordinates = vec![
35-
//! (50.1022829, 8.6982122),
36-
//! (50.1020076, 8.6956695),
37-
//! (50.1006313, 8.6914960),
38-
//! (50.0987800, 8.6875156),
39-
//! ];
40-
//!
41-
//! let polyline = Polyline::Data2d {
42-
//! coordinates,
43-
//! precision2d: Precision::Digits5,
44-
//! };
45-
//!
46-
//! let encoded = polyline.encode().unwrap();
47-
//! assert_eq!(encoded, "BFoz5xJ67i1B1B7PzIhaxL7Y");
48-
//!
49-
//! // decode
50-
//! let decoded = Polyline::decode("BFoz5xJ67i1B1B7PzIhaxL7Y").unwrap();
51-
//! assert_eq!(
52-
//! decoded,
53-
//! Polyline::Data2d {
54-
//! coordinates: vec![
55-
//! (50.10228, 8.69821),
56-
//! (50.10201, 8.69567),
57-
//! (50.10063, 8.69150),
58-
//! (50.09878, 8.68752)
59-
//! ],
60-
//! precision2d: Precision::Digits5
61-
//! }
62-
//! );
63-
//! ```
64-
1+
#![doc = include_str!("../README.md")]
652
#![doc(html_playground_url = "https://play.rust-lang.org/")]
663
#![deny(warnings, missing_docs)]
674
#![allow(clippy::unreadable_literal)]
@@ -185,18 +122,21 @@ pub enum Polyline {
185122

186123
impl std::fmt::Display for Polyline {
187124
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
188-
let prec = f.precision().unwrap_or(6);
189125
match self {
190126
Polyline::Data2d {
191127
coordinates,
192128
precision2d,
193129
} => {
130+
let prec_2d = f.precision().unwrap_or(precision2d.to_u32() as usize);
194131
write!(f, "{{({}); [", precision2d.to_u32())?;
195132
for coord in coordinates {
196133
write!(
197134
f,
198135
"({:.*}, {:.*}), ",
199-
prec as usize, coord.0, prec as usize, coord.1
136+
{ prec_2d },
137+
coord.0,
138+
{ prec_2d },
139+
coord.1
200140
)?;
201141
}
202142
write!(f, "]}}")?;
@@ -207,6 +147,8 @@ impl std::fmt::Display for Polyline {
207147
precision3d,
208148
type3d,
209149
} => {
150+
let prec_2d = f.precision().unwrap_or(precision2d.to_u32() as usize);
151+
let prec_3d = f.precision().unwrap_or(precision3d.to_u32() as usize);
210152
write!(
211153
f,
212154
"{{({}, {}, {}); [",
@@ -218,7 +160,12 @@ impl std::fmt::Display for Polyline {
218160
write!(
219161
f,
220162
"({:.*}, {:.*}, {:.*}), ",
221-
prec as usize, coord.0, prec as usize, coord.1, prec as usize, coord.2
163+
{ prec_2d },
164+
coord.0,
165+
{ prec_2d },
166+
coord.1,
167+
{ prec_3d },
168+
coord.2
222169
)?;
223170
}
224171
write!(f, "]}}")?;
@@ -230,15 +177,14 @@ impl std::fmt::Display for Polyline {
230177

231178
/// Error reported when encoding or decoding polylines
232179
#[derive(Debug, PartialEq, Eq)]
180+
#[non_exhaustive]
233181
pub enum Error {
234182
/// Data is encoded with unsupported version
235183
UnsupportedVersion,
236184
/// Precision is not supported by encoding
237185
InvalidPrecision,
238186
/// Encoding is corrupt
239187
InvalidEncoding,
240-
#[doc(hidden)]
241-
__Nonexhaustive,
242188
}
243189

244190
impl std::fmt::Display for Error {
@@ -247,7 +193,6 @@ impl std::fmt::Display for Error {
247193
Error::UnsupportedVersion => write!(f, "UnsupportedVersion"),
248194
Error::InvalidPrecision => write!(f, "InvalidPrecision"),
249195
Error::InvalidEncoding => write!(f, "InvalidEncoding"),
250-
Error::__Nonexhaustive => panic!(),
251196
}
252197
}
253198
}
@@ -264,7 +209,7 @@ impl Polyline {
264209
Polyline::Data2d {
265210
coordinates,
266211
precision2d,
267-
} => encode_2d(&coordinates, precision2d.to_u32()),
212+
} => encode_2d(coordinates, precision2d.to_u32()),
268213
Polyline::Data3d {
269214
coordinates,
270215
precision2d,
@@ -739,7 +684,7 @@ mod tests {
739684
}
740685
.encode()?;
741686

742-
let polyline = Polyline::decode(&encoded)?;
687+
let polyline = Polyline::decode(encoded)?;
743688
let result = format!("{:.*}", precision2d as usize + 1, polyline);
744689
assert_eq!(expected, result);
745690
}

0 commit comments

Comments
 (0)