dcbor/
cbor_tagged_encodable.rs

1import_stdlib!();
2
3use crate::{CBOR, CBORTagged, CBORCase};
4
5/// # Tagged CBOR Encoding Support
6/// 
7/// This module provides the `CBORTaggedEncodable` trait, which enables types to 
8/// be encoded as tagged CBOR values.
9/// 
10/// CBOR tags provide semantic information about the encoded data. For example,
11/// tag 1 is used for dates, indicating that the value should be interpreted
12/// as a timestamp. The dCBOR library ensures these tags are encoded deterministically.
13///
14/// This trait enables seamless encoding of Rust types to properly tagged CBOR values.
15/// A trait for types that can be encoded to CBOR with a specific tag.
16///
17/// This trait extends `CBORTagged` to provide methods for encoding a value
18/// with its associated tag. Types that implement this trait define how they
19/// should be represented in CBOR format, both with and without their tag.
20///
21/// ## Example
22///
23/// ```
24/// use dcbor::prelude::*;
25///
26/// // Define a Date type
27/// #[derive(Debug, Clone, PartialEq)]
28/// struct Date(f64); // Timestamp as seconds since epoch
29///
30/// // Implement CBORTagged
31/// impl CBORTagged for Date {
32///     fn cbor_tags() -> Vec<Tag> {
33///         vec![Tag::with_value(1)] // Standard date tag
34///     }
35/// }
36///
37/// // Implement encoding to tagged CBOR
38/// impl CBORTaggedEncodable for Date {
39///     fn untagged_cbor(&self) -> CBOR {
40///         // Date content is represented as a number
41///         self.0.into()
42///     }
43/// }
44///
45/// // Create a date and encode it
46/// let date = Date(1609459200.0); // 2021-01-01 00:00:00 UTC
47///
48/// // Get the untagged CBOR (just the timestamp)
49/// let untagged = date.untagged_cbor();
50/// // Timestamp is converted to an integer when it has no fractional part
51/// assert_eq!(untagged.diagnostic(), "1609459200");
52///
53/// // Get the tagged CBOR (with tag 1)
54/// let tagged = date.tagged_cbor();
55/// assert_eq!(tagged.diagnostic(), "1(1609459200)");
56///
57/// // Get binary representation
58/// let data = date.tagged_cbor_data();
59/// ```
60pub trait CBORTaggedEncodable: CBORTagged {
61    /// Returns the untagged CBOR encoding of this instance.
62    ///
63    /// This method defines how the value itself (without its tag) should 
64    /// be represented in CBOR format.
65    fn untagged_cbor(&self) -> CBOR;
66
67    /// Returns the tagged CBOR encoding of this instance.
68    ///
69    /// This method wraps the result of `untagged_cbor()` with the first tag
70    /// from `cbor_tags()`, which is considered the "preferred" tag for the type.
71    /// 
72    /// Even if a type supports multiple tags for backward-compatible decoding
73    /// via `cbor_tags()`, only the first (preferred) tag is used for encoding.
74    /// This ensures consistency in newly created data while maintaining the
75    /// ability to read older formats.
76    ///
77    /// In most cases, you don't need to override this method.
78    fn tagged_cbor(&self) -> CBOR {
79        CBORCase::Tagged(Self::cbor_tags()[0].clone(), self.untagged_cbor()).into()
80    }
81
82    /// Returns the tagged value in CBOR binary representation.
83    ///
84    /// This is a convenience method that converts the result of `tagged_cbor()`
85    /// to binary format.
86    fn tagged_cbor_data(&self) -> Vec<u8> {
87        self.tagged_cbor().to_cbor_data()
88    }
89}