Skip to main content

appcore_dnt/
flags.rs

1// =============================================================================
2//        #######
3//     ###       ###     F: flags.rs
4//    ##   ## ##   ##    P: AppCore-Runtime
5//         ## ##
6//                       C: 2026/08/02 10:29:16 by dnettoRaw
7//    ##   ## ##   ##    U: 2026/08/02 10:29:16 by dnettoRaw
8//      ###########      S: 1.0.1-rc.8
9// =============================================================================
10
11//! Authenticated DNT flag partitioning and builders.
12
13use crate::model_types::DntSealOptions;
14use crate::{DntError, DntResult};
15
16/// Internal DNT flag: stored encoded payload uses zlib-wrapped DEFLATE.
17pub const DNT_FLAG_PAYLOAD_DEFLATE: u32 = 0x0000_0001;
18
19/// Bits reserved for DNT envelope semantics.
20pub const DNT_INTERNAL_FLAG_MASK: u32 = 0x0000_FFFF;
21/// Bits available for caller/application semantics.
22pub const DNT_USER_FLAG_MASK: u32 = 0xFFFF_0000;
23/// First user flag bit in the raw DNT flag field.
24pub const DNT_USER_FLAG_OFFSET: u8 = 16;
25/// Number of user flag bits available to callers.
26pub const DNT_USER_FLAG_COUNT: u8 = 16;
27
28const KNOWN_INTERNAL_FLAGS: u32 = DNT_FLAG_PAYLOAD_DEFLATE;
29
30/// Validated DNT flags.
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub struct DntFlags(u32);
33
34impl DntFlags {
35    /// Returns empty flags.
36    pub const fn empty() -> Self {
37        Self(0)
38    }
39
40    /// Validates raw flag bits.
41    pub fn from_bits(bits: u32) -> DntResult<Self> {
42        validate_flags(bits)?;
43        Ok(Self(bits))
44    }
45
46    /// Returns the raw header bits.
47    pub const fn bits(self) -> u32 {
48        self.0
49    }
50
51    /// Returns only DNT-owned internal bits.
52    pub const fn internal_bits(self) -> u32 {
53        self.0 & DNT_INTERNAL_FLAG_MASK
54    }
55
56    /// Returns only caller-owned user bits.
57    pub const fn user_bits(self) -> u32 {
58        self.0 & DNT_USER_FLAG_MASK
59    }
60
61    /// Enables compact DNT payload storage.
62    pub const fn compact_payload(self) -> Self {
63        Self(self.0 | DNT_FLAG_PAYLOAD_DEFLATE)
64    }
65
66    /// Adds one caller-owned user flag by relative index `0..16`.
67    pub fn with_user_flag(self, index: u8) -> DntResult<Self> {
68        Ok(Self(self.0 | dnt_user_flag(index)?))
69    }
70}
71
72impl DntSealOptions {
73    /// Enables compact payload storage for this write.
74    ///
75    /// The codec output is compressed with zlib-wrapped DEFLATE before AEAD
76    /// encryption. The compression flag is part of the authenticated header.
77    pub fn compact_payload(mut self) -> Self {
78        self.flags |= DNT_FLAG_PAYLOAD_DEFLATE;
79        self
80    }
81
82    /// Adds one caller-owned user flag by relative index `0..16`.
83    pub fn with_user_flag(mut self, index: u8) -> DntResult<Self> {
84        self.flags = DntFlags::from_bits(self.flags)?
85            .with_user_flag(index)?
86            .bits();
87        Ok(self)
88    }
89}
90
91/// Creates a caller-owned user flag by relative index `0..16`.
92pub fn dnt_user_flag(index: u8) -> DntResult<u32> {
93    if index >= DNT_USER_FLAG_COUNT {
94        return Err(DntError::InvalidFlags);
95    }
96    1u32.checked_shl(u32::from(DNT_USER_FLAG_OFFSET + index))
97        .ok_or(DntError::InvalidFlags)
98}
99
100/// Combines DNT-owned internal flags and caller-owned user flags.
101pub fn dnt_compose_flags(internal_flags: u32, user_flags: u32) -> DntResult<u32> {
102    if internal_flags & !KNOWN_INTERNAL_FLAGS != 0 || user_flags & !DNT_USER_FLAG_MASK != 0 {
103        return Err(DntError::InvalidFlags);
104    }
105    Ok(internal_flags | user_flags)
106}
107
108pub(crate) fn validate_flags(flags: u32) -> DntResult<()> {
109    let unknown_internal_flags = flags & DNT_INTERNAL_FLAG_MASK & !KNOWN_INTERNAL_FLAGS;
110    if unknown_internal_flags != 0 {
111        return Err(DntError::InvalidFlags);
112    }
113    Ok(())
114}