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/// # 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}