use crate::model_types::DntSealOptions;
use crate::{DntError, DntResult};
pub const DNT_FLAG_PAYLOAD_DEFLATE: u32 = 0x0000_0001;
pub const DNT_INTERNAL_FLAG_MASK: u32 = 0x0000_FFFF;
pub const DNT_USER_FLAG_MASK: u32 = 0xFFFF_0000;
pub const DNT_USER_FLAG_OFFSET: u8 = 16;
pub const DNT_USER_FLAG_COUNT: u8 = 16;
const KNOWN_INTERNAL_FLAGS: u32 = DNT_FLAG_PAYLOAD_DEFLATE;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct DntFlags(u32);
impl DntFlags {
pub const fn empty() -> Self {
Self(0)
}
pub fn from_bits(bits: u32) -> DntResult<Self> {
validate_flags(bits)?;
Ok(Self(bits))
}
pub const fn bits(self) -> u32 {
self.0
}
pub const fn internal_bits(self) -> u32 {
self.0 & DNT_INTERNAL_FLAG_MASK
}
pub const fn user_bits(self) -> u32 {
self.0 & DNT_USER_FLAG_MASK
}
pub const fn compact_payload(self) -> Self {
Self(self.0 | DNT_FLAG_PAYLOAD_DEFLATE)
}
pub fn with_user_flag(self, index: u8) -> DntResult<Self> {
Ok(Self(self.0 | dnt_user_flag(index)?))
}
}
impl DntSealOptions {
pub fn compact_payload(mut self) -> Self {
self.flags |= DNT_FLAG_PAYLOAD_DEFLATE;
self
}
pub fn with_user_flag(mut self, index: u8) -> DntResult<Self> {
self.flags = DntFlags::from_bits(self.flags)?
.with_user_flag(index)?
.bits();
Ok(self)
}
}
pub fn dnt_user_flag(index: u8) -> DntResult<u32> {
if index >= DNT_USER_FLAG_COUNT {
return Err(DntError::InvalidFlags);
}
1u32.checked_shl(u32::from(DNT_USER_FLAG_OFFSET + index))
.ok_or(DntError::InvalidFlags)
}
pub fn dnt_compose_flags(internal_flags: u32, user_flags: u32) -> DntResult<u32> {
if internal_flags & !KNOWN_INTERNAL_FLAGS != 0 || user_flags & !DNT_USER_FLAG_MASK != 0 {
return Err(DntError::InvalidFlags);
}
Ok(internal_flags | user_flags)
}
pub(crate) fn validate_flags(flags: u32) -> DntResult<()> {
let unknown_internal_flags = flags & DNT_INTERNAL_FLAG_MASK & !KNOWN_INTERNAL_FLAGS;
if unknown_internal_flags != 0 {
return Err(DntError::InvalidFlags);
}
Ok(())
}