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}