qubit-datatype 0.15.2

Runtime data type descriptors and conversion utilities for Rust
Documentation
// =============================================================================
//    Copyright (c) 2025 - 2026 Haixing Hu.
//
//    SPDX-License-Identifier: Apache-2.0
//
//    Licensed under the Apache License, Version 2.0.
// =============================================================================
//! Runtime data type descriptors and policy-driven conversion utilities.
//!
//! The default feature set is empty and exposes the lightweight [`DataType`]
//! vocabulary plus [`DataTypeOf`]. The lightweight `duration` feature adds
//! Duration units, text codecs, and Serde field adapters. Optional `chrono`,
//! `big-integer`, `big-decimal`, `url`, and `json` features add mappings for
//! external types; `big-number` enables both big-number families. The
//! `converter` feature includes `duration` and enables core scalar, string, and
//! Duration conversions. Combine it with a rich-type feature to enable
//! conversions for that family, or use `all`.
//!
//! # Conversion contract
//!
//! With `converter`, representative paths include strings to numeric,
//! boolean, character, and Duration values; core scalars to String; integers
//! to numeric, boolean, and Duration values; and Duration to integers and
//! String. Boolean and character sources also have numeric paths. A path's
//! implementation does not guarantee that every value is accepted: the
//! selected policy and target range still apply. `chrono`, `big-integer`,
//! `big-decimal`, `url`, and `json` add their documented paths when combined
//! with `converter`; JSON also enables StringMap parsing and formatting.
//! Discover paths compiled into the current build with
//! [`ConversionCapabilities::supports`](https://docs.rs/qubit-datatype/latest/qubit_datatype/struct.ConversionCapabilities.html#method.supports)
//! and
//! [`ConversionCapabilities::supported_targets`](https://docs.rs/qubit-datatype/latest/qubit_datatype/struct.ConversionCapabilities.html#method.supported_targets).
//! These APIs are available with `converter`.
//! Other pairs return `DataConversionErrorKind::Unsupported`, and conversions
//! are not chained implicitly.
//!
//! `NumericConversionPolicy` configures fractional-to-integer conversion,
//! numeric-to-float rounding, and text-to-float rounding independently.
//! `NumericConversionLimits` and `ConversionLimits` bound resource usage
//! separately. The strict/default profile rejects truncation and
//! precision loss. `ConversionPolicy::lossy` permits finite
//! decimal/float truncation toward zero, IEEE nearest-even float rounding, and
//! Duration half-up rounding. Duration-to-integer and Duration-to-String
//! require exact divisibility unless `DurationRoundingPolicy::HalfUp` is
//! selected explicitly.
//!
//! A reusable conversion session reports stable resource facts through
//! `DataConversionError` accessors without exposing its accounting backend.
//! The session's output-byte budget is shared by built-in `String`
//! conversions, custom targets using `AdmittedConversion::write_string`, and
//! JSON encoding through `AdmittedConversion::encode_json` when the `json`
//! feature is enabled. It counts UTF-8 `String` bytes and encoded JSON bytes.
//! Each output operation commits its bytes on success. Custom targets'
//! independently produced output is not automatically accounted for.
//! Built-in `String` conversions retain the same accounting for borrowed and
//! owned sources; each `String` source is normalized exactly once.
//!
//! Strings are not trimmed by default and are normalized exactly once.
//! Boolean text defaults to `true` and `false`; numeric 0/1 handling is
//! controlled independently by `BooleanNumericPolicy`. By default, Duration
//! text rejects omitted suffixes and accepts
//! `[0-9]+(ns|us|µs|μs|ms|s|min|h|d)`. Strict mode accepts all three
//! microsecond spellings; lenient mode additionally accepts `m` for minutes.
//!
//! # Example
//!
//! ```
//! # #[cfg(feature = "converter")]
//! # {
//! use qubit_datatype::{
//!     ConversionLimits, ConversionPolicy, DataConversionErrorKind,
//!     DataConverter, InvalidValueReason,
//! };
//!
//! let error = DataConverter::from("3.9").to::<i32>().unwrap_err();
//! assert_eq!(error.kind(), DataConversionErrorKind::InvalidValue);
//! assert_eq!(error.reason(), Some(&InvalidValueReason::PrecisionLoss));
//!
//! let lossy = ConversionPolicy::lossy();
//! let limits = ConversionLimits::default();
//! assert_eq!(
//!     DataConverter::from(" 3.9 ").to_with::<i32>(&lossy, &limits),
//!     Ok(3),
//! );
//! # }
//! ```
//!
//! The example below checks both the compiled capability and the result of a
//! conversion. It is available when the `converter` feature is enabled.
//!
//! ```
//! # #[cfg(feature = "converter")]
//! # fn example() -> Result<(), qubit_datatype::DataConversionError> {
//! use qubit_datatype::ConversionCapabilities;
//! use qubit_datatype::DataConverter;
//! use qubit_datatype::DataType;
//!
//! let capabilities = ConversionCapabilities::current();
//! assert!(capabilities.supports(DataType::Int32, DataType::String));
//! assert_eq!(DataConverter::from(42_i32).to::<String>()?, "42");
//! # Ok(())
//! # }
//! # #[cfg(feature = "converter")]
//! # example().unwrap();
//! ```

