use crate::{Error, Href, Item, Link, Links, Migrate};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use std::{ops::Deref, vec::IntoIter};
pub const ITEM_COLLECTION_TYPE: &str = "FeatureCollection";
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct ItemCollection {
#[serde(rename = "features")]
pub items: Vec<Item>,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub links: Vec<Link>,
#[serde(flatten)]
pub additional_fields: Map<String, Value>,
#[serde(
deserialize_with = "deserialize_type",
serialize_with = "serialize_type"
)]
r#type: String,
#[serde(skip)]
href: Option<String>,
}
impl From<Vec<Item>> for ItemCollection {
fn from(items: Vec<Item>) -> Self {
ItemCollection {
r#type: ITEM_COLLECTION_TYPE.to_string(),
items,
links: Vec::new(),
additional_fields: Map::new(),
href: None,
}
}
}
impl FromIterator<Item> for ItemCollection {
fn from_iter<I: IntoIterator<Item = Item>>(iter: I) -> Self {
iter.into_iter().collect::<Vec<_>>().into()
}
}
impl IntoIterator for ItemCollection {
type IntoIter = IntoIter<Item>;
type Item = Item;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl Deref for ItemCollection {
type Target = Vec<Item>;
fn deref(&self) -> &Self::Target {
&self.items
}
}
impl Href for ItemCollection {
fn href(&self) -> Option<&str> {
self.href.as_deref()
}
fn set_href(&mut self, href: impl ToString) {
self.href = Some(href.to_string())
}
fn clear_href(&mut self) {
self.href = None;
}
}
impl Links for ItemCollection {
fn links(&self) -> &[Link] {
&self.links
}
fn links_mut(&mut self) -> &mut Vec<Link> {
&mut self.links
}
}
fn deserialize_type<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: serde::de::Deserializer<'de>,
{
crate::deserialize_type(deserializer, ITEM_COLLECTION_TYPE)
}
fn serialize_type<S>(r#type: &String, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
crate::serialize_type(r#type, serializer, ITEM_COLLECTION_TYPE)
}
impl Migrate for ItemCollection {
fn migrate(mut self, version: &crate::Version) -> crate::Result<Self> {
let mut items = Vec::with_capacity(self.items.len());
for item in self.items {
items.push(item.migrate(version)?);
}
self.items = items;
Ok(self)
}
}
impl TryFrom<Value> for ItemCollection {
type Error = Error;
fn try_from(value: Value) -> Result<Self, Self::Error> {
match serde_json::from_value::<ItemCollection>(value.clone()) {
Ok(item_collection) => Ok(item_collection),
Err(err) => {
if let Value::Array(array) = value {
let mut items = Vec::new();
for item in array {
items.push(serde_json::from_value(item)?);
}
Ok(items.into())
} else {
Err(Error::from(err))
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::ItemCollection;
use crate::Item;
#[test]
fn item_collection_from_vec() {
let items = vec![Item::new("a"), Item::new("b")];
let _ = ItemCollection::from(items);
}
#[test]
fn item_collection_from_iter() {
let items = vec![Item::new("a"), Item::new("b")];
let _ = ItemCollection::from_iter(items.into_iter());
}
}