1use std::fmt;
2use std::ops::{
3 BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Sub, SubAssign,
4};
5
6use crate::constants::{
7 CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE,
8 CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH,
9 CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY,
10};
11
12#[derive(Clone, Copy, PartialEq, Eq, Hash)]
14pub struct Tag(u8);
15
16const TAG_ITER_FLAGS: [Tag; 2] = [Tag::PUSH, Tag::REKEY];
17const TAG_ITER_NAMES: [(&str, Tag); 2] = [("PUSH", Tag::PUSH), ("REKEY", Tag::REKEY)];
18
19impl Tag {
20 pub const FINAL: Self = Self(Self::PUSH.bits() | Self::REKEY.bits());
22 const KNOWN_BITS: u8 = Self::MESSAGE.bits() | Self::PUSH.bits() | Self::REKEY.bits();
23 pub const MESSAGE: Self = Self(CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_MESSAGE);
25 pub const PUSH: Self = Self(CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH);
28 pub const REKEY: Self = Self(CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY);
30
31 #[inline]
33 pub const fn empty() -> Self {
34 Self(0)
35 }
36
37 #[inline]
39 pub const fn all() -> Self {
40 Self(Self::KNOWN_BITS)
41 }
42
43 #[inline]
45 pub const fn bits(&self) -> u8 {
46 self.0
47 }
48
49 #[inline]
51 pub const fn from_bits(bits: u8) -> Option<Self> {
52 if bits & !Self::KNOWN_BITS == 0 {
53 Some(Self(bits))
54 } else {
55 None
56 }
57 }
58
59 #[inline]
61 pub const fn from_bits_truncate(bits: u8) -> Self {
62 Self(bits & Self::KNOWN_BITS)
63 }
64
65 #[inline]
71 pub const fn from_bits_retain(bits: u8) -> Self {
72 Self(bits)
73 }
74
75 pub fn from_name(name: &str) -> Option<Self> {
77 match name {
78 "MESSAGE" => Some(Self::MESSAGE),
79 "PUSH" => Some(Self::PUSH),
80 "REKEY" => Some(Self::REKEY),
81 "FINAL" => Some(Self::FINAL),
82 _ => None,
83 }
84 }
85
86 #[inline]
88 pub const fn is_empty(&self) -> bool {
89 self.bits() == 0
90 }
91
92 #[inline]
94 pub const fn is_all(&self) -> bool {
95 Self::KNOWN_BITS | self.bits() == self.bits()
96 }
97
98 #[inline]
101 pub const fn intersects(&self, other: Self) -> bool {
102 self.bits() & other.bits() != 0
103 }
104
105 #[inline]
108 pub const fn contains(&self, other: Self) -> bool {
109 self.bits() & other.bits() == other.bits()
110 }
111
112 #[inline]
114 pub fn insert(&mut self, other: Self) {
115 *self = self.union(other);
116 }
117
118 #[inline]
121 pub fn remove(&mut self, other: Self) {
122 *self = self.difference(other);
123 }
124
125 #[inline]
127 pub fn toggle(&mut self, other: Self) {
128 *self = self.symmetric_difference(other);
129 }
130
131 #[inline]
134 pub fn set(&mut self, other: Self, value: bool) {
135 if value {
136 self.insert(other);
137 } else {
138 self.remove(other);
139 }
140 }
141
142 #[inline]
144 pub fn clear(&mut self) {
145 *self = Self::empty();
146 }
147
148 #[inline]
150 #[must_use]
151 pub const fn intersection(self, other: Self) -> Self {
152 Self(self.bits() & other.bits())
153 }
154
155 #[inline]
157 #[must_use]
158 pub const fn union(self, other: Self) -> Self {
159 Self(self.bits() | other.bits())
160 }
161
162 #[inline]
165 #[must_use]
166 pub const fn difference(self, other: Self) -> Self {
167 Self(self.bits() & !other.bits())
168 }
169
170 #[inline]
172 #[must_use]
173 pub const fn symmetric_difference(self, other: Self) -> Self {
174 Self(self.bits() ^ other.bits())
175 }
176
177 #[inline]
180 #[must_use]
181 pub const fn complement(self) -> Self {
182 Self::from_bits_truncate(!self.bits())
183 }
184
185 pub const fn iter(&self) -> TagIter {
187 TagIter {
188 remaining: *self,
189 index: 0,
190 yielded_unknown: false,
191 }
192 }
193
194 pub const fn iter_names(&self) -> TagIterNames {
196 TagIterNames {
197 remaining: *self,
198 index: 0,
199 }
200 }
201}
202
203impl Default for Tag {
204 fn default() -> Self {
205 Self::empty()
206 }
207}
208
209impl fmt::Debug for Tag {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 f.write_str("Tag(")?;
212
213 let mut first = true;
214 for (name, _) in self.iter_names() {
215 if !first {
216 f.write_str(" | ")?;
217 }
218 first = false;
219 f.write_str(name)?;
220 }
221
222 let unknown = self.bits() & !Self::KNOWN_BITS;
223 if unknown != 0 || first {
224 if !first {
225 f.write_str(" | ")?;
226 }
227 write!(f, "0x{unknown:x}")?;
228 }
229
230 f.write_str(")")
231 }
232}
233
234impl fmt::Binary for Tag {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 fmt::Binary::fmt(&self.bits(), f)
237 }
238}
239
240impl fmt::Octal for Tag {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 fmt::Octal::fmt(&self.bits(), f)
243 }
244}
245
246impl fmt::LowerHex for Tag {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 fmt::LowerHex::fmt(&self.bits(), f)
249 }
250}
251
252impl fmt::UpperHex for Tag {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 fmt::UpperHex::fmt(&self.bits(), f)
255 }
256}
257
258impl BitOr for Tag {
259 type Output = Self;
260
261 #[inline]
262 fn bitor(self, other: Self) -> Self {
263 self.union(other)
264 }
265}
266
267impl BitOrAssign for Tag {
268 #[inline]
269 fn bitor_assign(&mut self, other: Self) {
270 self.insert(other);
271 }
272}
273
274impl BitAnd for Tag {
275 type Output = Self;
276
277 #[inline]
278 fn bitand(self, other: Self) -> Self {
279 self.intersection(other)
280 }
281}
282
283impl BitAndAssign for Tag {
284 #[inline]
285 fn bitand_assign(&mut self, other: Self) {
286 *self = self.intersection(other);
287 }
288}
289
290impl BitXor for Tag {
291 type Output = Self;
292
293 #[inline]
294 fn bitxor(self, other: Self) -> Self {
295 self.symmetric_difference(other)
296 }
297}
298
299impl BitXorAssign for Tag {
300 #[inline]
301 fn bitxor_assign(&mut self, other: Self) {
302 self.toggle(other);
303 }
304}
305
306impl Sub for Tag {
307 type Output = Self;
308
309 #[inline]
310 fn sub(self, other: Self) -> Self {
311 self.difference(other)
312 }
313}
314
315impl SubAssign for Tag {
316 #[inline]
317 fn sub_assign(&mut self, other: Self) {
318 self.remove(other);
319 }
320}
321
322impl Not for Tag {
323 type Output = Self;
324
325 #[inline]
326 fn not(self) -> Self {
327 self.complement()
328 }
329}
330
331impl Extend<Tag> for Tag {
332 fn extend<T: IntoIterator<Item = Self>>(&mut self, iter: T) {
333 for item in iter {
334 self.insert(item);
335 }
336 }
337}
338
339impl FromIterator<Tag> for Tag {
340 fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
341 let mut result = Self::empty();
342 result.extend(iter);
343 result
344 }
345}
346
347impl IntoIterator for Tag {
348 type IntoIter = TagIter;
349 type Item = Tag;
350
351 fn into_iter(self) -> Self::IntoIter {
352 self.iter()
353 }
354}
355
356impl TryFrom<u8> for Tag {
357 type Error = crate::Error;
358
359 fn try_from(other: u8) -> Result<Self, Self::Error> {
360 Self::from_bits(other).ok_or(crate::Error::InvalidValue {
361 context: crate::ErrorContext::Tag,
362 actual: other as u64,
363 constraint: crate::ValueConstraint::AllowedBits {
364 mask: Self::KNOWN_BITS as u64,
365 },
366 })
367 }
368}
369
370#[derive(Clone, Debug)]
372pub struct TagIter {
373 remaining: Tag,
374 index: usize,
375 yielded_unknown: bool,
376}
377
378impl Iterator for TagIter {
379 type Item = Tag;
380
381 fn next(&mut self) -> Option<Self::Item> {
382 while self.index < TAG_ITER_FLAGS.len() {
383 let flag = TAG_ITER_FLAGS[self.index];
384 self.index += 1;
385
386 if self.remaining.contains(flag) {
387 self.remaining.remove(flag);
388 return Some(flag);
389 }
390 }
391
392 let unknown = self.remaining.bits() & !Tag::KNOWN_BITS;
393 if unknown != 0 && !self.yielded_unknown {
394 self.yielded_unknown = true;
395 self.remaining.remove(Tag::from_bits_retain(unknown));
396 Some(Tag::from_bits_retain(unknown))
397 } else {
398 None
399 }
400 }
401}
402
403#[derive(Clone, Debug)]
405pub struct TagIterNames {
406 remaining: Tag,
407 index: usize,
408}
409
410impl Iterator for TagIterNames {
411 type Item = (&'static str, Tag);
412
413 fn next(&mut self) -> Option<Self::Item> {
414 while self.index < TAG_ITER_NAMES.len() {
415 let (name, flag) = TAG_ITER_NAMES[self.index];
416 self.index += 1;
417
418 if self.remaining.contains(flag) {
419 self.remaining.remove(flag);
420 return Some((name, flag));
421 }
422 }
423
424 None
425 }
426}
427
428#[cfg(test)]
429mod tests {
430 use super::Tag;
431
432 #[test]
433 fn tag_constructors_and_names_cover_known_and_unknown_bits() {
434 assert_eq!(Tag::default(), Tag::empty());
435 assert_eq!(Tag::default(), Tag::MESSAGE);
436 assert_eq!(Tag::all(), Tag::FINAL);
437
438 for bits in 0..=u8::MAX {
439 let retained = Tag::from_bits_retain(bits);
440 assert_eq!(retained.bits(), bits);
441 assert_eq!(Tag::from_bits_truncate(bits).bits(), bits & Tag::KNOWN_BITS);
442
443 let expected = if bits & !Tag::KNOWN_BITS == 0 {
444 Some(retained)
445 } else {
446 None
447 };
448 assert_eq!(Tag::from_bits(bits), expected);
449 }
450
451 assert_eq!(
452 Tag::try_from(Tag::FINAL.bits()).expect("known tag bits should be accepted"),
453 Tag::FINAL
454 );
455 assert_eq!(Tag::from_name("MESSAGE"), Some(Tag::MESSAGE));
456 assert_eq!(Tag::from_name("PUSH"), Some(Tag::PUSH));
457 assert_eq!(Tag::from_name("REKEY"), Some(Tag::REKEY));
458 assert_eq!(Tag::from_name("FINAL"), Some(Tag::FINAL));
459 assert_eq!(Tag::from_name("UNKNOWN"), None);
460 }
461
462 #[test]
463 fn tag_from_u8_rejects_unknown_bits() {
464 let error = Tag::try_from(0x80).expect_err("unknown tag bits should be rejected");
465
466 assert!(matches!(
467 error,
468 crate::Error::InvalidValue {
469 context: crate::ErrorContext::Tag,
470 actual: 0x80,
471 constraint: crate::ValueConstraint::AllowedBits { .. },
472 }
473 ));
474 }
475
476 #[test]
477 fn tag_predicates_and_mutators_match_flag_semantics() {
478 assert!(Tag::empty().is_empty());
479 assert!(Tag::MESSAGE.is_empty());
480 assert!(!Tag::PUSH.is_empty());
481 assert!(Tag::FINAL.is_all());
482 assert!(Tag::from_bits_retain(Tag::FINAL.bits() | 0x80).is_all());
483 assert!(!Tag::PUSH.is_all());
484
485 assert!(Tag::FINAL.contains(Tag::PUSH));
486 assert!(Tag::PUSH.contains(Tag::MESSAGE));
487 assert!(!Tag::PUSH.contains(Tag::REKEY));
488 assert!(Tag::FINAL.intersects(Tag::PUSH));
489 assert!(!Tag::PUSH.intersects(Tag::REKEY));
490
491 let mut tag = Tag::empty();
492 tag.insert(Tag::PUSH);
493 assert_eq!(tag, Tag::PUSH);
494 tag.insert(Tag::REKEY);
495 assert_eq!(tag, Tag::FINAL);
496 tag.remove(Tag::PUSH);
497 assert_eq!(tag, Tag::REKEY);
498 tag.toggle(Tag::PUSH);
499 assert_eq!(tag, Tag::FINAL);
500 tag.set(Tag::REKEY, false);
501 assert_eq!(tag, Tag::PUSH);
502 tag.set(Tag::REKEY, true);
503 assert_eq!(tag, Tag::FINAL);
504 tag.clear();
505 assert_eq!(tag, Tag::empty());
506 }
507
508 #[test]
509 fn tag_set_operations_and_operators_match_flag_semantics() {
510 assert_eq!(Tag::PUSH.union(Tag::REKEY), Tag::FINAL);
511 assert_eq!(Tag::FINAL.intersection(Tag::PUSH), Tag::PUSH);
512 assert_eq!(Tag::FINAL.difference(Tag::PUSH), Tag::REKEY);
513 assert_eq!(Tag::FINAL.symmetric_difference(Tag::PUSH), Tag::REKEY);
514 assert_eq!(Tag::PUSH.complement(), Tag::REKEY);
515
516 assert_eq!(Tag::PUSH | Tag::REKEY, Tag::FINAL);
517 assert_eq!(Tag::FINAL & Tag::PUSH, Tag::PUSH);
518 assert_eq!(Tag::FINAL ^ Tag::PUSH, Tag::REKEY);
519 assert_eq!(Tag::FINAL - Tag::PUSH, Tag::REKEY);
520 assert_eq!(!Tag::PUSH, Tag::REKEY);
521
522 let mut tag = Tag::PUSH;
523 tag |= Tag::REKEY;
524 assert_eq!(tag, Tag::FINAL);
525 tag &= Tag::PUSH;
526 assert_eq!(tag, Tag::PUSH);
527 tag ^= Tag::REKEY;
528 assert_eq!(tag, Tag::FINAL);
529 tag -= Tag::PUSH;
530 assert_eq!(tag, Tag::REKEY);
531 }
532
533 #[test]
534 fn tag_iterators_skip_zero_bit_message_and_retain_unknown_bits() {
535 assert_eq!(Tag::MESSAGE.iter().collect::<Vec<_>>(), Vec::<Tag>::new());
536 assert_eq!(
537 Tag::FINAL.iter().collect::<Vec<_>>(),
538 vec![Tag::PUSH, Tag::REKEY]
539 );
540 assert_eq!(
541 Tag::FINAL.iter_names().collect::<Vec<_>>(),
542 vec![("PUSH", Tag::PUSH), ("REKEY", Tag::REKEY)]
543 );
544
545 let unknown = Tag::from_bits_retain(0x80);
546 let retained = Tag::from_bits_retain(Tag::FINAL.bits() | unknown.bits());
547
548 assert_eq!(
549 retained.iter().collect::<Vec<_>>(),
550 vec![Tag::PUSH, Tag::REKEY, unknown]
551 );
552 assert_eq!(
553 retained.iter_names().collect::<Vec<_>>(),
554 vec![("PUSH", Tag::PUSH), ("REKEY", Tag::REKEY)]
555 );
556 assert_eq!(unknown.iter().collect::<Vec<_>>(), vec![unknown]);
557 assert_eq!(unknown.iter_names().collect::<Vec<_>>(), Vec::new());
558 assert_eq!(
559 Tag::FINAL.into_iter().collect::<Vec<_>>(),
560 vec![Tag::PUSH, Tag::REKEY]
561 );
562 }
563
564 #[test]
565 fn tag_formatting_matches_bitflags_style() {
566 assert_eq!(format!("{:?}", Tag::empty()), "Tag(0x0)");
567 assert_eq!(format!("{:?}", Tag::MESSAGE), "Tag(0x0)");
568 assert_eq!(format!("{:?}", Tag::PUSH), "Tag(PUSH)");
569 assert_eq!(format!("{:?}", Tag::REKEY), "Tag(REKEY)");
570 assert_eq!(format!("{:?}", Tag::FINAL), "Tag(PUSH | REKEY)");
571
572 let retained = Tag::from_bits_retain(Tag::FINAL.bits() | 0x80);
573 assert_eq!(format!("{retained:?}"), "Tag(PUSH | REKEY | 0x80)");
574 assert_eq!(format!("{retained:b}"), format!("{:b}", retained.bits()));
575 assert_eq!(format!("{retained:o}"), format!("{:o}", retained.bits()));
576 assert_eq!(format!("{retained:x}"), format!("{:x}", retained.bits()));
577 assert_eq!(format!("{retained:X}"), format!("{:X}", retained.bits()));
578 assert_eq!(
579 format!("{retained:#04x}"),
580 format!("{:#04x}", retained.bits())
581 );
582 }
583
584 #[test]
585 fn tag_collection_traits_accumulate_flags() {
586 let mut tag = Tag::empty();
587 tag.extend([Tag::PUSH, Tag::REKEY]);
588 assert_eq!(tag, Tag::FINAL);
589
590 let tag: Tag = [Tag::PUSH, Tag::REKEY].into_iter().collect();
591 assert_eq!(tag, Tag::FINAL);
592 }
593}