use alloc::collections::{BTreeMap, BTreeSet};
use alloc::format;
use alloc::vec::Vec;
use core::convert::Infallible;
use core::error::Error;
use core::fmt::Debug;
use super::{MapField, OptionalField, RepeatedField};
use crate::{ConversionError, ConversionResultExt, Verify, VerifyWith, unwrap_infallible};
impl<S: Verify<Error = Infallible>> OptionalField<S> {
pub fn verify_infallible(self) -> Option<S::Verified> {
self.map(|value| unwrap_infallible(value.verify()))
}
}
impl<S: Verify<Error = Infallible>> RepeatedField<S> {
pub fn verify_infallible(self) -> Vec<S::Verified> {
self.map(|value| unwrap_infallible(value.verify()))
}
}
impl<K: Ord, S: Verify<Error = Infallible>> MapField<BTreeMap<K, S>> {
pub fn verify_infallible(self) -> BTreeMap<K, S::Verified> {
self.map(|value| unwrap_infallible(value.verify()))
}
}
#[cfg(feature = "std")]
impl<K: Eq + core::hash::Hash, S: Verify<Error = Infallible>>
MapField<std::collections::HashMap<K, S>>
{
pub fn verify_infallible(self) -> std::collections::HashMap<K, S::Verified> {
self.map(|value| unwrap_infallible(value.verify()))
}
}
impl<S: Verify> Verify for OptionalField<S> {
type Verified = Option<S::Verified>;
type Error = ConversionError;
fn verify(self) -> Result<Self::Verified, Self::Error> {
self.try_map(Verify::verify)
}
}
impl<S: VerifyWith<C>, C> VerifyWith<C> for OptionalField<S> {
type Verified = Option<S::Verified>;
type Error = ConversionError;
fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
self.try_map(|value| value.verify_with(context))
}
}
impl<S: Verify> Verify for RepeatedField<S> {
type Verified = Vec<S::Verified>;
type Error = ConversionError;
fn verify(self) -> Result<Self::Verified, Self::Error> {
self.try_map(Verify::verify)
}
}
impl<S: VerifyWith<C>, C: Clone> VerifyWith<C> for RepeatedField<S> {
type Verified = Vec<S::Verified>;
type Error = ConversionError;
fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
self.try_map(|value| value.verify_with(context.clone()))
}
}
impl<K: Ord + Debug, S: Verify> Verify for MapField<BTreeMap<K, S>> {
type Verified = BTreeMap<K, S::Verified>;
type Error = ConversionError;
fn verify(self) -> Result<Self::Verified, Self::Error> {
self.try_map(Verify::verify)
}
}
impl<K: Ord + Debug, S: VerifyWith<C>, C: Clone> VerifyWith<C> for MapField<BTreeMap<K, S>> {
type Verified = BTreeMap<K, S::Verified>;
type Error = ConversionError;
fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
self.try_map(|value| value.verify_with(context.clone()))
}
}
#[cfg(feature = "std")]
impl<K: Eq + core::hash::Hash + Debug, S: Verify> Verify
for MapField<std::collections::HashMap<K, S>>
{
type Verified = std::collections::HashMap<K, S::Verified>;
type Error = ConversionError;
fn verify(self) -> Result<Self::Verified, Self::Error> {
self.try_map(Verify::verify)
}
}
#[cfg(feature = "std")]
impl<K: Eq + core::hash::Hash + Debug, S: VerifyWith<C>, C: Clone> VerifyWith<C>
for MapField<std::collections::HashMap<K, S>>
{
type Verified = std::collections::HashMap<K, S::Verified>;
type Error = ConversionError;
fn verify_with(self, context: C) -> Result<Self::Verified, Self::Error> {
self.try_map(|value| value.verify_with(context.clone()))
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DuplicatePolicy {
Reject,
KeepFirst,
}
impl<S> RepeatedField<S> {
pub fn verify_into_btree_set(
self,
duplicates: DuplicatePolicy,
) -> Result<BTreeSet<S::Verified>, ConversionError>
where
S: Verify,
S::Verified: Ord,
{
let mut values = BTreeSet::new();
self.verify_set(duplicates, Verify::verify, |value| values.insert(value))?;
Ok(values)
}
pub fn verify_into_btree_set_with<C>(
self,
context: C,
duplicates: DuplicatePolicy,
) -> Result<BTreeSet<S::Verified>, ConversionError>
where
S: VerifyWith<C>,
S::Verified: Ord,
C: Clone,
{
let mut values = BTreeSet::new();
self.verify_set(
duplicates,
|value| value.verify_with(context.clone()),
|value| values.insert(value),
)?;
Ok(values)
}
#[cfg(feature = "std")]
pub fn verify_into_hash_set(
self,
duplicates: DuplicatePolicy,
) -> Result<std::collections::HashSet<S::Verified>, ConversionError>
where
S: Verify,
S::Verified: Eq + core::hash::Hash,
{
let mut values = std::collections::HashSet::new();
self.verify_set(duplicates, Verify::verify, |value| values.insert(value))?;
Ok(values)
}
#[cfg(feature = "std")]
pub fn verify_into_hash_set_with<C>(
self,
context: C,
duplicates: DuplicatePolicy,
) -> Result<std::collections::HashSet<S::Verified>, ConversionError>
where
S: VerifyWith<C>,
S::Verified: Eq + core::hash::Hash,
C: Clone,
{
let mut values = std::collections::HashSet::new();
self.verify_set(
duplicates,
|value| value.verify_with(context.clone()),
|value| values.insert(value),
)?;
Ok(values)
}
fn verify_set<T, E: Error + Send + Sync + 'static>(
self,
duplicates: DuplicatePolicy,
mut verify: impl FnMut(S) -> Result<T, E>,
mut insert: impl FnMut(T) -> bool,
) -> Result<(), ConversionError> {
for (index, value) in self.values.into_iter().enumerate() {
let value = verify(value).with_context(|| format!("{}[{index}]", self.name))?;
if !insert(value) && duplicates == DuplicatePolicy::Reject {
return Err(ConversionError::message("duplicate verified value")
.context(format!("{}[{index}]", self.name)));
}
}
Ok(())
}
}