Skip to main content

iab_specs_core/
extension.rs

1//! Extension Trait
2//!
3//! This module defines the `Extension` trait that all extension objects must implement.
4//! The trait ensures that extension types are serializable, deserializable, cloneable,
5//! debuggable, and have default values.
6//!
7//! # Overview
8//!
9//! The `Extension` trait provides a flexible mechanism for adding custom fields to IAB
10//! specification objects. This is particularly useful for:
11//! - Vendor-specific data
12//! - Internal tracking information
13//! - Experimental features
14//! - Custom business logic fields
15
16use serde::{Deserialize, Serialize};
17
18/// Extension trait for extension objects.
19///
20/// This trait defines the requirements for any type that can be used as an extension
21/// field (`ext`). All extension types must be:
22///
23/// - **Serializable**: Can be converted to various formats (JSON, YAML, etc.)
24/// - **Deserializable**: Can be parsed from various formats
25/// - **Cloneable**: Can be duplicated
26/// - **Debuggable**: Can be formatted for debugging
27/// - **Default**: Has a sensible default value
28/// - **Comparable**: Can be compared for equality
29/// - **Send**: Can be transferred between threads
30/// - **Sync**: Can be shared between threads
31///
32/// # Automatic Implementation
33///
34/// Any type that implements `Serialize`, `Deserialize`, `Clone`, `Debug`, `Default`,
35/// `PartialEq`, `Send`, and `Sync` automatically implements `Extension`.
36pub trait Extension:
37    Serialize + for<'de> Deserialize<'de> + Clone + std::fmt::Debug + Default + PartialEq + Send + Sync
38{
39}
40
41// Blanket implementation for any type that satisfies the trait bounds
42impl<T> Extension for T where
43    T: Serialize
44        + for<'de> Deserialize<'de>
45        + Clone
46        + std::fmt::Debug
47        + Default
48        + PartialEq
49        + Send
50        + Sync
51{
52}
53
54/// Default extension type.
55///
56/// `Vec<u8>` is used as the default extension type, representing opaque bytes.
57/// This is serde-agnostic: callers choose the serialization format by specifying
58/// an explicit type parameter (e.g., `serde_json::Value` for JSON, or a custom
59/// protobuf-decoded type) when they need typed extensions.
60pub type DefaultExt = Vec<u8>;
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
67    struct TestExtension {
68        field1: String,
69        field2: i32,
70    }
71
72    #[test]
73    fn test_custom_type_implements_extension() {
74        fn requires_extension<E: Extension>(_ext: E) {}
75
76        let ext = TestExtension {
77            field1: "test".to_string(),
78            field2: 42,
79        };
80
81        requires_extension(ext);
82    }
83
84    #[test]
85    fn test_json_value_implements_extension() {
86        fn requires_extension<E: Extension>(_ext: E) {}
87
88        let ext = serde_json::json!({"key": "value"});
89        requires_extension(ext);
90    }
91
92    #[test]
93    fn test_unit_type_implements_extension() {
94        fn requires_extension<E: Extension>(_ext: E) {}
95
96        requires_extension(());
97    }
98
99    #[test]
100    fn test_option_implements_extension() {
101        fn requires_extension<E: Extension>(_ext: Option<E>) {}
102
103        let ext: Option<TestExtension> = Some(TestExtension::default());
104        requires_extension(ext);
105    }
106
107    #[test]
108    fn test_vec_u8_implements_extension() {
109        fn requires_extension<E: Extension>(_ext: E) {}
110
111        let ext: Vec<u8> = vec![0x08, 0x96, 0x01];
112        requires_extension(ext);
113    }
114
115    #[test]
116    fn test_default_ext_is_vec_u8() {
117        let ext = DefaultExt::default();
118        assert!(ext.is_empty());
119        assert_eq!(ext, Vec::<u8>::new());
120    }
121}