use crate::core::DataRead;
use crate::sections::{IdSet, SectionDecodeError};
use bitstream_io::BitRead;
use iab_gpp_derive::GPPSection;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::collections::BTreeSet;
#[derive(Debug, Eq, PartialEq, GPPSection)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[gpp(section_version = 1)]
pub struct TcfEuV1 {
#[gpp(datetime_as_unix_timestamp)]
pub created: u64,
#[gpp(datetime_as_unix_timestamp)]
pub last_updated: u64,
pub cmp_id: u16,
pub cmp_version: u16,
pub consent_screen: u8,
#[gpp(string(2))]
pub consent_language: String,
pub vendor_list_version: u16,
#[gpp(fixed_bitfield(24))]
pub purposes_allowed: IdSet,
#[gpp(parse_with = parse_vendor_consents)]
pub vendor_consents: IdSet,
}
fn parse_vendor_consents<R: BitRead + ?Sized>(mut r: &mut R) -> Result<IdSet, SectionDecodeError> {
let max_vendor_id = r.read_unsigned::<16, u16>()?;
let is_range = r.read_bit()?;
Ok(if is_range {
let default_consent = r.read_bit()?;
let ids = BTreeSet::from_iter(r.read_integer_range()?);
(1..=max_vendor_id)
.filter(|id| {
default_consent ^ ids.contains(id)
})
.collect()
} else {
r.read_fixed_bitfield(max_vendor_id as usize)?
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use test_case::test_case;
#[test_case("BO5a1L7O5a1L7AAABBENC2-AAAAtH" => matches SectionDecodeError::Read { .. } ; "missing data")]
#[test_case("" => matches SectionDecodeError::Read { .. } ; "empty string")]
#[test_case("DOEFEAyOEFEAyAHABDENAI4AAAB9vABAASA" => matches SectionDecodeError::UnknownSegmentVersion { segment_version: 3 } ; "unknown segment version")]
fn error(s: &str) -> SectionDecodeError {
TcfEuV1::from_str(s).unwrap_err()
}
}