qubit-codec 0.17.2

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.
// =============================================================================
//! Tests the inventory factory that builds string value-codec registrations.

use std::any::TypeId;
use std::io::Error;
use std::ptr;

use qubit_codec::ValueBytesCodecDescriptor;
use qubit_codec::ValueCodecId;
use qubit_codec::ValueCodecRegistration;
use qubit_codec::ValueCodecRegistrationSource;
use qubit_codec::ValueDecoder;
use qubit_codec::ValueEncoder;
use qubit_codec::ValueStringCodecDescriptor;
use qubit_codec::ValueStringCodecRegistration;
use qubit_codec::ValueStringCodecRegistrationFactory;
use qubit_codec::ValueStringCodecRegistry;
use qubit_codec::register_value_string_codec;

#[derive(Default)]
struct MirrorU32StringCodec;

impl ValueEncoder<u32> for MirrorU32StringCodec {
    type Output = String;
    type Error = Error;

    fn encode(&mut self, input: &u32) -> Result<Self::Output, Self::Error> {
        Ok(input.to_string())
    }
}

impl ValueDecoder<str> for MirrorU32StringCodec {
    type Output = u32;
    type Error = Error;

    fn decode(&mut self, input: &str) -> Result<Self::Output, Self::Error> {
        input.parse().map_err(Error::other)
    }
}

#[derive(Default)]
struct ReviewBorrowedCodec;

impl ValueEncoder<[u8]> for ReviewBorrowedCodec {
    type Output = String;
    type Error = Error;

    fn encode(&mut self, input: &[u8]) -> Result<String, Error> {
        String::from_utf8(input.to_vec()).map_err(Error::other)
    }
}

impl ValueDecoder<str> for ReviewBorrowedCodec {
    type Output = Vec<u8>;
    type Error = Error;

    fn decode(&mut self, input: &str) -> Result<Vec<u8>, Error> {
        Ok(input.as_bytes().to_vec())
    }
}

#[derive(Default)]
struct MirrorU32BytesCodec;

impl ValueEncoder<u32> for MirrorU32BytesCodec {
    type Output = Vec<u8>;
    type Error = Error;

    fn encode(&mut self, input: &u32) -> Result<Self::Output, Self::Error> {
        Ok(input.to_be_bytes().to_vec())
    }
}

impl ValueDecoder<[u8]> for MirrorU32BytesCodec {
    type Output = u32;
    type Error = Error;

    fn decode(&mut self, input: &[u8]) -> Result<Self::Output, Self::Error> {
        let bytes: [u8; 4] = input
            .try_into()
            .map_err(|_| Error::other("expected exactly four bytes"))?;
        Ok(u32::from_be_bytes(bytes))
    }
}

static STRING_DESCRIPTOR: ValueStringCodecDescriptor = ValueStringCodecDescriptor::of::<MirrorU32StringCodec, u32>();
static BYTES_DESCRIPTOR: ValueBytesCodecDescriptor = ValueBytesCodecDescriptor::of::<MirrorU32BytesCodec, u32>();

fn build_first() -> ValueStringCodecRegistration {
    ValueCodecRegistration::new(
        ValueCodecId::new("mirror.factory.string.first"),
        &STRING_DESCRIPTOR,
        ValueCodecRegistrationSource::new("mirror-crate", "mirror::factory", "src/factory.rs", 17),
    )
}

fn build_second() -> ValueStringCodecRegistration {
    ValueCodecRegistration::new(
        ValueCodecId::new("mirror.factory.string.second"),
        &STRING_DESCRIPTOR,
        ValueCodecRegistrationSource::new("mirror-crate", "mirror::factory", "src/other.rs", 3),
    )
}

register_value_string_codec!(
    id = "mirror.factory.string.inventory",
    codec = MirrorU32StringCodec,
    value = u32,
);

register_value_string_codec!(
    id = "review.borrowed.bytes", codec = ReviewBorrowedCodec,
    value = Vec<u8>, input = [u8],
);

