dcbor/cbor_tagged.rs
1import_stdlib!();
2
3use crate::Tag;
4
5/// # CBOR Tagged Value Support
6///
7/// CBOR allows values to be "tagged" with semantic information using tag
8/// numbers. The dCBOR library provides a set of traits for working with tagged
9/// values in a type-safe manner.
10///
11/// Tags in CBOR provide additional context about how a value should be
12/// interpreted. For example, tag 1 is used for dates, indicating the value is a
13/// timestamp.
14///
15/// This trait system allows Rust types to define their associated CBOR tags
16/// and provide serialization/deserialization logic specifically for tagged
17/// values. A trait for types that have an associated CBOR tag.
18///
19/// In CBOR, tags provide semantic information about how to interpret data
20/// items. This trait defines which CBOR tag(s) are associated with a particular
21/// Rust type.
22///
23/// Implementing this trait is a prerequisite for implementing
24/// `CBORTaggedEncodable` and `CBORTaggedDecodable`.
25///
26/// ## Multiple Tags for Backward Compatibility
27///
28/// The `cbor_tags()` method returns a vector of tags, enabling support for
29/// backward compatibility with older tag versions:
30///
31/// - **When encoding**: Only the first tag in the vector is used for
32/// serialization
33/// - **When decoding**: Any of the tags in the vector will be accepted
34///
35/// This design solves several real-world problems:
36///
37/// 1. **IANA Registration Simplification**: If you initially choose a tag in
38/// the Specification Required range (24-32767) and later want to move to the
39/// simpler First Come First Served range (32768+), you can migrate while
40/// maintaining compatibility with existing data.
41///
42/// 2. **Protocol Evolution**: As your protocol evolves, you can introduce new
43/// preferred tags while still supporting data encoded with older tags.
44///
45/// 3. **Versioning**: Different tags can represent different versions of your
46/// data format while sharing the same Rust type for handling.
47///
48/// ## Example: Single Tag
49///
50/// ```
51/// use dcbor::prelude::*;
52///
53/// // Define a Date struct
54/// #[derive(Debug, Clone, PartialEq)]
55/// struct Date(f64); // Storing timestamp as seconds since epoch
56///
57/// // Associate with CBOR tag 1 (standard date tag)
58/// impl CBORTagged for Date {
59/// fn cbor_tags() -> Vec<Tag> { vec![Tag::with_value(1)] }
60/// }
61///
62/// // Now the Date type has an association with CBOR tag 1
63/// let tags = Date::cbor_tags();
64/// assert_eq!(tags[0].value(), 1);
65/// ```
66///
67/// ## Example: Multiple Tags for Backward Compatibility
68///
69/// ```
70/// use dcbor::prelude::*;
71///
72/// // Seed data structure for cryptographic operations
73/// #[derive(Debug, Clone, PartialEq)]
74/// struct Seed {
75/// bytes: [u8; 16], // Example seed data
76/// }
77///
78/// // Associate with two tags:
79/// // - Tag 40300 (First Come First Served IANA range, used for encoding)
80/// // - Tag 300 (legacy tag in the Specification Required range, still accepted for decoding)
81/// impl CBORTagged for Seed {
82/// fn cbor_tags() -> Vec<Tag> {
83/// vec![
84/// // Primary tag (used for all new encodings)
85/// Tag::with_value(40300), // Higher range (32768+) only needs First Come First Served registration
86///
87/// // Legacy tag (accepted when decoding old data)
88/// Tag::with_value(300), // Originally chosen tag in Specification Required range (24-32767)
89/// ]
90/// }
91/// }
92///
93/// // New data is encoded with tag 40300
94/// let seed = Seed { bytes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] };
95///
96/// // But when decoding, the system can still read data tagged with either
97/// // 40300 or 300, ensuring backward compatibility with existing data
98/// ```
99pub trait CBORTagged {
100 /// Returns the CBOR tags associated with this type.
101 ///
102 /// This method should return a vector of tags in order of preference:
103 ///
104 /// - The first tag in the vector is the "preferred" tag and will be used
105 /// when encoding values of this type via
106 /// `CBORTaggedEncodable::tagged_cbor()`.
107 ///
108 /// - All tags in the vector are considered equivalent for decoding. When
109 /// `CBORTaggedDecodable::from_tagged_cbor()` is called, any tag in this
110 /// vector will be accepted as valid for this type.
111 ///
112 /// This design enables backward compatibility: you can introduce a new tag
113 /// (placed first in the vector) while still supporting older tags for
114 /// decoding.
115 ///
116 /// For standard CBOR tags, you can use predefined tag constants from the
117 /// `tags` module, or create custom tags with `Tag::with_value()`.
118 fn cbor_tags() -> Vec<Tag>;
119}