Skip to main content

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/// The registration macros validate codecs through the matching descriptor.
26/// Encoder and decoder error types must implement `Error + Send + Sync +
27/// 'static`; codec and value types do not need those bounds.
28///
29/// # Type Parameters
30///
31/// - `D`: Executable codec descriptor type; `'static` lets the registry keep a
32///   borrowed `&'static D` for the whole program run.
33///
34/// # Examples
35///
36/// ```
37/// # #[cfg(feature = "json")]
38/// # {
39/// use qubit_codec::JsonStringValueCodec;
40/// use qubit_codec::ValueCodecId;
41/// use qubit_codec::ValueCodecRegistration;
42/// use qubit_codec::ValueCodecRegistrationSource;
43/// use qubit_codec::ValueStringCodecDescriptor;
44/// use qubit_codec::ValueStringCodecRegistration;
45///
46/// static DESCRIPTOR: ValueStringCodecDescriptor =
47///     ValueStringCodecDescriptor::of::<JsonStringValueCodec<u32>, u32>();
48///
49/// let registration: ValueStringCodecRegistration = ValueCodecRegistration::new(
50///     ValueCodecId::new("example.u32"),
51///     &DESCRIPTOR,
52///     ValueCodecRegistrationSource::new(
53///         "qubit-codec",
54///         "doctest",
55///         "src/value/value_codec_registration.rs",
56///         1,
57///     ),
58/// );
59/// assert_eq!(registration.id().as_str(), "example.u32");
60/// # }
61/// ```
62#[derive(Clone, Copy, Debug)]
63pub struct ValueCodecRegistration<D: 'static> {
64    /// Stable identifier shared with registry lookups and duplicate detection.
65    id: ValueCodecId,
66    /// Executable descriptor borrowed from static storage.
67    descriptor: &'static D,
68    /// Link-time location the registration was declared at.
69    source: ValueCodecRegistrationSource,
70}
71
72/// A string-wire value-codec registration.
73pub type ValueStringCodecRegistration = ValueCodecRegistration<ValueStringCodecDescriptor>;
74
75/// A bytes-wire value-codec registration.
76pub type ValueBytesCodecRegistration = ValueCodecRegistration<ValueBytesCodecDescriptor>;
77
78impl<D: 'static> ValueCodecRegistration<D> {
79    /// Creates a registration from validated static facts.
80    ///
81    /// # Parameters
82    ///
83    /// - `id`: Stable identifier for registry lookups.
84    /// - `descriptor`: Executable descriptor borrowed from static storage.
85    /// - `source`: Link-time location recorded for diagnostics.
86    ///
87    /// # Returns
88    ///
89    /// Returns a registration that borrows `descriptor` for the whole run.
90    ///
91    /// Prefer [`register_value_string_codec!
92    /// `](crate::register_value_string_codec)
93    /// or [`register_value_bytes_codec!`](crate::register_value_bytes_codec)
94    /// over calling this directly.
95    #[doc(hidden)]
96    #[inline]
97    #[must_use]
98    pub const fn new(id: ValueCodecId, descriptor: &'static D, source: ValueCodecRegistrationSource) -> Self {
99        Self { id, descriptor, source }
100    }
101
102    /// Returns the stable value-codec ID.
103    ///
104    /// # Returns
105    ///
106    /// Returns the identifier this registration was filed under.
107    #[inline]
108    #[must_use]
109    pub const fn id(&self) -> ValueCodecId {
110        self.id
111    }
112
113    /// Returns the executable descriptor.
114    ///
115    /// # Returns
116    ///
117    /// Returns the borrowed static descriptor, valid for the whole program run.
118    #[inline]
119    #[must_use]
120    pub const fn descriptor(&self) -> &'static D {
121        self.descriptor
122    }
123
124    /// Returns the linked source location.
125    ///
126    /// # Returns
127    ///
128    /// Returns the link-time crate, module, file, and line of the declaration.
129    #[inline]
130    #[must_use]
131    pub const fn source(&self) -> ValueCodecRegistrationSource {
132        self.source
133    }
134}
135
136/// Registers a default-constructible bidirectional string codec.
137///
138/// The macro must be invoked at module scope; it defines the descriptor, a
139/// registration function, and an inventory submission in an anonymous const.
140/// The `id` must be a constant expression. Use a literal, constant, or
141/// `const fn` result; a runtime function call cannot define a static ID.
142/// The encoder and decoder error types must implement `Error + Send + Sync +
143/// 'static`, as required by [`ValueStringCodecDescriptor::of`].
144///
145/// # Examples
146///
147/// ```compile_fail
148/// use qubit_codec::JsonStringValueCodec;
149/// use qubit_codec::register_value_string_codec;
150///
151/// fn invalid_id() -> &'static str { "example.u32" }
152/// register_value_string_codec!(id = invalid_id(), codec = JsonStringValueCodec<u32>, value = u32);
153/// ```
154///
155/// ```compile_fail
156/// use qubit_codec::JsonStringValueCodec;
157/// use qubit_codec::register_value_string_codec;
158/// register_value_string_codec!(id = "invalid-id", codec = JsonStringValueCodec<u32>, value = u32);
159/// ```
160///
161/// ```
162/// # #[cfg(feature = "json")]
163/// # {
164/// use qubit_codec::JsonStringValueCodec;
165/// use qubit_codec::register_value_string_codec;
166///
167/// register_value_string_codec!(
168///     id = "example.u32",
169///     codec = JsonStringValueCodec<u32>,
170///     value = u32,
171/// );
172/// # }
173/// ```
174#[macro_export]
175macro_rules! register_value_string_codec {
176    (id = $id:expr, codec = $codec:ty, value = $value:ty $(,)?) => {
177        const _: () = {
178            const ID: $crate::ValueCodecId = $crate::ValueCodecId::new($id);
179            static DESCRIPTOR: $crate::ValueStringCodecDescriptor =
180                $crate::ValueStringCodecDescriptor::of::<$codec, $value>();
181
182            fn registration() -> $crate::ValueStringCodecRegistration {
183                $crate::ValueCodecRegistration::new(
184                    ID,
185                    &DESCRIPTOR,
186                    $crate::ValueCodecRegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
187                )
188            }
189
190            $crate::__private::inventory::submit! {
191                $crate::ValueStringCodecRegistrationFactory(registration)
192            }
193        };
194    };
195}
196
197/// Registers a default-constructible bidirectional bytes codec.
198///
199/// The macro must be invoked at module scope; it defines the descriptor, a
200/// registration function, and an inventory submission in an anonymous const.
201/// The `id` must be a constant expression. Use a literal, constant, or
202/// `const fn` result; a runtime function call cannot define a static ID.
203/// The encoder and decoder error types must implement `Error + Send + Sync +
204/// 'static`, as required by [`ValueBytesCodecDescriptor::of`].
205///
206/// # Examples
207///
208/// ```compile_fail
209/// use qubit_codec::JsonBytesValueCodec;
210/// use qubit_codec::register_value_bytes_codec;
211/// register_value_bytes_codec!(id = "invalid-id", codec = JsonBytesValueCodec<u32>, value = u32);
212/// ```
213///
214/// ```
215/// # #[cfg(feature = "json")]
216/// # {
217/// use qubit_codec::JsonBytesValueCodec;
218/// use qubit_codec::register_value_bytes_codec;
219///
220/// register_value_bytes_codec!(
221///     id = "example.u32",
222///     codec = JsonBytesValueCodec<u32>,
223///     value = u32,
224/// );
225/// # }
226/// ```
227#[macro_export]
228macro_rules! register_value_bytes_codec {
229    (id = $id:expr, codec = $codec:ty, value = $value:ty $(,)?) => {
230        const _: () = {
231            const ID: $crate::ValueCodecId = $crate::ValueCodecId::new($id);
232            static DESCRIPTOR: $crate::ValueBytesCodecDescriptor =
233                $crate::ValueBytesCodecDescriptor::of::<$codec, $value>();
234
235            fn registration() -> $crate::ValueBytesCodecRegistration {
236                $crate::ValueCodecRegistration::new(
237                    ID,
238                    &DESCRIPTOR,
239                    $crate::ValueCodecRegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
240                )
241            }
242
243            $crate::__private::inventory::submit! {
244                $crate::ValueBytesCodecRegistrationFactory(registration)
245            }
246        };
247    };
248}