google_places_api/endpoints/
find_place.rs

1use crate::types::constants::{Language, LocationBias, PlaceSearchPlace, PlaceSearchPlaceFields};
2use crate::types::FindPlaceSearchResult;
3use reqwest::Client;
4use std::collections::HashSet;
5
6pub struct FindPlace<'a> {
7    input: Option<String>,
8    input_type: Option<String>,
9    language: Option<Language>,
10    fields: Option<HashSet<PlaceSearchPlaceFields>>,
11    location_bias: Option<LocationBias>,
12    api_key: String,
13    client: &'a Client,
14    result: FindPlaceSearchResult,
15}
16
17impl<'a> FindPlace<'a> {
18    /// Construct a new `FindPlace` instance.
19    ///
20    /// # Arguments
21    ///
22    /// * `api_key` - The Google Places API key.
23    /// * `client` - The reqwest client instance.
24    ///
25    /// # Returns
26    ///
27    /// A new instance of `FindPlace`.
28    pub fn new(api_key: &str, client: &'a Client) -> Self {
29        Self {
30            input: None,
31            fields: None,
32            language: None,
33            location_bias: None,
34            input_type: None,
35            api_key: String::from(api_key),
36            client,
37            result: Default::default(),
38        }
39    }
40
41    /**
42    Assign the input string for a FindPlace call.
43
44    input -> The input text.
45    */
46    pub fn with_input(&mut self, input: &str) -> &mut FindPlace<'a> {
47        self.input = Some(String::from(input));
48        self
49    }
50
51    /**
52    Assign the fields for a FindPlace call.
53
54    fields -> The fields parameter.
55    */
56    pub fn with_fields(&mut self, fields: HashSet<PlaceSearchPlaceFields>) -> &mut FindPlace<'a> {
57        self.fields = Some(fields);
58        self
59    }
60
61    /**
62    Assign the language for a FindPlace call.
63
64    language -> The language parameter.
65    */
66    pub fn with_language(&mut self, language: Language) -> &mut FindPlace<'a> {
67        self.language = Some(language);
68        self
69    }
70
71    /**
72    Assign the location_bias for a FindPlace call.
73
74    location_bias -> The location_bias parameter.
75    */
76    pub fn with_location_bias(&mut self, location_bias: LocationBias) -> &mut FindPlace<'a> {
77        self.location_bias = Some(location_bias);
78        self
79    }
80
81    /**
82    Assign the input_type for a FindPlace call.
83
84    input_type -> The input_type parameter.
85    */
86    pub fn with_input_type(&mut self, input_type: &str) -> &mut FindPlace<'a> {
87        self.input_type = Some(String::from(input_type));
88        self
89    }
90
91    fn build_params(&self) -> Vec<(&'static str, String)> {
92        let mut params = vec![("key", self.api_key.clone())];
93
94        if let Some(input) = &self.input {
95            params.push(("input", input.clone()));
96        }
97
98        if let Some(fields) = &self.fields {
99            params.push((
100                "fields",
101                fields
102                    .iter()
103                    .map(|f| f.to_string())
104                    .collect::<Vec<_>>()
105                    .join(","),
106            ));
107        }
108
109        if let Some(language) = &self.language {
110            params.push(("language", language.to_string()));
111        }
112
113        if let Some(location_bias) = &self.location_bias {
114            params.push(("locationbias", location_bias.to_string()));
115        }
116
117        if let Some(input_type) = &self.input_type {
118            params.push(("inputtype", input_type.clone()));
119        }
120
121        params
122    }
123
124    /**
125    Execute the call in an asynchronous fashion.
126    */
127    pub async fn execute(&mut self) -> Option<&mut FindPlace<'a>> {
128        match (self.input.clone(), self.input_type.clone()) {
129            (Some(_), Some(_)) => {
130                let url = "https://maps.googleapis.com/maps/api/place/findplacefromtext/json";
131                let params = self.build_params();
132
133                let resp = self.client.get(url).query(&params).send().await.unwrap();
134
135                match resp.json::<FindPlaceSearchResult>().await {
136                    Ok(query_result) => {
137                        self.result = query_result;
138                        Some(self)
139                    }
140                    Err(err) => {
141                        println!("Error parsing response: {:?}", err);
142
143                        None
144                    }
145                }
146            }
147
148            _ => {panic!("Provide input and inputtype for find_place query!");}
149        }
150    }
151
152    /**
153    Execute the call in a blocking fashion.
154    */
155    #[cfg(feature = "blocking")]
156    pub fn execute_blocking(&mut self) -> Option<&mut FindPlace<'a>> {
157        tokio::runtime::Runtime::new()
158            .unwrap()
159            .block_on(self.execute())
160    }
161
162    /**
163    This function returns an iterator (FindPlaceIterator) over the places in a FindPlace object. The iterator is initialized to start at the first place (index 0).
164
165    It allows you to iterate over the places in the FindPlace result without having to manually keep track of the index.
166
167    For example, you can use it like this:
168    */
169    pub fn iter(&mut self) -> FindPlaceIterator<'_, 'a> {
170        FindPlaceIterator {
171            find_place: self,
172            current_index: 0,
173        }
174    }
175
176    /**
177    Retrieve the place at the specified index.
178
179    index -> The index of the place to retrieve.
180
181    Returns an `Option` with the place if it exists, or `None` if the index is out of range.
182    */
183    pub fn at(&self, index: usize) -> Option<&PlaceSearchPlace> {
184        self.result.places.get(index)
185    }
186    pub fn get_result(&self) -> FindPlaceSearchResult {
187        self.result.clone()
188    }
189}
190
191/**
192An iterator over the places in a FindPlace object.
193
194The iterator is initialized to start at the first place (index 0).
195
196It allows you to iterate over the places in the FindPlace result without having to manually keep track of the index.
197
198For example, you can use it like this:
199*/
200pub struct FindPlaceIterator<'a, 'b> {
201    find_place: &'b mut FindPlace<'a>,
202    current_index: usize,
203}
204
205impl<'a, 'b> Iterator for FindPlaceIterator<'a, 'b> {
206    type Item = &'b PlaceSearchPlace;
207
208    /// Advances the iterator and returns the next value.
209    ///
210    /// Returns `None` when iteration is finished.
211    ///
212    /// # Safety
213    ///
214    /// This function is unsafe because it uses `std::mem::transmute` to cast a reference to `PlaceSearchPlace` to a reference to `&'b PlaceSearchPlace`.
215    /// This is safe because the `FindPlaceIterator` is only ever created from a `&'b mut FindPlace<'a>`, so we know that the lifetime of the `FindPlace`
216    /// is at least as long as the lifetime of the `FindPlaceIterator`.
217    fn next(&mut self) -> Option<Self::Item> {
218        if self.current_index < self.find_place.result.places.len() {
219            let place = &self.find_place.result.places[self.current_index];
220            self.current_index += 1;
221            Some(unsafe { std::mem::transmute(place) })
222        } else {
223            None
224        }
225    }
226}