Add support for serde (closes: #2)
* Introduce and document the `serde` feature * Implement `serde::Deserialize` and `serde::Serialize` for `GeoUri` * Add tests
This commit is contained in:
parent
a044ec3f22
commit
04198fbe62
|
@ -15,11 +15,14 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||
|
||||
[features]
|
||||
url = ["dep:url"]
|
||||
serde = ["dep:serde"]
|
||||
|
||||
[dependencies]
|
||||
derive_builder = "0.11.2"
|
||||
serde = { version = "1.0.145", optional = true }
|
||||
thiserror = "1.0.35"
|
||||
url = { version = "2.3.1", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
float_eq = "1.0.0"
|
||||
serde_test = "1.0.145"
|
||||
|
|
11
README.md
11
README.md
|
@ -119,6 +119,17 @@ Note that it is always possible to transform a [`GeoUri`] into an [`Url`], 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`] 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
|
||||
|
||||
geo-uri-rs is licensed under the MIT license (see the `LICENSE` file or
|
||||
|
|
74
src/lib.rs
74
src/lib.rs
|
@ -19,11 +19,16 @@
|
|||
use std::fmt;
|
||||
use std::num::ParseFloatError;
|
||||
use std::str::FromStr;
|
||||
#[cfg(feature = "url")]
|
||||
use url::Url;
|
||||
|
||||
use derive_builder::Builder;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{
|
||||
de::{Deserialize, Visitor},
|
||||
ser::Serialize,
|
||||
};
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "url")]
|
||||
use url::Url;
|
||||
|
||||
/// The scheme name of a geo URI.
|
||||
const URI_SCHEME_NAME: &str = "geo";
|
||||
|
@ -433,6 +438,36 @@ impl GeoUri {
|
|||
}
|
||||
}
|
||||
|
||||
#[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 {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self {
|
||||
|
@ -479,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 {
|
||||
type Error = Error;
|
||||
|
||||
|
@ -579,6 +625,8 @@ impl GeoUriBuilder {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use float_eq::assert_float_eq;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde_test::{assert_de_tokens_error, assert_tokens, Token};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -856,6 +904,28 @@ mod tests {
|
|||
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]
|
||||
fn geo_uri_try_from() -> Result<(), Error> {
|
||||
// &str
|
||||
|
|
Loading…
Reference in New Issue