#[test]
fn test_invoking_the_factory_returns_the_registration_built_by_its_callback() {
    let factory = ValueStringCodecRegistrationFactory(build_first);

    let registration = (factory.0)();

    assert_eq!(
        registration.id().as_str(),
        "mirror.factory.string.first",
        "the factory must yield exactly what its callback produced"
    );
    assert!(
        ptr::eq(registration.descriptor(), &STRING_DESCRIPTOR),
        "the built registration must keep borrowing the callback's static descriptor"
    );
}

#[test]
fn test_factory_callback_needs_no_arguments_and_no_registry_context() {
    let factory = ValueStringCodecRegistrationFactory(build_first);
    let callback: fn() -> ValueStringCodecRegistration = factory.0;

    let registration = callback();

    assert_eq!(
        registration.source().line(),
        17,
        "a zero-argument callback must be callable without any registry state"
    );
}

#[test]
fn test_two_invocations_produce_independent_registrations_over_one_descriptor() {
    let factory = ValueStringCodecRegistrationFactory(build_first);

    let first = (factory.0)();
    let second = (factory.0)();

    assert_eq!(
        first.id(),
        second.id(),
        "repeated invocation must build the same stable ID"
    );
    assert!(
        ptr::eq(first.descriptor(), second.descriptor()),
        "repeated invocation must not construct fresh descriptor state"
    );
}

#[test]
fn test_two_factories_serve_different_stable_ids() {
    let first = ValueStringCodecRegistrationFactory(build_first);
    let second = ValueStringCodecRegistrationFactory(build_second);

    assert_ne!(
        (first.0)().id(),
        (second.0)().id(),
        "independent factories must remain independently addressable"
    );
}

#[test]
fn test_factory_registration_enters_the_global_registry() {
    let registry = ValueStringCodecRegistry::try_global().expect("inventory registrations must freeze");
    let found = registry
        .get("mirror.factory.string.inventory")
        .expect("the inventory factory result must be reachable by its stable ID");
    assert_eq!(
        found.source().module_path(),
        "tests::value::value_string_codec_registration_factory_tests",
        "the registry must retain the declaration site of the submitted factory"
    );
    assert_eq!(
        found
            .descriptor()
            .encode(&11_u32)
            .expect("registered string codec should encode"),
        "11",
    );
}

#[test]
fn test_factory_does_not_restrict_the_declared_wire_representation() {
    let factory = ValueStringCodecRegistrationFactory(build_first);

    let registration = (factory.0)();

    assert_eq!(
        registration.descriptor().codec_type_id(),
        STRING_DESCRIPTOR.codec_type_id(),
        "the factory must keep the codec type the callback declared"
    );
    assert_ne!(
        registration.descriptor().codec_type_id(),
        BYTES_DESCRIPTOR.codec_type_id(),
        "a string factory must not smuggle in the bytes descriptor"
    );
    assert_eq!(
        registration.descriptor().value_type_id(),
        TypeId::of::<u32>(),
        "the value type must come from the callback's descriptor"
    );
}

#[test]
fn test_factory_built_registration_remains_executable() {
    let factory = ValueStringCodecRegistrationFactory(build_first);

    let registration = (factory.0)();

    assert_eq!(
        registration.descriptor().encode(&11_u32).expect("encode"),
        "11",
        "a factory-built registration must stay executable through its descriptor"
    );
}

#[test]
fn test_review_borrowed_registration_executes_through_inventory() {
    let registry = ValueStringCodecRegistry::try_global().unwrap();
    let descriptor = registry.get("review.borrowed.bytes").unwrap().descriptor();
    assert_eq!(descriptor.value_type_id(), TypeId::of::<Vec<u8>>());
    assert_eq!(descriptor.encode(&b"hello".to_vec()).unwrap(), "hello");
    assert_eq!(
        *descriptor.decode("hello").unwrap().downcast::<Vec<u8>>().unwrap(),
        b"hello".to_vec()
    );
}