presence_rs/lib.rs
1//! Three-valued logic for Rust: distinguishing between absent, null, and present values.
2//!
3//! This crate provides the [`Presence<T>`] type, a three-valued alternative to [`Option<T>`]
4//! that distinguishes between "field not present" and "field present but null".
5//!
6//! # The Three States
7//!
8//! - **`Absent`**: Field doesn't exist in the data structure (`{}` in JSON)
9//! - **`Null`**: Field exists but is explicitly null (`{"field": null}` in JSON)
10//! - **`Some(value)`**: Field exists with a concrete value (`{"field": 42}` in JSON)
11//!
12//! # When to Use This
13//!
14//! Use `Presence<T>` when you need to distinguish between absence and null:
15//!
16//! - JSON/API responses where `{}`, `{"field": null}`, and `{"field": value}` are semantically different
17//! - IPLD schemas where absent and null fields have distinct meanings
18//! - Database operations where NULL and missing columns differ
19//! - Form data where unchecked differs from explicitly cleared
20//!
21//! # Quick Example
22//!
23//! ```
24//! use presence_rs::Presence;
25//!
26//! let present = Presence::Some(42);
27//! let null = Presence::<i32>::Null;
28//! let absent = Presence::<i32>::Absent;
29//!
30//! assert!(present.is_present());
31//! assert!(null.is_defined()); // Exists in structure (even though null)
32//! assert!(!absent.is_defined()); // Doesn't exist in structure
33//!
34//! // Transformations preserve null vs absent
35//! assert_eq!(null.map(|x| x * 2), Presence::Null);
36//! ```
37//!
38//! See the [`mod@presence`] module for detailed documentation and examples.
39//!
40//! [`Presence<T>`]: presence::Presence
41
42pub mod presence;
43pub use presence::Presence;
44
45#[cfg(feature = "serde")]
46mod serde;
47
48/// Convenience macro for creating [`Presence`] values.
49///
50/// This macro provides a concise syntax for constructing `Presence` values,
51/// similar to how `vec![]` works for `Vec`.
52///
53/// [`Presence`]: presence::Presence
54///
55/// # Syntax
56///
57/// - `presence!()` - Creates `Presence::Absent`
58/// - `presence!(null)` - Creates `Presence::Null`
59/// - `presence!(value)` - Creates `Presence::Some(value)`
60///
61/// # Examples
62///
63/// ```
64/// use presence_rs::presence;
65///
66/// let absent: presence::Presence<i32> = presence!();
67/// assert_eq!(absent, presence::Presence::Absent);
68///
69/// let null: presence::Presence<i32> = presence!(null);
70/// assert_eq!(null, presence::Presence::Null);
71///
72/// let some = presence!(42);
73/// assert_eq!(some, presence::Presence::Some(42));
74///
75/// // Works with any expression
76/// let computed = presence!(2 + 2);
77/// assert_eq!(computed, presence::Presence::Some(4));
78///
79/// let owned = presence!("hello".to_string());
80/// assert_eq!(owned, presence::Presence::Some("hello".to_string()));
81/// ```
82#[macro_export]
83macro_rules! presence {
84 () => {
85 $crate::presence::Presence::Absent
86 };
87 (null) => {
88 $crate::presence::Presence::Null
89 };
90 ($value:expr) => {
91 $crate::presence::Presence::Some($value)
92 };
93}