librespot_metadata/
restriction.rs

1use std::{
2    fmt::Debug,
3    ops::{Deref, DerefMut},
4};
5
6use crate::util::impl_deref_wrapped;
7use crate::util::{impl_from_repeated, impl_from_repeated_copy};
8
9use protocol::metadata::Restriction as RestrictionMessage;
10
11use librespot_protocol as protocol;
12pub use protocol::metadata::restriction::Catalogue as RestrictionCatalogue;
13pub use protocol::metadata::restriction::Type as RestrictionType;
14
15#[derive(Debug, Clone)]
16pub struct Restriction {
17    pub catalogues: RestrictionCatalogues,
18    pub restriction_type: RestrictionType,
19    pub catalogue_strs: Vec<String>,
20    pub countries_allowed: Option<Vec<String>>,
21    pub countries_forbidden: Option<Vec<String>>,
22}
23
24#[derive(Debug, Clone, Default)]
25pub struct Restrictions(pub Vec<Restriction>);
26
27impl_deref_wrapped!(Restrictions, Vec<Restriction>);
28
29#[derive(Debug, Clone)]
30pub struct RestrictionCatalogues(pub Vec<RestrictionCatalogue>);
31
32impl_deref_wrapped!(RestrictionCatalogues, Vec<RestrictionCatalogue>);
33
34impl Restriction {
35    fn parse_country_codes(country_codes: &str) -> Vec<String> {
36        country_codes
37            .chunks(2)
38            .map(|country_code| country_code.to_owned())
39            .collect()
40    }
41}
42
43impl From<&RestrictionMessage> for Restriction {
44    fn from(restriction: &RestrictionMessage) -> Self {
45        let countries_allowed = if restriction.has_countries_allowed() {
46            Some(Self::parse_country_codes(restriction.countries_allowed()))
47        } else {
48            None
49        };
50
51        let countries_forbidden = if restriction.has_countries_forbidden() {
52            Some(Self::parse_country_codes(restriction.countries_forbidden()))
53        } else {
54            None
55        };
56
57        Self {
58            catalogues: restriction
59                .catalogue
60                .iter()
61                .map(|c| c.enum_value_or_default())
62                .collect::<Vec<RestrictionCatalogue>>()
63                .as_slice()
64                .into(),
65            restriction_type: restriction
66                .type_
67                .unwrap_or_default()
68                .enum_value_or_default(),
69            catalogue_strs: restriction.catalogue_str.to_vec(),
70            countries_allowed,
71            countries_forbidden,
72        }
73    }
74}
75
76impl_from_repeated!(RestrictionMessage, Restrictions);
77impl_from_repeated_copy!(RestrictionCatalogue, RestrictionCatalogues);
78
79struct StrChunks<'s>(&'s str, usize);
80
81trait StrChunksExt {
82    fn chunks(&self, size: usize) -> StrChunks<'_>;
83}
84
85impl StrChunksExt for str {
86    fn chunks(&self, size: usize) -> StrChunks<'_> {
87        StrChunks(self, size)
88    }
89}
90
91impl<'s> Iterator for StrChunks<'s> {
92    type Item = &'s str;
93    fn next(&mut self) -> Option<&'s str> {
94        let &mut StrChunks(data, size) = self;
95        if data.is_empty() {
96            None
97        } else {
98            let ret = Some(&data[..size]);
99            self.0 = &data[size..];
100            ret
101        }
102    }
103}