Compare commits
31 Commits
Author | SHA1 | Date |
---|---|---|
Paul van Tilburg | 0ef589a5ac | |
Paul van Tilburg | 8b69470cff | |
Paul van Tilburg | 071473ffcf | |
Paul van Tilburg | 867397d2db | |
Paul van Tilburg | 54e3540946 | |
Paul van Tilburg | c63bdceb01 | |
Paul van Tilburg | 00856f4dd9 | |
Paul van Tilburg | e6f02664b7 | |
Paul van Tilburg | bbd061f0d3 | |
Paul van Tilburg | ca86701ee8 | |
Paul van Tilburg | aa9d2b88f7 | |
Paul van Tilburg | 0c158e13b7 | |
Paul van Tilburg | abf3234a25 | |
Paul van Tilburg | be4ebc26e1 | |
Paul van Tilburg | f00fbc76ab | |
Paul van Tilburg | 129b29da26 | |
Paul van Tilburg | 6030134a34 | |
Paul van Tilburg | 79a6f7c25f | |
Paul van Tilburg | 7fbef8ddf9 | |
Paul van Tilburg | 56a888d5a3 | |
Paul van Tilburg | f2cb2788ab | |
Paul van Tilburg | ff32105fce | |
Paul van Tilburg | 758a3f8072 | |
Paul van Tilburg | 2628e96740 | |
Paul van Tilburg | 76ff1c95da | |
Paul van Tilburg | 8ad3d5dea7 | |
Paul van Tilburg | 7f3d4128b8 | |
Paul van Tilburg | 8201b4d17b | |
Paul van Tilburg | eba77d57f8 | |
Paul van Tilburg | 93cc6a8501 | |
Paul van Tilburg | 3a9bc96289 |
|
@ -0,0 +1,48 @@
|
||||||
|
name: "Check, lint and test using Cargo"
|
||||||
|
|
||||||
|
on:
|
||||||
|
- pull_request
|
||||||
|
- push
|
||||||
|
- workflow_dispatch
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check_lint:
|
||||||
|
name: Check, lint and test
|
||||||
|
runs-on: debian-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install stable toolchain
|
||||||
|
uses: https://github.com/actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Use sparse Cargo index for crates.io
|
||||||
|
run: echo -e '[registries.crates-io]\nprotocol = "sparse"' >> /root/.cargo/config.toml
|
||||||
|
|
||||||
|
- name: Run cargo check
|
||||||
|
uses: https://github.com/actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: check
|
||||||
|
|
||||||
|
- name: Run cargo clippy
|
||||||
|
uses: https://github.com/actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: -- -D warnings
|
||||||
|
|
||||||
|
- name: Run cargo fmt
|
||||||
|
uses: https://github.com/actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
|
|
||||||
|
- name: Run cargo test
|
||||||
|
uses: https://github.com/actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --all-features
|
|
@ -0,0 +1,75 @@
|
||||||
|
name: "Release"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: "Release"
|
||||||
|
runs-on: debian-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Determine the version of the release
|
||||||
|
run: |
|
||||||
|
VERSION=${GITHUB_REF_NAME#v}
|
||||||
|
echo "Releasing version: $VERSION"
|
||||||
|
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Get the release notes from the changelog
|
||||||
|
run: |
|
||||||
|
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)
|
||||||
|
RELEASE_NOTES=$(sed -n -e "/^## \[$VERSION\]/,/^## \[/{//"'!'"p;}" CHANGELOG.md | sed -e '1d;$d')
|
||||||
|
echo "Release notes:"
|
||||||
|
echo
|
||||||
|
echo "$RELEASE_NOTES"
|
||||||
|
echo "RELEASE_NOTES<<$EOF" >> "$GITHUB_ENV"
|
||||||
|
echo "$RELEASE_NOTES" >> "$GITHUB_ENV"
|
||||||
|
echo "$EOF" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Install Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '>=1.20.1'
|
||||||
|
|
||||||
|
- name: Release to Gitea
|
||||||
|
uses: actions/release-action@main
|
||||||
|
with:
|
||||||
|
# This is available by default.
|
||||||
|
api_key: '${{ secrets.RELEASE_TOKEN }}'
|
||||||
|
files: FIXME
|
||||||
|
title: 'Release ${{ env.VERSION }}'
|
||||||
|
body: '${{ env.RELEASE_NOTES }}'
|
||||||
|
|
||||||
|
release-crate:
|
||||||
|
name: "Release crate"
|
||||||
|
runs-on: debian-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout sources
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install Rust stable toolchain
|
||||||
|
uses: https://github.com/actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: stable
|
||||||
|
override: true
|
||||||
|
|
||||||
|
- name: Register the Gitea crate registry with Cargo
|
||||||
|
run: echo -e '[registries.luon]\nindex = "https://git.luon.net/paul/_cargo-index.git"' >> /root/.cargo/config.toml
|
||||||
|
|
||||||
|
- name: Run cargo publish
|
||||||
|
uses: https://github.com/actions-rs/cargo@v1
|
||||||
|
env:
|
||||||
|
# This needs to be provided for the repository; no login necessary as a result.
|
||||||
|
CARGO_REGISTRIES_LUON_TOKEN: '${{ secrets.CARGO_TOKEN }}'
|
||||||
|
with:
|
||||||
|
command: publish
|
||||||
|
args: --registry luon
|
|
@ -1,2 +1,4 @@
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
.vim
|
||||||
|
.vscode
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to geo-uri-rs will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [0.2.2] - 2024-04-03
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Bumped dependency on `derive_builder` crate
|
||||||
|
|
||||||
|
## [0.2.1] - 2023-03-11
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Bumped dependency on `derive_builder` crate
|
||||||
|
* Use `assert_eq` for float tests; drop dev depend on `float_eq` crate
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fix doclinks in README
|
||||||
|
* Fix docs.rs metadata section name in `Cargo.toml`
|
||||||
|
|
||||||
|
## [0.2.0] - 2022-10-01
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Add support for converting from/to `Url` structs (#1)
|
||||||
|
* Add support for (de)serializing via serde (#2)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fix documentation and comment types and improve examples
|
||||||
|
* Make the crate adhere to the [Rust API guidelines](https://rust-lang.github.io/api-guidelines/)
|
||||||
|
|
||||||
|
## [0.1.1] - 2022-09-30
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Update examples in `README.md`
|
||||||
|
* Add some more fields to `Cargo.toml`
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Fix some small errors in the documentation
|
||||||
|
|
||||||
|
[Unreleased]: https://git.luon.net/paul/geo-uri-rs/compare/v0.2.2...HEAD
|
||||||
|
[0.2.2]: https://git.luon.net/paul/geo-uri-rs/compare/v0.2.1..v0.2.2
|
||||||
|
[0.2.1]: https://git.luon.net/paul/geo-uri-rs/compare/v0.2.0..v0.2.1
|
||||||
|
[0.2.0]: https://git.luon.net/paul/geo-uri-rs/compare/v0.1.1..v0.2.0
|
||||||
|
[0.1.1]: https://git.luon.net/paul/geo-uri-rs/commits/tag/v0.1.1
|
23
Cargo.toml
23
Cargo.toml
|
@ -1,15 +1,30 @@
|
||||||
[package]
|
[package]
|
||||||
name = "geo-uri"
|
name = "geo-uri"
|
||||||
version = "0.1.0"
|
version = "0.2.2"
|
||||||
authors = ["Paul van Tilburg <paul@luon.net>"]
|
authors = ["Paul van Tilburg <paul@luon.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
description = "A Rust crate for parsing uniform resource identifiers for geographic locations (geo URIs)"
|
rust-version = "1.60.0"
|
||||||
|
description = "A crate for parsing and generating uniform resource identifiers for geographic locations (geo URIs)"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
repository = "https://git.luon.net/paul/geo-uri-rs"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
keywords = ["geolocation", "uri", "parser", "rfc5870"]
|
||||||
|
categories = ["parser-implementations", "web-programming", "encoding"]
|
||||||
|
include = ["CHANGELOG.md", "LICENSE", "README.md", "src/*.rs"]
|
||||||
|
|
||||||
|
[package.metadata."docs.rs"]
|
||||||
|
all-features = true
|
||||||
|
rustdoc-args = ["--cfg", "docsrs"]
|
||||||
|
|
||||||
|
[features]
|
||||||
|
url = ["dep:url"]
|
||||||
|
serde = ["dep:serde"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
derive_builder = "0.11.2"
|
derive_builder = "0.20.0"
|
||||||
|
serde = { version = "1.0.145", optional = true }
|
||||||
thiserror = "1.0.35"
|
thiserror = "1.0.35"
|
||||||
|
url = { version = "2.3.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
float_eq = "1.0.0"
|
serde_test = "1.0.145"
|
||||||
|
|
95
README.md
95
README.md
|
@ -1,9 +1,8 @@
|
||||||
t# geo-uri-rs
|
# geo-uri-rs
|
||||||
|
|
||||||
A Rust crate (`geo-uri`) for uniform resource identifiers for geographic
|
A Rust crate for uniform resource identifiers for geographic locations (geo
|
||||||
locations (geo URIs) according to
|
URIs) according to IEEE [RFC 5870](https://www.rfc-editor.org/rfc/rfc5870).
|
||||||
IEEE RFC [5870](https://www.rfc-editor.org/rfc/rfc5870).
|
This crate supports parsing and generating geo URIs in the correct format.
|
||||||
This crate allows for parsing and generating geo URIs in the correct format.
|
|
||||||
Its parser is currently somewhat more liberal than the proposed standard.
|
Its parser is currently somewhat more liberal than the proposed standard.
|
||||||
|
|
||||||
It supports geolocations specified by latitude and longitude, but also
|
It supports geolocations specified by latitude and longitude, but also
|
||||||
|
@ -18,23 +17,29 @@ Just run the following to add this library to your project:
|
||||||
```sh
|
```sh
|
||||||
$ cargo add geo-uri
|
$ cargo add geo-uri
|
||||||
Updating crates.io index
|
Updating crates.io index
|
||||||
Adding thiserror v??? to dependencies.
|
Adding geo-uri vX.Y.Z to dependencies.
|
||||||
```
|
```
|
||||||
|
|
||||||
### Parsing
|
### Parsing
|
||||||
|
|
||||||
Use either the [`FromStr`](std::str::FromStr) or
|
Use either the [`TryFrom`](std::convert::TryFrom) trait or the
|
||||||
[`TryFrom`](std::convert::TryFrom) traits to parse a geo URI string:
|
[`parse`](str::parse) method on strings to parse a geo URI string into a
|
||||||
|
[`GeoUri`](GeoUri) struct:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use geo_uri::GeoUri;
|
use geo_uri::GeoUri;
|
||||||
|
|
||||||
let geo_uri = GeoUri::try_from("geo:52.107,5.134,3.6;u=1000");
|
let geo_uri = GeoUri::try_from("geo:52.107,5.134,3.6;u=1000").expect("valid geo URI");
|
||||||
assert!(geo_uri.is_ok());
|
assert_eq!(geo_uri.latitude(), 52.107);
|
||||||
|
assert_eq!(geo_uri.longitude(), 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude(), Some(3.6));
|
||||||
|
assert_eq!(geo_uri.uncertainty(), Some(1000.0));
|
||||||
|
|
||||||
use std::str::FromStr;
|
let geo_uri: GeoUri = "geo:52.107,5.134;u=2000.0".parse().expect("valid geo URI");
|
||||||
let geo_uri2 = GeoUri::from_str("geo:52.107,5.134;u=2000.0");
|
assert_eq!(geo_uri.latitude(), 52.107);
|
||||||
assert!(geo_uri2.is_ok());
|
assert_eq!(geo_uri.longitude(), 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude(), None);
|
||||||
|
assert_eq!(geo_uri.uncertainty(), Some(2000.0));
|
||||||
```
|
```
|
||||||
|
|
||||||
It is also possible to call the parse function directly:
|
It is also possible to call the parse function directly:
|
||||||
|
@ -42,14 +47,18 @@ It is also possible to call the parse function directly:
|
||||||
```rust
|
```rust
|
||||||
use geo_uri::GeoUri;
|
use geo_uri::GeoUri;
|
||||||
|
|
||||||
let geo_uri3 = GeoUri::parse("geo:52.107,5.134,3.6;u=1000");
|
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6").expect("valid geo URI");
|
||||||
assert!(geo_uri3.is_ok());
|
assert_eq!(geo_uri.latitude(), 52.107);
|
||||||
|
assert_eq!(geo_uri.longitude(), 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude(), Some(3.6));
|
||||||
|
assert_eq!(geo_uri.uncertainty(), None);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Generating
|
### Generating
|
||||||
|
|
||||||
Use either the [`ToString`](std::string::ToString) or
|
Use the [`GeoUriBuilder`](GeoUriBuilder) to construct a [`GeoUri`](GeoUri)
|
||||||
[`Display`](std::fmt::Display) trait to generate an geo URI after building it:
|
struct. Then, use either the [`ToString`](std::string::ToString) or
|
||||||
|
[`Display`](std::fmt::Display) trait to generate a geo URI string:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use geo_uri::GeoUri;
|
use geo_uri::GeoUri;
|
||||||
|
@ -60,6 +69,7 @@ let geo_uri = GeoUri::builder()
|
||||||
.uncertainty(1_000.0)
|
.uncertainty(1_000.0)
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
geo_uri.to_string(),
|
geo_uri.to_string(),
|
||||||
String::from("geo:52.107,5.134;u=1000")
|
String::from("geo:52.107,5.134;u=1000")
|
||||||
|
@ -70,6 +80,57 @@ assert_eq!(
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It is also possible to construct a [`GeoUri`](GeoUri) struct from coordinate
|
||||||
|
tuples using the [`TryFrom`](std::convert::TryFrom) trait:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use geo_uri::GeoUri;
|
||||||
|
|
||||||
|
let geo_uri = GeoUri::try_from((52.107, 5.134)).expect("valid coordinates");
|
||||||
|
let geo_uri = GeoUri::try_from((52.107, 5.134, 3.6)).expect("valid coordinates");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Feature: `url`
|
||||||
|
|
||||||
|
You can enable the `url` feature to convert from and to
|
||||||
|
[`Url`](https://docs.rs/url/2/url/struct.Url.html) structs from the
|
||||||
|
[`url`](https://docs.rs/url/2/url) crate.
|
||||||
|
|
||||||
|
Enable the feature in your `Cargo.toml` first:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
geo-uri = { version = "X.Y.Z", features = ["url"] }
|
||||||
|
```
|
||||||
|
|
||||||
|
Then you can do:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use geo_uri::GeoUri;
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
|
let url = Url::parse("geo:52.107,5.134,3.6").expect("valid URL");
|
||||||
|
let geo_uri = GeoUri::try_from(&url).expect("valid geo URI");
|
||||||
|
let geo_url = Url::from(geo_uri);
|
||||||
|
|
||||||
|
assert_eq!(url, geo_url);
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that it is always possible to transform a [`GeoUri`](GeoUri) into an
|
||||||
|
[`Url`](https://docs.rs/url/2/url/struct.Url.html), but not always the other
|
||||||
|
way around! This is because the format of the coordinates and parameters after
|
||||||
|
the URI scheme "geo:" may be invalid!
|
||||||
|
|
||||||
|
### Feature: `serde`
|
||||||
|
|
||||||
|
If you enable the `serde` feature, [`GeoUri`](GeoUri) will implement
|
||||||
|
[`serde::Serialize`](https://docs.rs/serde/1/serde/trait.Serialize.html) and
|
||||||
|
[`serde::Deserialize`](https://docs.rs/serde/1/serde/trait.Deserialize.html).
|
||||||
|
See the [serde](https://serde.rs) documentation for more information.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
geo-uri = { version = "X.Y.Z", features = ["serde"] }
|
||||||
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
geo-uri-rs is licensed under the MIT license (see the `LICENSE` file or
|
geo-uri-rs is licensed under the MIT license (see the `LICENSE` file or
|
||||||
|
|
403
src/lib.rs
403
src/lib.rs
|
@ -1,3 +1,4 @@
|
||||||
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
#![doc = include_str!("../README.md")]
|
#![doc = include_str!("../README.md")]
|
||||||
#![warn(
|
#![warn(
|
||||||
clippy::all,
|
clippy::all,
|
||||||
|
@ -20,7 +21,14 @@ use std::num::ParseFloatError;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use derive_builder::Builder;
|
use derive_builder::Builder;
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde::{
|
||||||
|
de::{Deserialize, Visitor},
|
||||||
|
ser::Serialize,
|
||||||
|
};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
use url::Url;
|
||||||
|
|
||||||
/// The scheme name of a geo URI.
|
/// The scheme name of a geo URI.
|
||||||
const URI_SCHEME_NAME: &str = "geo";
|
const URI_SCHEME_NAME: &str = "geo";
|
||||||
|
@ -90,7 +98,7 @@ pub enum CoordRefSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CoordRefSystem {
|
impl CoordRefSystem {
|
||||||
/// Validates geo location coordinates against the selected coordinate reference system.
|
/// Validates geolocation coordinates against the selected coordinate reference system.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
|
@ -107,6 +115,11 @@ impl CoordRefSystem {
|
||||||
/// Err(Error::OutOfRangeLongitude)
|
/// Err(Error::OutOfRangeLongitude)
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// An error is returned if the latitude/longitude is out of range with respect to the
|
||||||
|
/// coordinate reference system.
|
||||||
pub fn validate(&self, latitude: f64, longitude: f64) -> Result<(), Error> {
|
pub fn validate(&self, latitude: f64, longitude: f64) -> Result<(), Error> {
|
||||||
// This holds only for WGS-84, but it is the only one supported right now!
|
// This holds only for WGS-84, but it is the only one supported right now!
|
||||||
if !(-90.0..=90.0).contains(&latitude) {
|
if !(-90.0..=90.0).contains(&latitude) {
|
||||||
|
@ -138,36 +151,47 @@ impl Default for CoordRefSystem {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use geo_uri::GeoUri;
|
/// use geo_uri::GeoUri;
|
||||||
|
/// # use geo_uri::Error;
|
||||||
///
|
///
|
||||||
/// let geo_uri = GeoUri::try_from("geo:52.107,5.134,3.6;u=1000").expect("valid geo URI");
|
/// # fn main() -> Result<(), Error> {
|
||||||
|
/// let geo_uri = GeoUri::try_from("geo:52.107,5.134,3.6;u=1000")?;
|
||||||
/// assert_eq!(geo_uri.latitude(), 52.107);
|
/// assert_eq!(geo_uri.latitude(), 52.107);
|
||||||
/// assert_eq!(geo_uri.longitude(), 5.134);
|
/// assert_eq!(geo_uri.longitude(), 5.134);
|
||||||
/// assert_eq!(geo_uri.altitude(), Some(3.6));
|
/// assert_eq!(geo_uri.altitude(), Some(3.6));
|
||||||
/// assert_eq!(geo_uri.uncertainty(), Some(1000.0));
|
/// assert_eq!(geo_uri.uncertainty(), Some(1000.0));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// or by using the [`TryFrom`] trait:
|
/// or by calling the [`parse`](str::parse) method on a string (using the [`TryFrom`] trait):
|
||||||
/// ```
|
/// ```
|
||||||
/// use geo_uri::GeoUri;
|
/// use geo_uri::GeoUri;
|
||||||
/// use std::str::FromStr;
|
/// # use geo_uri::Error;
|
||||||
///
|
///
|
||||||
/// let geo_uri = GeoUri::from_str("geo:52.107,5.134;u=2000.0").expect("valid geo URI");
|
/// # fn main() -> Result<(), Error> {
|
||||||
|
/// let geo_uri: GeoUri = "geo:52.107,5.134;u=2000.0".parse()?;
|
||||||
/// assert_eq!(geo_uri.latitude(), 52.107);
|
/// assert_eq!(geo_uri.latitude(), 52.107);
|
||||||
/// assert_eq!(geo_uri.longitude(), 5.134);
|
/// assert_eq!(geo_uri.longitude(), 5.134);
|
||||||
/// assert_eq!(geo_uri.altitude(), None);
|
/// assert_eq!(geo_uri.altitude(), None);
|
||||||
/// assert_eq!(geo_uri.uncertainty(), Some(2000.0));
|
/// assert_eq!(geo_uri.uncertainty(), Some(2000.0));
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// It is also possible to call the parse function directly:
|
/// It is also possible to call the parse function directly:
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use geo_uri::GeoUri;
|
/// use geo_uri::GeoUri;
|
||||||
|
/// # use geo_uri::Error;
|
||||||
///
|
///
|
||||||
/// let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6").expect("valid geo URI");
|
/// # fn main() -> Result<(), Error> {
|
||||||
|
/// let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6")?;
|
||||||
/// assert_eq!(geo_uri.latitude(), 52.107);
|
/// assert_eq!(geo_uri.latitude(), 52.107);
|
||||||
/// assert_eq!(geo_uri.longitude(), 5.134);
|
/// assert_eq!(geo_uri.longitude(), 5.134);
|
||||||
/// assert_eq!(geo_uri.altitude(), Some(3.6));
|
/// assert_eq!(geo_uri.altitude(), Some(3.6));
|
||||||
/// assert_eq!(geo_uri.uncertainty(), None);
|
/// assert_eq!(geo_uri.uncertainty(), None);
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## Generating
|
/// ## Generating
|
||||||
|
@ -176,13 +200,14 @@ impl Default for CoordRefSystem {
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// use geo_uri::GeoUri;
|
/// use geo_uri::GeoUri;
|
||||||
|
/// # use geo_uri::GeoUriBuilderError;
|
||||||
///
|
///
|
||||||
|
/// # fn main() -> Result<(), GeoUriBuilderError> {
|
||||||
/// let geo_uri = GeoUri::builder()
|
/// let geo_uri = GeoUri::builder()
|
||||||
/// .latitude(52.107)
|
/// .latitude(52.107)
|
||||||
/// .longitude(5.134)
|
/// .longitude(5.134)
|
||||||
/// .uncertainty(1_000.0)
|
/// .uncertainty(1_000.0)
|
||||||
/// .build()
|
/// .build()?;
|
||||||
/// .unwrap();
|
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// geo_uri.to_string(),
|
/// geo_uri.to_string(),
|
||||||
/// String::from("geo:52.107,5.134;u=1000")
|
/// String::from("geo:52.107,5.134;u=1000")
|
||||||
|
@ -191,6 +216,18 @@ impl Default for CoordRefSystem {
|
||||||
/// format!("{geo_uri}"),
|
/// format!("{geo_uri}"),
|
||||||
/// String::from("geo:52.107,5.134;u=1000")
|
/// String::from("geo:52.107,5.134;u=1000")
|
||||||
/// );
|
/// );
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// It is also possible to construct a [`GeoUri`] struct from coordinate tuples
|
||||||
|
/// using the [`TryFrom`](std::convert::TryFrom) trait:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use geo_uri::GeoUri;
|
||||||
|
///
|
||||||
|
/// let geo_uri = GeoUri::try_from((52.107, 5.134)).expect("valid coordinates");
|
||||||
|
/// let geo_uri = GeoUri::try_from((52.107, 5.134, 3.6)).expect("valid coordinates");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # See also
|
/// # See also
|
||||||
|
@ -236,6 +273,10 @@ impl GeoUri {
|
||||||
///
|
///
|
||||||
/// For the geo URI scheme syntax, see the propsed IEEE standard
|
/// For the geo URI scheme syntax, see the propsed IEEE standard
|
||||||
/// [RFC 5870](https://www.rfc-editor.org/rfc/rfc5870#section-3.3).
|
/// [RFC 5870](https://www.rfc-editor.org/rfc/rfc5870#section-3.3).
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Will return an error if the parsing fails in any way.
|
||||||
pub fn parse(uri: &str) -> Result<Self, Error> {
|
pub fn parse(uri: &str) -> Result<Self, Error> {
|
||||||
let uri = uri.to_ascii_lowercase();
|
let uri = uri.to_ascii_lowercase();
|
||||||
let uri_path = uri.strip_prefix("geo:").ok_or(Error::MissingScheme)?;
|
let uri_path = uri.strip_prefix("geo:").ok_or(Error::MissingScheme)?;
|
||||||
|
@ -293,22 +334,17 @@ impl GeoUri {
|
||||||
Some(_) | None => (CoordRefSystem::default(), None),
|
Some(_) | None => (CoordRefSystem::default(), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate the parsed values.
|
// Validate the geo URI before returning it.
|
||||||
crs.validate(latitude, longitude)?;
|
let geo_uri = GeoUri {
|
||||||
// FIXME: Move this into the validator? This code is duplicate now.
|
|
||||||
if let Some(unc) = uncertainty {
|
|
||||||
if unc < 0.0 {
|
|
||||||
return Err(Error::OutOfRangeUncertainty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(GeoUri {
|
|
||||||
crs,
|
crs,
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
altitude,
|
altitude,
|
||||||
uncertainty,
|
uncertainty,
|
||||||
})
|
};
|
||||||
|
geo_uri.validate()?;
|
||||||
|
|
||||||
|
Ok(geo_uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the latitude coordinate.
|
/// Returns the latitude coordinate.
|
||||||
|
@ -318,7 +354,10 @@ impl GeoUri {
|
||||||
|
|
||||||
/// Changes the latitude coordinate.
|
/// Changes the latitude coordinate.
|
||||||
///
|
///
|
||||||
/// The latitude may be out of range for the coordinate reference system.
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the latitude is out of range for the coordinate reference system, an error will be
|
||||||
|
/// returned.
|
||||||
pub fn set_latitude(&mut self, latitude: f64) -> Result<(), Error> {
|
pub fn set_latitude(&mut self, latitude: f64) -> Result<(), Error> {
|
||||||
self.crs.validate(latitude, self.longitude)?;
|
self.crs.validate(latitude, self.longitude)?;
|
||||||
self.latitude = latitude;
|
self.latitude = latitude;
|
||||||
|
@ -333,7 +372,10 @@ impl GeoUri {
|
||||||
|
|
||||||
/// Changes the longitude coordinate.
|
/// Changes the longitude coordinate.
|
||||||
///
|
///
|
||||||
/// The longitude may be out of range for the coordinate reference system.
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the longitude is out of range for the coordinate reference system, an error will be
|
||||||
|
/// returned.
|
||||||
pub fn set_longitude(&mut self, longitude: f64) -> Result<(), Error> {
|
pub fn set_longitude(&mut self, longitude: f64) -> Result<(), Error> {
|
||||||
self.crs.validate(self.latitude, longitude)?;
|
self.crs.validate(self.latitude, longitude)?;
|
||||||
self.longitude = longitude;
|
self.longitude = longitude;
|
||||||
|
@ -358,7 +400,9 @@ impl GeoUri {
|
||||||
|
|
||||||
/// Changes the uncertainty around the location.
|
/// Changes the uncertainty around the location.
|
||||||
///
|
///
|
||||||
/// The uncertainty distance must be positive.
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the uncertainty distance is not zero or positive, an error will be returned.
|
||||||
pub fn set_uncertainty(&mut self, uncertainty: Option<f64>) -> Result<(), Error> {
|
pub fn set_uncertainty(&mut self, uncertainty: Option<f64>) -> Result<(), Error> {
|
||||||
if let Some(unc) = uncertainty {
|
if let Some(unc) = uncertainty {
|
||||||
if unc < 0.0 {
|
if unc < 0.0 {
|
||||||
|
@ -369,6 +413,59 @@ impl GeoUri {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Validates the coordinates.
|
||||||
|
///
|
||||||
|
/// This is only meant for internal use to prevent returning [`GeoUri`] objects that are
|
||||||
|
/// actually invalid.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the current latitude/longitude is invalid with respect to the current
|
||||||
|
/// coordinate reference system, or if the uncertainy, if set, is not zero or positive.
|
||||||
|
fn validate(&self) -> Result<(), Error> {
|
||||||
|
// Validate the latitude/longitude against the coordinate refrence system.
|
||||||
|
self.crs.validate(self.latitude, self.longitude)?;
|
||||||
|
|
||||||
|
// Ensure that the uncertainty is not negatify, if set.
|
||||||
|
if let Some(unc) = self.uncertainty {
|
||||||
|
if unc < 0.0 {
|
||||||
|
return Err(Error::OutOfRangeUncertainty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
struct GeoUriVisitor;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
impl<'de> Visitor<'de> for GeoUriVisitor {
|
||||||
|
type Value = GeoUri;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(formatter, "a string starting with {URI_SCHEME_NAME}:")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
|
GeoUri::parse(v).map_err(E::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
||||||
|
impl<'de> Deserialize<'de> for GeoUri {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(GeoUriVisitor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for GeoUri {
|
impl fmt::Display for GeoUri {
|
||||||
|
@ -393,6 +490,22 @@ impl fmt::Display for GeoUri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
|
||||||
|
impl From<&GeoUri> for Url {
|
||||||
|
fn from(geo_uri: &GeoUri) -> Self {
|
||||||
|
Url::parse(&geo_uri.to_string()).expect("valid URL")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
|
||||||
|
impl From<GeoUri> for Url {
|
||||||
|
fn from(geo_uri: GeoUri) -> Self {
|
||||||
|
Url::from(&geo_uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl FromStr for GeoUri {
|
impl FromStr for GeoUri {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
|
|
||||||
|
@ -401,6 +514,17 @@ impl FromStr for GeoUri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
||||||
|
impl Serialize for GeoUri {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for GeoUri {
|
impl TryFrom<&str> for GeoUri {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
|
@ -409,6 +533,57 @@ impl TryFrom<&str> for GeoUri {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFrom<(f64, f64)> for GeoUri {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from((latitude, longitude): (f64, f64)) -> Result<Self, Self::Error> {
|
||||||
|
let geo_uri = GeoUri {
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
geo_uri.validate()?;
|
||||||
|
|
||||||
|
Ok(geo_uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<(f64, f64, f64)> for GeoUri {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from((latitude, longitude, altitude): (f64, f64, f64)) -> Result<Self, Self::Error> {
|
||||||
|
let geo_uri = GeoUri {
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
altitude: Some(altitude),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
geo_uri.validate()?;
|
||||||
|
|
||||||
|
Ok(geo_uri)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
|
||||||
|
impl TryFrom<&Url> for GeoUri {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(url: &Url) -> Result<Self, Self::Error> {
|
||||||
|
GeoUri::parse(url.as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
#[cfg_attr(docsrs, doc(cfg(feature = "url")))]
|
||||||
|
impl TryFrom<Url> for GeoUri {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(url: Url) -> Result<Self, Self::Error> {
|
||||||
|
GeoUri::try_from(&url)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for GeoUri {
|
impl PartialEq for GeoUri {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// In the WGS-84 CRS the the longitude is ignored for the poles.
|
// In the WGS-84 CRS the the longitude is ignored for the poles.
|
||||||
|
@ -424,6 +599,10 @@ impl PartialEq for GeoUri {
|
||||||
|
|
||||||
impl GeoUriBuilder {
|
impl GeoUriBuilder {
|
||||||
/// Validates the coordinates against the
|
/// Validates the coordinates against the
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns an error if the the currently configured coordinate values are invalid.
|
||||||
fn validate(&self) -> Result<(), String> {
|
fn validate(&self) -> Result<(), String> {
|
||||||
self.crs
|
self.crs
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
|
@ -445,7 +624,8 @@ impl GeoUriBuilder {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use float_eq::assert_float_eq;
|
#[cfg(feature = "serde")]
|
||||||
|
use serde_test::{assert_de_tokens_error, assert_tokens, Token};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -481,8 +661,8 @@ mod tests {
|
||||||
|
|
||||||
builder.longitude(5.134);
|
builder.longitude(5.134);
|
||||||
let geo_uri = builder.build()?;
|
let geo_uri = builder.build()?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_eq!(geo_uri.altitude, None);
|
assert_eq!(geo_uri.altitude, None);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
|
@ -498,14 +678,20 @@ mod tests {
|
||||||
Err(GeoUriBuilderError::ValidationError(_))
|
Err(GeoUriBuilderError::ValidationError(_))
|
||||||
));
|
));
|
||||||
|
|
||||||
|
builder.longitude(5.134).uncertainty(-200.0);
|
||||||
|
assert!(matches!(
|
||||||
|
builder.build(),
|
||||||
|
Err(GeoUriBuilderError::ValidationError(_))
|
||||||
|
));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn geo_uri_parse() -> Result<(), Error> {
|
fn geo_uri_parse() -> Result<(), Error> {
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.134")?;
|
let geo_uri = GeoUri::parse("geo:52.107,5.134")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_eq!(geo_uri.altitude, None);
|
assert_eq!(geo_uri.altitude, None);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
|
@ -540,9 +726,9 @@ mod tests {
|
||||||
assert!(matches!(geo_uri, Err(Error::InvalidCoord(_))));
|
assert!(matches!(geo_uri, Err(Error::InvalidCoord(_))));
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6")?;
|
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_float_eq!(geo_uri.altitude.unwrap(), 3.6, abs <= 0.1);
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.34,3.6;u=");
|
let geo_uri = GeoUri::parse("geo:52.107,5.34,3.6;u=");
|
||||||
|
@ -558,24 +744,24 @@ mod tests {
|
||||||
assert!(matches!(geo_uri, Err(Error::OutOfRangeUncertainty)));
|
assert!(matches!(geo_uri, Err(Error::OutOfRangeUncertainty)));
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;u=25000")?;
|
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;u=25000")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_float_eq!(geo_uri.altitude.unwrap(), 3.6, abs <= 0.1);
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;crs=wgs84;u=25000")?;
|
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;crs=wgs84;u=25000")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_float_eq!(geo_uri.altitude.unwrap(), 3.6, abs <= 0.1);
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;CRS=wgs84;U=25000")?;
|
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;CRS=wgs84;U=25000")?;
|
||||||
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;crs=wgs84;u=25000;foo=bar")?;
|
let geo_uri = GeoUri::parse("geo:52.107,5.134,3.6;crs=wgs84;u=25000;foo=bar")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_float_eq!(geo_uri.altitude.unwrap(), 3.6, abs <= 0.1);
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
assert_eq!(geo_uri.uncertainty, Some(25_000.0));
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:52.107,5.34,3.6;crs=foo");
|
let geo_uri = GeoUri::parse("geo:52.107,5.34,3.6;crs=foo");
|
||||||
|
@ -586,21 +772,21 @@ mod tests {
|
||||||
|
|
||||||
// Examples from RFC 5870 (sections 1, 6.1, 6.2 and 9.4)!
|
// Examples from RFC 5870 (sections 1, 6.1, 6.2 and 9.4)!
|
||||||
let geo_uri = GeoUri::parse("geo:13.4125,103.8667")?;
|
let geo_uri = GeoUri::parse("geo:13.4125,103.8667")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 13.4125, abs <= 0.0001);
|
assert_eq!(geo_uri.latitude, 13.4125);
|
||||||
assert_float_eq!(geo_uri.longitude, 103.8667, abs <= 0.0001);
|
assert_eq!(geo_uri.longitude, 103.8667);
|
||||||
assert_eq!(geo_uri.altitude, None);
|
assert_eq!(geo_uri.altitude, None);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:48.2010,16.3695,183")?;
|
let geo_uri = GeoUri::parse("geo:48.2010,16.3695,183")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 48.2010, abs <= 0.0001);
|
assert_eq!(geo_uri.latitude, 48.2010);
|
||||||
assert_float_eq!(geo_uri.longitude, 16.3695, abs <= 0.0001);
|
assert_eq!(geo_uri.longitude, 16.3695);
|
||||||
assert_float_eq!(geo_uri.altitude.unwrap(), 183.0, abs <= 0.1);
|
assert_eq!(geo_uri.altitude.unwrap(), 183.0);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
let geo_uri = GeoUri::parse("geo:48.198634,16.371648;crs=wgs84;u=40")?;
|
let geo_uri = GeoUri::parse("geo:48.198634,16.371648;crs=wgs84;u=40")?;
|
||||||
assert_eq!(geo_uri.crs, CoordRefSystem::Wgs84);
|
assert_eq!(geo_uri.crs, CoordRefSystem::Wgs84);
|
||||||
assert_float_eq!(geo_uri.latitude, 48.198634, abs <= 0.000001);
|
assert_eq!(geo_uri.latitude, 48.198634);
|
||||||
assert_float_eq!(geo_uri.longitude, 16.371648, abs <= 0.000001);
|
assert_eq!(geo_uri.longitude, 16.371648);
|
||||||
assert_eq!(geo_uri.altitude, None);
|
assert_eq!(geo_uri.altitude, None);
|
||||||
assert_eq!(geo_uri.uncertainty, Some(40.0));
|
assert_eq!(geo_uri.uncertainty, Some(40.0));
|
||||||
|
|
||||||
|
@ -610,6 +796,29 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn geo_uri_validate() {
|
||||||
|
let mut geo_uri = GeoUri {
|
||||||
|
crs: CoordRefSystem::Wgs84,
|
||||||
|
latitude: 52.107,
|
||||||
|
longitude: 5.134,
|
||||||
|
altitude: None,
|
||||||
|
uncertainty: None,
|
||||||
|
};
|
||||||
|
assert_eq!(geo_uri.validate(), Ok(()));
|
||||||
|
|
||||||
|
geo_uri.latitude = 100.0;
|
||||||
|
assert_eq!(geo_uri.validate(), Err(Error::OutOfRangeLatitude));
|
||||||
|
|
||||||
|
geo_uri.latitude = 52.107;
|
||||||
|
geo_uri.longitude = -200.0;
|
||||||
|
assert_eq!(geo_uri.validate(), Err(Error::OutOfRangeLongitude));
|
||||||
|
|
||||||
|
geo_uri.longitude = 5.134;
|
||||||
|
geo_uri.uncertainty = Some(-2000.0);
|
||||||
|
assert_eq!(geo_uri.validate(), Err(Error::OutOfRangeUncertainty));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn geo_uri_get_set() {
|
fn geo_uri_get_set() {
|
||||||
let mut geo_uri = GeoUri {
|
let mut geo_uri = GeoUri {
|
||||||
|
@ -664,25 +873,119 @@ mod tests {
|
||||||
assert_eq!(&geo_uri.to_string(), "geo:52.107,5.134,3.6;u=25000");
|
assert_eq!(&geo_uri.to_string(), "geo:52.107,5.134,3.6;u=25000");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
#[test]
|
||||||
|
fn geo_uri_from() {
|
||||||
|
let geo_uri = GeoUri {
|
||||||
|
crs: CoordRefSystem::Wgs84,
|
||||||
|
latitude: 52.107,
|
||||||
|
longitude: 5.134,
|
||||||
|
altitude: Some(3.6),
|
||||||
|
uncertainty: Some(1000.0),
|
||||||
|
};
|
||||||
|
let url = Url::from(&geo_uri);
|
||||||
|
assert_eq!(url.scheme(), "geo");
|
||||||
|
assert_eq!(url.path(), "52.107,5.134,3.6;u=1000");
|
||||||
|
|
||||||
|
let url = Url::from(geo_uri);
|
||||||
|
assert_eq!(url.scheme(), "geo");
|
||||||
|
assert_eq!(url.path(), "52.107,5.134,3.6;u=1000");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn geo_uri_from_str() -> Result<(), Error> {
|
fn geo_uri_from_str() -> Result<(), Error> {
|
||||||
let geo_uri = GeoUri::from_str("geo:52.107,5.134")?;
|
let geo_uri = GeoUri::from_str("geo:52.107,5.134")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_eq!(geo_uri.altitude, None);
|
assert_eq!(geo_uri.altitude, None);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
#[test]
|
||||||
|
fn geo_uri_serde() {
|
||||||
|
let geo_uri = GeoUri {
|
||||||
|
crs: CoordRefSystem::Wgs84,
|
||||||
|
latitude: 52.107,
|
||||||
|
longitude: 5.134,
|
||||||
|
altitude: Some(3.6),
|
||||||
|
uncertainty: Some(1000.0),
|
||||||
|
};
|
||||||
|
assert_tokens(&geo_uri, &[Token::String("geo:52.107,5.134,3.6;u=1000")]);
|
||||||
|
|
||||||
|
assert_de_tokens_error::<GeoUri>(
|
||||||
|
&[Token::I32(0)],
|
||||||
|
"invalid type: integer `0`, expected a string starting with geo:",
|
||||||
|
);
|
||||||
|
assert_de_tokens_error::<GeoUri>(
|
||||||
|
&[Token::String("geo:100.0,5.134,3.6")],
|
||||||
|
&format!("{}", Error::OutOfRangeLatitude),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn geo_uri_try_from() -> Result<(), Error> {
|
fn geo_uri_try_from() -> Result<(), Error> {
|
||||||
|
// &str
|
||||||
let geo_uri = GeoUri::try_from("geo:52.107,5.134")?;
|
let geo_uri = GeoUri::try_from("geo:52.107,5.134")?;
|
||||||
assert_float_eq!(geo_uri.latitude, 52.107, abs <= 0.001);
|
assert_eq!(geo_uri.latitude, 52.107);
|
||||||
assert_float_eq!(geo_uri.longitude, 5.134, abs <= 0.001);
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
assert_eq!(geo_uri.altitude, None);
|
assert_eq!(geo_uri.altitude, None);
|
||||||
assert_eq!(geo_uri.uncertainty, None);
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
|
// (f64, f64)
|
||||||
|
let geo_uri = GeoUri::try_from((51.107, 5.134))?;
|
||||||
|
assert_eq!(geo_uri.latitude, 51.107);
|
||||||
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude, None);
|
||||||
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
GeoUri::try_from((100.0, 5.134)),
|
||||||
|
Err(Error::OutOfRangeLatitude)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
GeoUri::try_from((51.107, -200.0)),
|
||||||
|
Err(Error::OutOfRangeLongitude)
|
||||||
|
);
|
||||||
|
|
||||||
|
// (f64, f64, f64)
|
||||||
|
let geo_uri = GeoUri::try_from((51.107, 5.134, 3.6))?;
|
||||||
|
assert_eq!(geo_uri.latitude, 51.107);
|
||||||
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
|
assert_eq!(geo_uri.uncertainty, None);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
GeoUri::try_from((100.0, 5.134, 3.6)),
|
||||||
|
Err(Error::OutOfRangeLatitude)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
GeoUri::try_from((51.107, -200.0, 3.6)),
|
||||||
|
Err(Error::OutOfRangeLongitude)
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "url")]
|
||||||
|
#[test]
|
||||||
|
fn geo_uri_try_from_url() -> Result<(), Error> {
|
||||||
|
// Url
|
||||||
|
let url = Url::parse("geo:51.107,5.134,3.6;crs=wgs84;u=1000;foo=bar").expect("valid URL");
|
||||||
|
let geo_uri = GeoUri::try_from(&url)?;
|
||||||
|
assert_eq!(geo_uri.latitude, 51.107);
|
||||||
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
|
assert_eq!(geo_uri.uncertainty, Some(1000.0));
|
||||||
|
|
||||||
|
let geo_uri = GeoUri::try_from(url)?;
|
||||||
|
assert_eq!(geo_uri.latitude, 51.107);
|
||||||
|
assert_eq!(geo_uri.longitude, 5.134);
|
||||||
|
assert_eq!(geo_uri.altitude.unwrap(), 3.6);
|
||||||
|
assert_eq!(geo_uri.uncertainty, Some(1000.0));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue