1use reqwest::blocking;
2use std::error::Error as StdError;
3use std::fmt;
4use std::result;
5use serde::{Serialize, Deserialize};
6
7const API_URL_SEARCH : &'static str = "https://api-adresse.data.gouv.fr/search/?q=";
8const API_URL_REVERSE : &'static str = "https://api-adresse.data.gouv.fr/reverse/?";
9
10#[derive(Debug)]
11pub enum Error {
12 HttpError,
13 GetTextError,
14 UnmarshalJsonError,
15}
16
17impl StdError for Error {}
18
19impl fmt::Display for Error {
20 fn fmt(&self, f: &mut fmt::Formatter <'_>) -> fmt::Result {
21 match &*self {
22 HttpError => write!(f, "Can't access to http://api-adresse.data.gouv.fr"),
23 GetTextError => write!(f, "Can't unmarshal data response to text"),
24 UnmarshalJsonError => write!(f, "Can't unmarshal text response to json")
25 }
26 }
27}
28
29#[derive(Serialize, Deserialize, Debug)]
30pub struct AddressResult {
31 pub r#type: String,
32 pub version: String,
33 pub features: Vec<Feature>
34}
35
36#[derive(Serialize, Deserialize, Debug)]
37pub struct Feature {
38 pub r#type: String,
39 pub geometry: Geometry,
40 pub properties: Properties
41}
42
43#[derive(Serialize, Deserialize, Debug)]
44pub struct Geometry {
45 pub r#type: String,
46 pub coordinates: Coordinates
47}
48
49#[derive(Serialize, Deserialize, Debug)]
50pub struct Coordinates {
51 #[serde(rename = "0")]
52 pub lat: f64,
53 #[serde(rename = "1")]
54 pub lon: f64
55}
56
57#[derive(Serialize, Deserialize, Debug)]
58pub struct Properties {
59 pub label: String,
60 pub score: f64,
61 pub housenumber: Option<String>,
62 pub id: String,
63 pub r#type: String,
64 pub x: f64,
65 pub y: f64,
66 pub importance: f64,
67 pub name: String,
68 pub postcode: String,
69 pub citycode: String,
70 pub context: String,
71 pub street: Option<String>
72}
73
74fn get_data(url: &str) -> Result<AddressResult, Error> {
75 let response = match blocking::get(url) {
76 Ok(value) => value,
77 _ => return Err(Error::HttpError)
78 };
79
80 let value = match response.text() {
81 Ok(value) => value,
82 _ => return Err(Error::GetTextError)
83 };
84
85 let data: AddressResult = match serde_json::from_str(&value) {
86 Ok(value) => value,
87 _ => return Err(Error::UnmarshalJsonError)
88 };
89 Ok(data)
90
91}
92
93pub fn get_address_info(search: &str) -> Result<AddressResult, Error> {
94 let url = format!("{}{}", API_URL_SEARCH, search);
95 get_data(&*url)
96}
97
98pub fn get_reverse_info(lon: f64, lat: f64) -> Result<AddressResult, Error> {
99 let url = format!("{}lon={}&lat={}", API_URL_REVERSE, lon, lat);
100 get_data(&*url)
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 #[test]
107 fn test_get_address_info() {
108 let result = get_address_info("200 Chemin de puy petit").unwrap();
109 assert_eq!(result.features[0].properties.postcode, "26270");
110 assert_eq!(result.features[0].properties.citycode, "26166");
111 }
112
113 #[test]
114 fn test_get_reverse_info() {
115 let result = get_reverse_info(2.37, 48.357).unwrap();
116 assert_eq!(result.features[0].properties.label, "23 Chemin de Pithiviers 91720 Prunay-sur-Essonne");
117 }
118}