qubit-codec 0.17.1

Core codec traits and buffer conversion primitives for Rust
Documentation
// =============================================================================
//    Copyright (c) 2026 Haixing Hu.
//
//    SPDX-License-Identifier: Apache-2.0
//
//    Licensed under the Apache License, Version 2.0.
// =============================================================================

//! Distributed value-codec registrations.

use crate::ValueCodecId;
use crate::ValueCodecRegistrationSource;

/// One statically linked value-codec implementation.
///
/// A registration bundles the stable identifier used for lookup and duplicate
/// detection, a borrowed executable descriptor, and the link-time location the
/// registration was declared at. It is produced by
/// [`register_value_string_codec!`](crate::register_value_string_codec) or
/// [`register_value_bytes_codec!`](crate::register_value_bytes_codec)
/// rather than built by hand.
///
/// The registration macros validate codecs through the matching descriptor.
/// Encoder and decoder error types must implement `Error + Send + Sync +
/// 'static`; codec and value types do not need those bounds.
#[derive(Clone, Copy, Debug)]
pub struct ValueCodecRegistration<D: 'static> {
    /// Stable identifier shared with registry lookups and duplicate detection.
    id: ValueCodecId,
    /// Executable descriptor borrowed from static storage.
    descriptor: &'static D,
    /// Link-time location the registration was declared at.
    source: ValueCodecRegistrationSource,
}

impl<D: 'static> ValueCodecRegistration<D> {
    /// Creates a registration from validated static facts.
    #[doc(hidden)]
    #[inline]
    #[must_use]
    pub const fn new(id: ValueCodecId, descriptor: &'static D, source: ValueCodecRegistrationSource) -> Self {
        Self { id, descriptor, source }
    }

    /// Returns the stable value-codec ID.
    #[inline]
    #[must_use]
    pub const fn id(&self) -> ValueCodecId {
        self.id
    }

    /// Returns the executable descriptor.
    #[inline]
    #[must_use]
    pub const fn descriptor(&self) -> &'static D {
        self.descriptor
    }

    /// Returns the linked source location.
    #[inline]
    #[must_use]
    pub const fn source(&self) -> ValueCodecRegistrationSource {
        self.source
    }
}

/// Registers a default-constructible bidirectional string codec.
///
/// The macro must be invoked at module scope; it defines the descriptor, a
/// registration function, and an inventory submission in an anonymous const.
/// The `id` must be a constant expression. Use a literal, constant, or
/// `const fn` result; a runtime function call cannot define a static ID.
/// The encoder and decoder error types must implement `Error + Send + Sync +
/// 'static`, as required by [`crate::ValueStringCodecDescriptor::of`].
///
/// # Examples
///
/// ```compile_fail
/// use qubit_codec::JsonStringValueCodec;
/// use qubit_codec::register_value_string_codec;
///
/// fn invalid_id() -> &'static str { "example.u32" }
/// register_value_string_codec!(id = invalid_id(), codec = JsonStringValueCodec<u32>, value = u32);
/// ```
///
/// ```compile_fail
/// use qubit_codec::JsonStringValueCodec;
/// use qubit_codec::register_value_string_codec;
/// register_value_string_codec!(id = "invalid-id", codec = JsonStringValueCodec<u32>, value = u32);
/// ```
///
/// ```
/// # #[cfg(feature = "json")]
/// # {
/// use qubit_codec::JsonStringValueCodec;
/// use qubit_codec::register_value_string_codec;
///
/// register_value_string_codec!(
///     id = "example.u32",
///     codec = JsonStringValueCodec<u32>,
///     value = u32,
/// );
/// # }
/// ```
#[macro_export]
macro_rules! register_value_string_codec {
    (id = $id:expr, codec = $codec:ty, value = $value:ty $(,)?) => {
        const _: () = {
            const ID: $crate::ValueCodecId = $crate::ValueCodecId::new($id);
            static DESCRIPTOR: $crate::ValueStringCodecDescriptor =
                $crate::ValueStringCodecDescriptor::of::<$codec, $value>();

            fn registration() -> $crate::ValueStringCodecRegistration {
                $crate::ValueCodecRegistration::new(
                    ID,
                    &DESCRIPTOR,
                    $crate::ValueCodecRegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
                )
            }

            $crate::__private::inventory::submit! {
                $crate::ValueStringCodecRegistrationFactory(registration)
            }
        };
    };
}

/// Registers a default-constructible bidirectional bytes codec.
///
/// The macro must be invoked at module scope; it defines the descriptor, a
/// registration function, and an inventory submission in an anonymous const.
/// The `id` must be a constant expression. Use a literal, constant, or
/// `const fn` result; a runtime function call cannot define a static ID.
/// The encoder and decoder error types must implement `Error + Send + Sync +
/// 'static`, as required by [`crate::ValueBytesCodecDescriptor::of`].
///
/// # Examples
///
/// ```compile_fail
/// use qubit_codec::JsonBytesValueCodec;
/// use qubit_codec::register_value_bytes_codec;
/// register_value_bytes_codec!(id = "invalid-id", codec = JsonBytesValueCodec<u32>, value = u32);
/// ```
///
/// ```
/// # #[cfg(feature = "json")]
/// # {
/// use qubit_codec::JsonBytesValueCodec;
/// use qubit_codec::register_value_bytes_codec;
///
/// register_value_bytes_codec!(
///     id = "example.u32",
///     codec = JsonBytesValueCodec<u32>,
///     value = u32,
/// );
/// # }
/// ```
#[macro_export]
macro_rules! register_value_bytes_codec {
    (id = $id:expr, codec = $codec:ty, value = $value:ty $(,)?) => {
        const _: () = {
            const ID: $crate::ValueCodecId = $crate::ValueCodecId::new($id);
            static DESCRIPTOR: $crate::ValueBytesCodecDescriptor =
                $crate::ValueBytesCodecDescriptor::of::<$codec, $value>();

            fn registration() -> $crate::ValueBytesCodecRegistration {
                $crate::ValueCodecRegistration::new(
                    ID,
                    &DESCRIPTOR,
                    $crate::ValueCodecRegistrationSource::new(env!("CARGO_PKG_NAME"), module_path!(), file!(), line!()),
                )
            }

            $crate::__private::inventory::submit! {
                $crate::ValueBytesCodecRegistrationFactory(registration)
            }
        };
    };
}