#![deny(missing_docs)]

/// Data type descriptors and compile-time type mappings.
pub mod datatype;

/// Policy-driven numeric comparison primitives.
pub mod numeric;

/// Lightweight Duration units and text codecs.
#[cfg(feature = "duration")]
pub mod duration;

#[cfg(feature = "duration")]
#[path = "serde/mod.rs"]
mod serde_impl;

/// Serde adapters for Duration interchange formats.
///
/// Use these modules with `#[serde(with = "...")]` when a field requires a
/// stable numeric or unit-suffixed Duration representation.
#[cfg(feature = "duration")]
pub mod serde {
    pub use super::serde_impl::duration_millis;
    pub use super::serde_impl::duration_millis_with_unit;
    pub use super::serde_impl::duration_millis_with_unit_exact;
    pub use super::serde_impl::duration_with_unit;
}

/// Runtime value conversion utilities.
#[cfg(feature = "converter")]
pub mod converter;

#[cfg(feature = "converter")]
pub use converter::AdmittedConversion;
#[cfg(feature = "converter")]
pub use converter::AdmittedScalarItem;
#[cfg(feature = "converter")]
pub use converter::AdmittedScalarSource;
#[cfg(feature = "converter")]
pub use converter::BlankStringPolicy;
#[cfg(feature = "converter")]
pub use converter::BooleanConversionPolicy;
#[cfg(feature = "converter")]
pub use converter::BooleanConversionPolicyBuilder;
#[cfg(feature = "converter")]
pub use converter::BooleanLiteralConflictError;
#[cfg(feature = "converter")]
pub use converter::BooleanNumericPolicy;
#[cfg(feature = "converter")]
pub use converter::CollectionConversionLimits;
#[cfg(feature = "converter")]
pub use converter::CollectionConversionLimitsBuilder;
#[cfg(feature = "converter")]
pub use converter::CollectionConversionPolicy;
#[cfg(feature = "converter")]
pub use converter::CollectionConversionPolicyBuilder;
#[cfg(feature = "converter")]
pub use converter::ConversionCapabilities;
#[cfg(feature = "converter")]
pub use converter::ConversionLimits;
#[cfg(feature = "converter")]
pub use converter::ConversionLimitsBuilder;
#[cfg(feature = "converter")]
pub use converter::ConversionOperationLimits;
#[cfg(feature = "converter")]
pub use converter::ConversionOperationLimitsBuilder;
#[cfg(feature = "converter")]
pub use converter::ConversionPolicy;
#[cfg(feature = "converter")]
pub use converter::ConversionPolicyBuilder;
#[cfg(feature = "converter")]
pub use converter::ConversionResource;
#[cfg(feature = "converter")]
pub use converter::ConversionSession;
#[cfg(feature = "converter")]
pub use converter::ConversionStringWriter;
#[cfg(feature = "converter")]
pub use converter::DataConversionError;
#[cfg(feature = "converter")]
pub use converter::DataConversionErrorKind;
#[cfg(feature = "converter")]
pub use converter::DataConversionTarget;
#[cfg(feature = "converter")]
pub use converter::DataConverter;
#[cfg(feature = "converter")]
pub use converter::DataConverters;
#[cfg(feature = "converter")]
pub use converter::DataFormat;
#[cfg(feature = "converter")]
pub use converter::DataListConversionError;
#[cfg(feature = "converter")]
pub use converter::DurationConversionLimits;
#[cfg(feature = "converter")]
pub use converter::DurationConversionLimitsBuilder;
#[cfg(feature = "converter")]
pub use converter::DurationConversionPolicy;
#[cfg(feature = "converter")]
pub use converter::DurationConversionPolicyBuilder;
#[cfg(feature = "converter")]
pub use converter::DurationRoundingPolicy;
#[cfg(feature = "converter")]
pub use converter::EmptyItemPolicy;
#[cfg(feature = "converter")]
pub use converter::FloatRoundingPolicy;
#[cfg(feature = "converter")]
pub use converter::FractionalToIntegerPolicy;
#[cfg(feature = "converter")]
pub use converter::InvalidValueReason;
#[cfg(feature = "converter")]
pub use converter::JsonConversionDiagnostic;
#[cfg(feature = "converter")]
pub use converter::JsonConversionErrorCategory;
#[cfg(feature = "converter")]
pub use converter::NumericConversionLimits;
#[cfg(feature = "converter")]
pub use converter::NumericConversionLimitsBuilder;
#[cfg(feature = "converter")]
pub use converter::NumericConversionPolicy;
#[cfg(feature = "converter")]
pub use converter::NumericConversionPolicyBuilder;
#[cfg(feature = "converter")]
pub use converter::ScalarItem;
#[cfg(feature = "converter")]
pub use converter::ScalarItemError;
#[cfg(feature = "converter")]
pub use converter::ScalarItems;
#[cfg(feature = "converter")]
pub use converter::ScalarStringDataConverters;
#[cfg(feature = "converter")]
pub use converter::StringConversionPolicy;
#[cfg(feature = "converter")]
pub use converter::StringConversionPolicyBuilder;
#[cfg(feature = "converter")]
pub use converter::StringNormalizationError;
#[cfg(feature = "converter")]
pub use converter::StructuredConversionLimits;
#[cfg(feature = "converter")]
pub use converter::StructuredConversionLimitsBuilder;
pub use datatype::DataType;
pub use datatype::DataTypeCategory;
pub use datatype::DataTypeOf;
pub use datatype::DataTypeParseError;
#[cfg(feature = "duration")]
pub use duration::DurationOverflowError;
#[cfg(feature = "duration")]
pub use duration::DurationParseError;
#[cfg(feature = "duration")]
pub use duration::DurationPrecisionLossError;
#[cfg(feature = "duration")]
pub use duration::DurationTextOptions;
#[cfg(feature = "duration")]
pub use duration::DurationTextOptionsBuilder;
#[cfg(feature = "duration")]
pub use duration::DurationUnit;
#[cfg(feature = "duration")]
pub use duration::DurationUnitParseMode;
#[cfg(feature = "duration")]
pub use duration::SuffixlessDurationPolicy;
#[cfg(feature = "duration")]
pub use duration::format_duration_exact;
#[cfg(feature = "duration")]
pub use duration::parse_duration_text;
pub use numeric::NumberRef;
pub use numeric::NumericComparisonPolicy;