1use crate::ser::to_feature_writer;
2use crate::{Error, Feature, Result};
3
4use serde::Serialize;
5use std::io::Write;
6
7#[derive(PartialEq)]
8enum State {
9 New,
10 WritingFeatures,
11 WritingForeignMembers,
12 Finished,
13}
14
15pub struct FeatureWriter<W: Write> {
17 writer: W,
18 state: State,
19}
20
21impl<W: Write> FeatureWriter<W> {
22 pub fn from_writer(writer: W) -> Self {
31 Self {
32 writer,
33 state: State::New,
34 }
35 }
36
37 pub fn write_feature(&mut self, feature: &Feature) -> Result<()> {
40 match self.state {
41 State::Finished => {
42 return Err(Error::InvalidWriterState(
43 "cannot write another Feature when writer has already finished",
44 ))
45 }
46 State::New => {
47 self.write_prefix()?;
48 self.state = State::WritingFeatures;
49 }
50 State::WritingFeatures => {
51 self.write_str(",")?;
52 }
53 State::WritingForeignMembers => {
54 self.write_str(r#" "features": ["#)?;
55 self.state = State::WritingFeatures;
56 }
57 }
58 serde_json::to_writer(&mut self.writer, feature)?;
59 Ok(())
60 }
61
62 #[cfg_attr(feature = "geo-types", doc = "```")]
86 #[cfg_attr(not(feature = "geo-types"), doc = "```ignore")]
87 pub fn serialize<S: Serialize>(&mut self, value: &S) -> Result<()> {
161 match self.state {
162 State::Finished => {
163 return Err(Error::InvalidWriterState(
164 "cannot serialize another record when writer has already finished",
165 ))
166 }
167 State::New => {
168 self.write_prefix()?;
169 self.state = State::WritingFeatures;
170 }
171 State::WritingFeatures => {
172 self.write_str(",")?;
173 }
174 State::WritingForeignMembers => {
175 self.write_str(r#" "features": ["#)?;
176 self.state = State::WritingFeatures;
177 }
178 }
179 to_feature_writer(&mut self.writer, value)
180 }
181
182 pub fn write_foreign_member<T: ?Sized + Serialize>(
185 &mut self,
186 key: &str,
187 value: &T,
188 ) -> Result<()> {
189 match self.state {
190 State::Finished => Err(Error::InvalidWriterState(
191 "cannot write foreign member when writer has already finished",
192 )),
193 State::New => {
194 self.write_str(r#"{ "type": "FeatureCollection", "#)?;
195 write!(self.writer, "\"{key}\": ")?;
196 serde_json::to_writer(&mut self.writer, value)?;
197 self.write_str(",")?;
198
199 self.state = State::WritingForeignMembers;
200 Ok(())
201 }
202 State::WritingFeatures => Err(Error::InvalidWriterState(
203 "must write foreign members before any features",
204 )),
205 State::WritingForeignMembers => {
206 write!(self.writer, "\"{key}\": ")?;
207 serde_json::to_writer(&mut self.writer, value)?;
208 self.write_str(",")?;
209 Ok(())
210 }
211 }
212 }
213
214 pub fn finish(&mut self) -> Result<()> {
219 match self.state {
220 State::Finished => {
221 return Err(Error::InvalidWriterState(
222 "cannot finish writer - it's already finished",
223 ))
224 }
225 State::New => {
226 self.state = State::Finished;
227 self.write_prefix()?;
228 self.write_suffix()?;
229 }
230 State::WritingFeatures | State::WritingForeignMembers => {
231 self.state = State::Finished;
232 self.write_suffix()?;
233 }
234 }
235 Ok(())
236 }
237
238 pub fn flush(&mut self) -> Result<()> {
243 Ok(self.writer.flush()?)
244 }
245
246 fn write_prefix(&mut self) -> Result<()> {
247 self.write_str(r#"{ "type": "FeatureCollection", "features": ["#)
248 }
249
250 fn write_suffix(&mut self) -> Result<()> {
251 self.write_str("]}")
252 }
253
254 fn write_str(&mut self, text: &str) -> Result<()> {
255 self.writer.write_all(text.as_bytes())?;
256 Ok(())
257 }
258}
259
260impl<W: Write> Drop for FeatureWriter<W> {
261 fn drop(&mut self) {
262 if self.state != State::Finished {
263 _ = self.finish().map_err(|e| {
264 log::error!("FeatureWriter errored while finishing in Drop impl. To handle errors like this, explicitly call `FeatureWriter::finish`. Error: {}", e);
265 });
266 }
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273 use crate::JsonValue;
274
275 use serde_json::json;
276
277 #[derive(Serialize)]
279 struct MyRecord {
280 geometry: crate::Geometry,
281 name: String,
282 age: u64,
283 }
284
285 #[test]
286 fn write_empty() {
287 let mut buffer: Vec<u8> = vec![];
288 {
289 let mut writer = FeatureWriter::from_writer(&mut buffer);
290 writer.finish().unwrap();
291 }
292
293 let expected = json!({
294 "type": "FeatureCollection",
295 "features": []
296 });
297
298 let actual_json: JsonValue = serde_json::from_slice(&buffer).unwrap();
299 assert_eq!(actual_json, expected);
300 }
301
302 #[test]
303 fn finish_on_drop() {
304 let mut buffer: Vec<u8> = vec![];
305 {
306 _ = FeatureWriter::from_writer(&mut buffer);
307 }
308
309 let expected = json!({
310 "type": "FeatureCollection",
311 "features": []
312 });
313
314 let actual_json: JsonValue = serde_json::from_slice(&buffer).unwrap();
315 assert_eq!(actual_json, expected);
316 }
317
318 #[test]
319 fn write_feature() {
320 let mut buffer: Vec<u8> = vec![];
321 {
322 let mut writer = FeatureWriter::from_writer(&mut buffer);
323
324 let record_1 = {
325 let mut props = serde_json::Map::new();
326 props.insert("name".to_string(), "Mishka".into());
327 props.insert("age".to_string(), 12.into());
328
329 Feature {
330 bbox: None,
331 geometry: Some(crate::Geometry::from(crate::Value::Point(vec![1.1, 1.2]))),
332 id: None,
333 properties: Some(props),
334 foreign_members: None,
335 }
336 };
337
338 let record_2 = {
339 let mut props = serde_json::Map::new();
340 props.insert("name".to_string(), "Jane".into());
341 props.insert("age".to_string(), 22.into());
342
343 Feature {
344 bbox: None,
345 geometry: Some(crate::Geometry::from(crate::Value::Point(vec![2.1, 2.2]))),
346 id: None,
347 properties: Some(props),
348 foreign_members: None,
349 }
350 };
351
352 writer.write_feature(&record_1).unwrap();
353 writer.write_feature(&record_2).unwrap();
354 writer.flush().unwrap();
355 }
356
357 let expected = json!({
358 "type": "FeatureCollection",
359 "features": [
360 {
361 "type": "Feature",
362 "geometry": { "type": "Point", "coordinates": [1.1, 1.2] },
363 "properties": { "name": "Mishka", "age": 12
364 }
365 },
366 {
367 "type": "Feature",
368 "geometry": { "type": "Point", "coordinates": [2.1, 2.2] },
369 "properties": {
370 "name": "Jane",
371 "age": 22
372 }
373 }
374 ]
375 });
376
377 let actual_json: JsonValue = serde_json::from_slice(&buffer).expect("valid json");
378 assert_eq!(actual_json, expected)
379 }
380
381 #[test]
382 fn serialize() {
383 let mut buffer: Vec<u8> = vec![];
384 {
385 let mut writer = FeatureWriter::from_writer(&mut buffer);
386 let record_1 = MyRecord {
387 geometry: crate::Geometry::from(crate::Value::Point(vec![1.1, 1.2])),
388 name: "Mishka".to_string(),
389 age: 12,
390 };
391 let record_2 = MyRecord {
392 geometry: crate::Geometry::from(crate::Value::Point(vec![2.1, 2.2])),
393 name: "Jane".to_string(),
394 age: 22,
395 };
396 writer.serialize(&record_1).unwrap();
397 writer.serialize(&record_2).unwrap();
398 writer.flush().unwrap();
399 }
400
401 let expected = json!({
402 "type": "FeatureCollection",
403 "features": [
404 {
405 "type": "Feature",
406 "geometry": { "type": "Point", "coordinates": [1.1, 1.2] },
407 "properties": { "name": "Mishka", "age": 12
408 }
409 },
410 {
411 "type": "Feature",
412 "geometry": { "type": "Point", "coordinates": [2.1, 2.2] },
413 "properties": {
414 "name": "Jane",
415 "age": 22
416 }
417 }
418 ]
419 });
420
421 let actual_json: JsonValue = serde_json::from_slice(&buffer).expect("valid json");
422 assert_eq!(actual_json, expected)
423 }
424
425 #[test]
426 fn write_foreign_members() {
427 let mut buffer: Vec<u8> = vec![];
428 {
429 let mut writer = FeatureWriter::from_writer(&mut buffer);
430
431 writer.write_foreign_member("extra", "string").unwrap();
432 writer.write_foreign_member("list", &[1, 2, 3]).unwrap();
433 writer
434 .write_foreign_member("nested", &json!({"foo": "bar"}))
435 .unwrap();
436
437 let record_1 = {
438 let mut props = serde_json::Map::new();
439 props.insert("name".to_string(), "Mishka".into());
440 props.insert("age".to_string(), 12.into());
441
442 Feature {
443 bbox: None,
444 geometry: Some(crate::Geometry::from(crate::Value::Point(vec![1.1, 1.2]))),
445 id: None,
446 properties: Some(props),
447 foreign_members: None,
448 }
449 };
450
451 writer.write_feature(&record_1).unwrap();
452 writer.flush().unwrap();
453 }
454
455 let expected = json!({
456 "type": "FeatureCollection",
457 "extra": "string",
458 "list": [1, 2, 3],
459 "nested": {
460 "foo": "bar",
461 },
462 "features": [
463 {
464 "type": "Feature",
465 "geometry": { "type": "Point", "coordinates": [1.1, 1.2] },
466 "properties": { "name": "Mishka", "age": 12
467 }
468 },
469 ]
470 });
471
472 println!("{}", String::from_utf8(buffer.clone()).unwrap());
473 let actual_json: JsonValue = serde_json::from_slice(&buffer).expect("valid json");
474 assert_eq!(actual_json, expected)
475 }
476
477 #[cfg(feature = "geo-types")]
478 mod test_geo_types {
479 use super::*;
480 use crate::ser::serialize_geometry;
481
482 #[derive(Serialize)]
484 struct MyGeoRecord {
485 #[serde(serialize_with = "serialize_geometry")]
486 geometry: geo_types::Point,
487 name: String,
488 age: u64,
489 }
490
491 #[test]
492 fn serialize_geo_types() {
493 let mut buffer: Vec<u8> = vec![];
494 {
495 let mut writer = FeatureWriter::from_writer(&mut buffer);
496 let record_1 = MyGeoRecord {
497 geometry: geo_types::point!(x: 1.1, y: 1.2),
498 name: "Mishka".to_string(),
499 age: 12,
500 };
501 let record_2 = MyGeoRecord {
502 geometry: geo_types::point!(x: 2.1, y: 2.2),
503 name: "Jane".to_string(),
504 age: 22,
505 };
506 writer.serialize(&record_1).unwrap();
507 writer.serialize(&record_2).unwrap();
508 writer.flush().unwrap();
509 }
510
511 let expected = json!({
512 "type": "FeatureCollection",
513 "features": [
514 {
515 "type": "Feature",
516 "geometry": { "type": "Point", "coordinates": [1.1, 1.2] },
517 "properties": {
518 "name": "Mishka",
519 "age": 12
520 }
521 },
522 {
523 "type": "Feature",
524 "geometry": { "type": "Point", "coordinates": [2.1, 2.2] },
525 "properties": {
526 "name": "Jane",
527 "age": 22
528 }
529 }
530 ]
531 });
532
533 let actual_json: JsonValue = serde_json::from_slice(&buffer).expect("valid json");
534 assert_eq!(actual_json, expected)
535 }
536 }
537}