qubit_codec/value/value_codec_registration.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9//! Distributed value-codec registrations.
10
11use crate::ValueBytesCodecDescriptor;
12use crate::ValueCodecId;
13use crate::ValueCodecRegistrationSource;
14use crate::ValueStringCodecDescriptor;
15
16/// One statically linked value-codec implementation.
17///
18/// A registration bundles the stable identifier used for lookup and duplicate
19/// detection, a borrowed executable descriptor, and the link-time location the
20/// registration was declared at. It is produced by
21/// [`register_value_string_codec!`](crate::register_value_string_codec) or
22/// [`register_value_bytes_codec!`](crate::register_value_bytes_codec) rather
23/// than built by hand.
24///
25/// # Type Parameters
26///
27/// - `D`: Executable codec descriptor type; `'static` lets the registry keep a
28/// borrowed `&'static D` for the whole program run.
29///
30/// # Examples
31///
32/// ```
33/// use qubit_codec::JsonStringValueCodec;
34/// use qubit_codec::ValueCodecId;
35/// use qubit_codec::ValueCodecRegistration;
36/// use qubit_codec::ValueCodecRegistrationSource;
37/// use qubit_codec::ValueStringCodecDescriptor;
38/// use qubit_codec::ValueStringCodecRegistration;
39///
40/// static DESCRIPTOR: ValueStringCodecDescriptor =
41/// ValueStringCodecDescriptor::of::<JsonStringValueCodec<u32>, u32>();
42///
43/// let registration: ValueStringCodecRegistration = ValueCodecRegistration::new(
44/// ValueCodecId::new("example.u32"),
45/// &DESCRIPTOR,
46/// ValueCodecRegistrationSource::new(
47/// "qubit-codec",
48/// "doctest",
49/// "src/value/value_codec_registration.rs",
50/// 1,
51/// ),
52/// );
53/// assert_eq!(registration.id().as_str(), "example.u32");
54/// ```
55#[derive(Clone, Copy, Debug)]
56pub struct ValueCodecRegistration<D: 'static> {
57 /// Stable identifier shared with registry lookups and duplicate detection.
58 id: ValueCodecId,
59 /// Executable descriptor borrowed from static storage.
60 descriptor: &'static D,
61 /// Link-time location the registration was declared at.
62 source: ValueCodecRegistrationSource,
63}
64
65/// A string-wire value-codec registration.
66pub type ValueStringCodecRegistration = ValueCodecRegistration<ValueStringCodecDescriptor>;
67
68/// A bytes-wire value-codec registration.
69pub type ValueBytesCodecRegistration = ValueCodecRegistration<ValueBytesCodecDescriptor>;
70
71impl<D: 'static> ValueCodecRegistration<D> {
72 /// Creates a registration from validated static facts.
73 ///
74 /// # Parameters
75 ///
76 /// - `id`: Stable identifier for registry lookups.
77 /// - `descriptor`: Executable descriptor borrowed from static storage.
78 /// - `source`: Link-time location recorded for diagnostics.
79 ///
80 /// # Returns
81 ///
82 /// Returns a registration that borrows `descriptor` for the whole run.
83 ///
84 /// Prefer [`register_value_string_codec!
85 /// `](crate::register_value_string_codec)
86 /// or [`register_value_bytes_codec!`](crate::register_value_bytes_codec)
87 /// over calling this directly.
88 #[doc(hidden)]
89 #[inline]
90 #[must_use]
91 pub const fn new(id: ValueCodecId, descriptor: &'static D, source: ValueCodecRegistrationSource) -> Self {
92 Self { id, descriptor, source }
93 }
94
95 /// Returns the stable value-codec ID.
96 ///
97 /// # Returns
98 ///
99 /// Returns the identifier this registration was filed under.
100 #[inline]
101 #[must_use]
102 pub const fn id(&self) -> ValueCodecId {
103 self.id
104 }
105
106 /// Returns the executable descriptor.
107 ///
108 /// # Returns
109 ///
110 /// Returns the borrowed static descriptor, valid for the whole program run.
111 #[inline]
112 #[must_use]
113 pub const fn descriptor(&self) -> &'static D {
114 self.descriptor
115 }
116
117 /// Returns the linked source location.
118 ///
119 /// # Returns
120 ///
121 /// Returns the link-time crate, module, file, and line of the declaration.
122 #[inline]
123 #[must_use]
124 pub const fn source(&self) -> ValueCodecRegistrationSource {
125 self.source
126 }
127}
128
129/// Registers a default-constructible bidirectional string codec.
130///
131/// The macro must be invoked at module scope; it defines the descriptor, a
132/// registration function, and an inventory submission in an anonymous const.
133///
134/// # Examples
135///
136/// ```
137/// use qubit_codec::JsonStringValueCodec;
138/// use qubit_codec::register_value_string_codec;
139///
140/// register_value_string_codec!(
141/// id = "example.u32",
142/// codec = JsonStringValueCodec<u32>,
143/// value = u32,
144/// );
145/// ```
146#[macro_export]
147macro_rules! register_value_string_codec {
148 (id = $id:expr, codec = $codec:ty, value = $value:ty $(,)?) => {
149 const _: () = {
150 static DESCRIPTOR: $crate::ValueStringCodecDescriptor =
151 $crate::ValueStringCodecDescriptor::of::<$codec, $value>();
152
153 fn registration() -> $crate::ValueStringCodecRegistration {
154 $crate::ValueCodecRegistration::new(
155 $crate::ValueCodecId::new($id),
156 &DESCRIPTOR,
157 $crate::ValueCodecRegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
158 )
159 }
160
161 $crate::__private::inventory::submit! {
162 $crate::ValueStringCodecRegistrationFactory(registration)
163 }
164 };
165 };
166}
167
168/// Registers a default-constructible bidirectional bytes codec.
169///
170/// The macro must be invoked at module scope; it defines the descriptor, a
171/// registration function, and an inventory submission in an anonymous const.
172///
173/// # Examples
174///
175/// ```
176/// use qubit_codec::JsonBytesValueCodec;
177/// use qubit_codec::register_value_bytes_codec;
178///
179/// register_value_bytes_codec!(
180/// id = "example.u32",
181/// codec = JsonBytesValueCodec<u32>,
182/// value = u32,
183/// );
184/// ```
185#[macro_export]
186macro_rules! register_value_bytes_codec {
187 (id = $id:expr, codec = $codec:ty, value = $value:ty $(,)?) => {
188 const _: () = {
189 static DESCRIPTOR: $crate::ValueBytesCodecDescriptor =
190 $crate::ValueBytesCodecDescriptor::of::<$codec, $value>();
191
192 fn registration() -> $crate::ValueBytesCodecRegistration {
193 $crate::ValueCodecRegistration::new(
194 $crate::ValueCodecId::new($id),
195 &DESCRIPTOR,
196 $crate::ValueCodecRegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
197 )
198 }
199
200 $crate::__private::inventory::submit! {
201 $crate::ValueBytesCodecRegistrationFactory(registration)
202 }
203 };
204 };
205}