pub mod bit_reader;
pub mod bit_writer;
pub mod core_string;
pub mod gvl;
pub mod segments;
pub mod tc_string;
pub mod validation;
pub mod vendor_set;
pub use bit_reader::BitReader;
pub use bit_writer::BitWriter;
pub use core_string::{
AllowedVendors, CoreString, DisclosedVendors, PublisherRestriction, PublisherRestrictions,
PublisherTC, RestrictionType, TCModel,
};
pub use gvl::{
DataRetention, Feature, GlobalVendorList, Purpose, SpecialFeature, SpecialPurpose, Vendor,
VendorUrl,
};
pub use tc_string::{decode_tc_string, encode_tc_string};
pub use validation::{
quick_validate, validate_tc_string, validate_tc_string_with_gvl, ValidationError,
ValidationResult, ValidationWarning,
};
pub use vendor_set::{VendorRange, VendorSet};
pub use segments::{
EncodingType, PublisherTCAnalysis, SegmentAnalysis, SegmentAnalyzer, SegmentUtils,
SegmentValidator,
};
use serde::{Deserialize, Serialize};
use std::fmt;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Invalid TC String: {0}")]
InvalidTCString(String),
#[error("Unsupported TCF version: {0}")]
UnsupportedVersion(u8),
#[error("End of data reached unexpectedly")]
EndOfData,
#[error("Too many bits requested: {0} (maximum 64)")]
TooManyBits(u8),
#[error("Base64 decode error: {0}")]
Base64DecodeError(String),
#[error("Invalid timestamp: {0} deciseconds")]
InvalidTimestamp(u64),
#[error("Missing disclosed vendors segment (required in TCF v2.2+)")]
MissingDisclosedVendors,
#[error("Unknown segment type: {0}")]
UnknownSegmentType(u8),
#[error("Invalid segment type: expected {1}, found {0}")]
InvalidSegmentType(u8, u8),
#[error("Invalid language code: {0}")]
InvalidLanguageCode(String),
#[error("Invalid language encoding: {0}")]
InvalidLanguageEncoding(u64),
#[error("Invalid purpose ID: {0} (must be 1-24)")]
InvalidPurposeId(u8),
#[error("Invalid restriction type: {0}")]
InvalidRestrictionType(u8),
#[error("Empty vendor set")]
EmptyVendorSet,
#[error("Invalid custom purpose count")]
InvalidCustomPurposeCount,
#[error("UTF-8 encoding error: {0}")]
Utf8Error(#[from] std::string::FromUtf8Error),
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("Network error: {0}")]
NetworkError(String),
#[error("GVL fetch error: HTTP {0}")]
GVLFetchError(u16),
#[error("GVL parse error: {0}")]
GVLParseError(String),
#[error("JSON serialization error: {0}")]
SerializationError(String),
#[error("JSON parse error: {0}")]
JsonError(#[from] serde_json::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BitField {
bits: Vec<bool>,
}
impl BitField {
#[must_use]
pub fn new(size: usize) -> Self {
Self {
bits: vec![false; size],
}
}
pub fn set(&mut self, index: usize, value: bool) {
if index < self.bits.len() {
self.bits[index] = value;
}
}
#[must_use]
pub fn get(&self, index: usize) -> bool {
self.bits.get(index).copied().unwrap_or(false)
}
#[must_use]
pub fn is_set(&self, index: usize) -> bool {
self.get(index)
}
#[must_use]
pub fn len(&self) -> usize {
self.bits.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bits.is_empty()
}
#[must_use = "Iterator must be used"]
pub fn iter_set(&self) -> impl Iterator<Item = usize> + '_ {
self.bits
.iter()
.enumerate()
.filter_map(|(i, &bit)| if bit { Some(i) } else { None })
}
#[must_use]
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = vec![0u8; self.bits.len().div_ceil(8)];
for (i, &bit) in self.bits.iter().enumerate() {
if bit {
bytes[i / 8] |= 1 << (7 - (i % 8));
}
}
bytes
}
#[must_use]
pub fn from_bytes(bytes: &[u8], size: usize) -> Self {
let mut bits = vec![false; size];
for (i, bit) in bits.iter_mut().enumerate().take(size) {
if i < bytes.len() * 8 {
*bit = (bytes[i / 8] & (1 << (7 - (i % 8)))) != 0;
}
}
Self { bits }
}
}
impl fmt::Display for BitField {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BitField(")?;
for (i, &bit) in self.bits.iter().enumerate() {
write!(f, "{}", if bit { '1' } else { '0' })?;
if (i + 1) % 8 == 0 && i + 1 < self.bits.len() {
write!(f, " ")?;
}
}
write!(f, ")")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bitfield_basic_operations() {
let mut field = BitField::new(24);
field.set(0, true);
field.set(5, true);
field.set(23, true);
assert!(field.get(0));
assert!(field.get(5));
assert!(field.get(23));
assert!(!field.get(1));
}
#[test]
fn test_bitfield_iter_set() {
let mut field = BitField::new(10);
field.set(1, true);
field.set(3, true);
field.set(7, true);
let set_bits: Vec<usize> = field.iter_set().collect();
assert_eq!(set_bits, vec![1, 3, 7]);
}
#[test]
fn test_bitfield_to_bytes() {
let mut field = BitField::new(8);
field.set(0, true); field.set(7, true);
let bytes = field.to_bytes();
assert_eq!(bytes, vec![0b1000_0001]);
}
#[test]
fn test_bitfield_from_bytes() {
let bytes = vec![0b1000_0001];
let field = BitField::from_bytes(&bytes, 8);
assert!(field.get(0));
assert!(field.get(7));
assert!(!field.get(1));
}
}