Skip to main content

co_primitives/types/
metadata.rs

1// SPDX-License-Identifier: AGPL-3.0-only
2// Copyright (C) 2026 1io BRANDGUARDIAN GmbH
3
4use serde::{Deserialize, Serialize};
5
6/// Special CO metadata.
7pub trait CoMetadata: Serialize {
8	fn metadata() -> Vec<Metadata>;
9}
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub enum Metadata {
13	/// External field namess.
14	#[serde(rename = "ext")]
15	External(Vec<String>),
16}
17
18#[derive(Clone, Serialize)]
19pub struct WithCoMetadata<T: CoMetadata + Serialize> {
20	#[serde(rename = "$co", skip_serializing_if = "Vec::is_empty")]
21	co: Vec<Metadata>,
22	#[serde(flatten)]
23	value: T,
24}
25impl<T> WithCoMetadata<T>
26where
27	T: CoMetadata + Serialize,
28{
29	pub fn new(value: T) -> Self {
30		Self { co: T::metadata(), value }
31	}
32}
33impl<T: CoMetadata + Serialize> From<T> for WithCoMetadata<T> {
34	fn from(value: T) -> Self {
35		WithCoMetadata::new(value)
36	}
37}
38
39// pub fn serialize_with_metadata<T: CoMetadata + Serialize, S: serde::Serializer>(
40// 	serializer: S,
41// 	value: T,
42// ) -> Result<S::Ok, S::Error> {
43// 	WithCoMetadata::new(value).serialize(serializer)
44// }
45
46// Workaround for https://github.com/rust-lang/rust/issues/50133
47// pub struct WithCoMetadataWrapper<T>(T);
48// impl<T: CoMetadata> Into<WithCoMetadataWrapper<T>> for WithCoMetadata<T> {
49// 	fn into(self) -> WithCoMetadataWrapper<T> {
50// 		WithCoMetadataWrapper(self.value)
51// 	}
52// }
53// impl<T: CoMetadata> Into<WithCoMetadata<T>> for T {
54// 	fn into(self) -> WithCoMetadata<T> {
55// 		WithCoMetadata::new(self)
56// 	}
57// }
58
59#[cfg(test)]
60mod tests {
61	use super::WithCoMetadata;
62	use crate::{CoMetadata, Metadata};
63	use cid::Cid;
64	use co_macros::TaggedFields;
65	use serde::{Deserialize, Serialize};
66
67	#[test]
68	fn metadata() {
69		#[derive(Debug, Clone, Serialize, Deserialize)]
70		// error[E0275]: overflow evaluating the requirement `&mut Vec<u8>: Sized`
71		// #[serde(into = "WithCoMetadata<Test>")]
72		struct Test {
73			hello: i32,
74			world: Cid,
75		}
76		impl CoMetadata for Test {
77			fn metadata() -> Vec<crate::Metadata> {
78				vec![Metadata::External(vec!["world".to_owned()])]
79			}
80		}
81		// impl Serialize for Test {
82		// 	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83		// 	where
84		// 		S: serde::Serializer,
85		// 	{
86		// 		self.serialize_with_metadata(serializer)
87		// 	}
88		// }
89
90		let json = serde_json::to_string_pretty(&WithCoMetadata::new(Test {
91			hello: 1,
92			world: Cid::try_from("bafyr4igf663hpuvdpvque42uxmkbacg5ubd4cgageulmwmqo33g2tpod7e").unwrap(),
93		}))
94		.unwrap();
95		println!("{json}");
96	}
97
98	#[test]
99	fn metadata_derive() {
100		#[derive(Debug, Clone, Serialize, Deserialize, TaggedFields)]
101		struct Test {
102			hello: i32,
103			#[tagged(external)]
104			world: Cid,
105		}
106		let json = serde_json::to_string_pretty(&WithCoMetadata::new(Test {
107			hello: 1,
108			world: Cid::try_from("bafyr4igf663hpuvdpvque42uxmkbacg5ubd4cgageulmwmqo33g2tpod7e").unwrap(),
109		}))
110		.unwrap();
111		println!("{json}");
112	}
113}
114
115// impl<T> From<WithCoMetadata<T>> for T
116// where
117// 	T: CoMetadata,
118// {
119// 	fn from(value: WithCoMetadata<T>) -> Self {
120// 		value.value
121// 	}
122// }
123
124// impl<T: CoMetadata> Into<T> for WithCoMetadata<T> {
125// 	fn into(self) -> T {
126// 		self.value
127// 	}
128// }
129
130// #[proc_macro_attribute]
131// pub fn co_metadata(attr: TokenStream, input: TokenStream) -> TokenStream {
132// }
133
134// macro_rules! metadata_serialize {
135// 	($t:ident) => {
136// 		impl Serialize for X {
137// 			fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
138// 				#[derive(Serialize)]
139// 				struct XSerialize {
140// 					a: u32,
141// 					b: u32,
142// 					c: u32,
143// 					$co: &'static str,
144// 				}
145
146// 				XSerialize { a: self.a, b: self.b, c: self.c, d: "only at serialization" }.serialize(serializer)
147// 			}
148// 		}
149// 	};
150// }
151
152// impl Serialize for X {
153// 	fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
154// 		#[derive(Serialize)]
155// 		struct XSerialize {
156// 			a: u32,
157// 			b: u32,
158// 			c: u32,
159// 			d: &'static str,
160// 		}
161
162// 		XSerialize { a: self.a, b: self.b, c: self.c, d: "only at serialization" }.serialize(serializer)
163// 	}
164// }