dcbor/
cbor_tagged_encodable.rs

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