Skip to content

Commit

Permalink
unique manifest catalogs by id & type
Browse files Browse the repository at this point in the history
  • Loading branch information
nklhtv committed Jun 15, 2022
1 parent 4c88410 commit 6727866
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 2 deletions.
45 changes: 43 additions & 2 deletions src/types/addon/manifest.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use crate::types::addon::{ExtraValue, ResourcePath};
use crate::types::Unique;
use derivative::Derivative;
use derive_more::Deref;
use derive_more::{Deref, From, Into};
use either::Either;
use semver::Version;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::{serde_as, DeserializeAs, SerializeAs};
use std::borrow::Cow;
use std::hash::{Hash, Hasher};

#[serde_as]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
#[cfg_attr(debug_assertions, derive(Debug))]
#[cfg_attr(test, derive(Derivative))]
Expand All @@ -24,6 +28,7 @@ pub struct Manifest {
pub resources: Vec<ManifestResource>,
pub id_prefixes: Option<Vec<String>>,
#[serde(default)]
#[serde_as(as = "Unique<ManifestCatalogUnique>")]
pub catalogs: Vec<ManifestCatalog>,
#[serde(default)]
pub addon_catalogs: Vec<ManifestCatalog>,
Expand Down Expand Up @@ -157,6 +162,42 @@ impl ManifestCatalog {
}
}

#[derive(Clone, From, Into, Deserialize, Serialize)]
struct ManifestCatalogUnique(ManifestCatalog);

impl Hash for ManifestCatalogUnique {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.id.hash(state);
self.0.r#type.hash(state);
}
}

impl PartialEq for ManifestCatalogUnique {
fn eq(&self, other: &Self) -> bool {
self.0.id == other.0.id && self.0.r#type == other.0.r#type
}
}

impl Eq for ManifestCatalogUnique {}

impl<'de> DeserializeAs<'de, ManifestCatalog> for ManifestCatalogUnique {
fn deserialize_as<D>(deserializer: D) -> Result<ManifestCatalog, D::Error>
where
D: Deserializer<'de>,
{
Ok(ManifestCatalogUnique::deserialize(deserializer)?.into())
}
}

impl SerializeAs<ManifestCatalog> for ManifestCatalogUnique {
fn serialize_as<S>(source: &ManifestCatalog, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
ManifestCatalogUnique::from(source.to_owned()).serialize(serializer)
}
}

#[derive(Derivative, Clone, PartialEq, Serialize, Deserialize)]
#[derivative(Default)]
#[cfg_attr(debug_assertions, derive(Debug))]
Expand Down
3 changes: 3 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ pub mod library;
pub mod profile;
pub mod resource;

mod serde_as_ext;
pub use serde_as_ext::*;

mod r#true;
pub use r#true::*;
92 changes: 92 additions & 0 deletions src/types/serde_as_ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use core::marker::PhantomData;
use itertools::Itertools;
use serde::de::{SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_with::de::DeserializeAsWrap;
use serde_with::{DeserializeAs, SerializeAs};
use std::fmt;
use std::hash::Hash;

#[derive(Copy, Clone, Debug, Default)]
pub struct Unique<T: Hash + Eq>(PhantomData<T>);

impl<'de, T, U> DeserializeAs<'de, Vec<T>> for Unique<U>
where
U: Clone + Hash + Eq + Deserialize<'de> + DeserializeAs<'de, T>,
T: From<U>,
{
fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
#[serde(
transparent,
bound(deserialize = "DeserializeAsWrap<Vec<T>, Vec<U>>: Deserialize<'de>")
)]
struct Helper<'a, T, U>
where
U: DeserializeAs<'a, T>,
{
#[serde(flatten)]
inner: DeserializeAsWrap<Vec<T>, Vec<U>>,
#[serde(skip)]
marker: PhantomData<&'a u32>,
}

impl<'a, T, U> Helper<'a, T, U>
where
U: DeserializeAs<'a, T>,
{
fn into_inner(self) -> DeserializeAsWrap<Vec<T>, Vec<U>> {
self.inner
}
}

impl<'de, T, U> Visitor<'de> for Helper<'de, T, U>
where
U: Clone + Hash + Eq + Deserialize<'de> + DeserializeAs<'de, T>,
T: From<U>,
{
type Value = Vec<T>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence")
}

fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: SeqAccess<'de>,
{
let mut values = Vec::<U>::with_capacity(visitor.size_hint().unwrap_or_default());
while let Some(value) = visitor.next_element()? {
values.push(value);
}
Ok(values.into_iter().unique().map(From::from).collect())
}
}

Ok(Helper::<'de, T, U>::deserialize(deserializer)?
.into_inner()
.into_inner())
}
}

impl<T, U> SerializeAs<Vec<T>> for Unique<U>
where
U: Clone + Hash + Eq + From<T> + Serialize + SerializeAs<T>,
T: Clone,
{
fn serialize_as<S>(source: &Vec<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
source
.iter()
.cloned()
.map(From::from)
.unique()
.collect::<Vec<U>>()
.serialize(serializer)
}
}

0 comments on commit 6727866

Please sign in to comment.