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}