Skip to main content

qubit_value/
lib.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! # Value Processing Framework
9//!
10//! Provides type-safe value storage and access functionality, supporting single
11//! values, collections, explicit scalar-or-collection shape, and named values.
12//!
13//! # Public API Overview
14//!
15//! - [`Value`] stores one typed scalar, including an explicit `Unset(DataType)`
16//!   state.
17//! - [`MultiValues`] stores one homogeneous typed collection.
18//! - [`ValueRef`] and [`MultiValuesRef`] expose borrowed semantic views while
19//!   keeping runtime storage private.
20//! - [`ValueContainer`] preserves whether storage is scalar or collection.
21//! - [`NamedValue`] and [`NamedMultiValues`] provide name wrappers.
22//! - [`ValueWireV1`] and [`ValueWirePayloadV1`] name explicit Serde DTOs.
23//! - [`ValueWireRefV1`] and [`ValueWirePayloadRefV1`] serialize borrowed
24//!   values.
25//!
26//! # Core behavior
27//!
28//! - [`Value::get`] and [`MultiValues::get`] perform strict typed reads.
29//! - [`ValueContainer`] preserves whether the source supplied a scalar or an
30//!   explicit collection, even when the collection contains one item.
31//! - `to` methods use `qubit-datatype` conversion policy and resource limits.
32//! - Optional type families and conversion methods are available only when the
33//!   corresponding crate features are enabled; all-features documentation shows
34//!   the superset of those APIs.
35//! - [`Value::is_unset`] and [`ValueContainer::is_unset`] indicate that no
36//!   concrete value is stored.
37//! - [`MultiValues::is_unset`] distinguishes no collection from a concrete
38//!   collection; [`MultiValues::is_empty`] reports only that its length is
39//!   zero.
40//! - Generic `set` replaces a value infallibly; [`MultiValues::add`] remains
41//!   fallible because appended values must have the same data type.
42//! - Serde uses the strict, type-preserving [`ValueWireV1`] envelope. Its
43//!   canonical JSON representation is byte-stable for the same value under the
44//!   supported `serde_json` version and configuration. String-map keys and
45//!   nested JSON object keys are emitted in lexicographic order. Other Serde
46//!   formats are supported as representations, but are outside this byte-level
47//!   stability contract. With the `natural-json` feature, `to_json_value`
48//!   provides a separate natural JSON projection with the same ordering.
49//! - Version one rejects legacy bare enum representations such as
50//!   `{"Int32":42}`. A standalone V1 document uses the versioned envelope with
51//!   nested `scalar` or `collection` and lowercase type tags.
52//! - Non-finite floats may exist in memory, but V1 Serde and natural JSON
53//!   reject them because JSON has no `NaN` or infinity number literals.
54//! - JSON numbers follow `qubit-json`'s explicit range contract: negative
55//!   integers fit `i64`, non-negative integers fit `u64`, and fractional or
56//!   exponential values must be finite `f64`. Wider exact values use the
57//!   crate's explicit string-based integer and decimal wire representations.
58//!   [`ValueWireV1`] additionally requires each runtime JSON number to round
59//!   trip to the same `serde_json::Number`; with `arbitrary_precision`, a
60//!   nonstandard or over-precise representation is rejected rather than
61//!   silently changing JSON identity. Natural JSON projection performs the
62//!   range check while retaining an accepted original `Number`, so a successful
63//!   projection does not imply that Wire V1 accepts that number.
64//!
65//! # Usage Examples
66//!
67//! ## Single Value Operations
68//!
69//! ```rust
70//! use qubit_value::Value;
71//!
72//! // Create and access a single value
73//! let value = Value::Int32(42);
74//! assert_eq!(value.get_int32().unwrap(), 42);
75//!
76//! // Strict generic access
77//! let number: i32 = value.get().unwrap();
78//! assert_eq!(number, 42);
79//! ```
80//!
81//! ## Multiple Values Operations
82//!
83//! ```rust
84//! use qubit_value::MultiValues;
85//!
86//! // Create and access multiple values
87//! let mut values = MultiValues::Int32(vec![1, 2, 3]);
88//! assert_eq!(values.len(), 3);
89//!
90//! // Add values
91//! values.add(4).unwrap();
92//! assert_eq!(values.get_int32s().unwrap(), &[1, 2, 3, 4]);
93//! ```
94//!
95//! ## Named Value Operations
96//!
97//! ```rust
98//! use qubit_value::NamedValue;
99//! use qubit_value::Value;
100//!
101//! // Create a named value
102//! let config = NamedValue::new("port", Value::Int32(8080));
103//! assert_eq!(config.name(), "port");
104//! assert_eq!(config.value().get_int32().unwrap(), 8080);
105//! ```
106//!
107//! ## Explicit Shape Operations
108//!
109//! ```rust
110//! use qubit_value::ValueContainer;
111//!
112//! let scalar = ValueContainer::from(42_i32);
113//! let collection = ValueContainer::from(vec![42_i32]);
114//! assert!(scalar.is_scalar());
115//! assert!(collection.is_collection());
116//! ```
117
118#![cfg_attr(docsrs, feature(doc_cfg))]
119
120// Sub-modules
121mod finite_float;
122mod identity;
123mod into_value_default;
124#[macro_use]
125mod value_type_table;
126#[cfg(any(feature = "natural-json", all(feature = "converter", feature = "json")))]
127mod json;
128mod multi_values;
129mod named_multi_values;
130mod named_value;
131mod numeric_comparison_error;
132mod strict_value_read;
133mod value;
134mod value_container;
135mod value_error;
136mod value_missing;
137mod value_missing_reason;
138mod value_wire;
139mod wide_integer;
140mod wire;
141
142#[cfg(test)]
143mod tests;
144
145// Public exports
146pub use self::into_value_default::IntoValueDefault;
147pub use self::multi_values::MultiValues;
148pub use self::multi_values::MultiValuesRef;
149pub use self::named_multi_values::NamedMultiValues;
150pub use self::named_value::NamedValue;
151pub use self::numeric_comparison_error::NumericComparisonError;
152pub use self::strict_value_read::StrictValueRead;
153pub use self::value::Value;
154pub use self::value::ValueRef;
155pub use self::value_container::ValueContainer;
156pub use self::value_error::ValueError;
157pub use self::value_error::ValueResult;
158pub use self::value_missing::ValueMissing;
159pub use self::value_missing_reason::ValueMissingReason;
160#[cfg(feature = "json")]
161#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
162pub use self::value_wire::ValueWireDecodeError;
163pub use self::value_wire::ValueWireEncodeError;
164#[cfg(feature = "json")]
165#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
166pub use self::value_wire::ValueWireEncodePreflight;
167#[cfg(feature = "json")]
168#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
169pub use self::value_wire::ValueWireJsonError;
170pub use self::value_wire::ValueWirePayloadRefV1;
171pub use self::value_wire::ValueWirePayloadV1;
172pub use self::value_wire::ValueWirePayloadV1Seed;
173pub use self::value_wire::ValueWireRefV1;
174pub use self::value_wire::ValueWireV1;
175pub use self::value_wire::ValueWireV1Seed;