Presence
A Rust library providing a tri-state type for representing value presence in schemas and data structures.
[!TIP] If you what to read more about the motivation behind this crate, check out Stop Losing Intent: Absent, Null, and Value in Rust
Overview
Presence<T> extends the traditional Option<T> two-state model (Some/None)
with an additional distinction between "absent" and "null".
This is particularly useful when working with serialization formats like JSON
where the following states are semantically different:
- Absent: Field not present in the data structure:
{} - Null: Field present but explicitly set to null:
{"field": null} - Some: Field present with a concrete value:
{"field": value}
Cardinality
The Presence type increases the cardinality (number of possible states) of any
wrapped type by adding two states: Absent and Null.
| Type | Valid States | Cardinality |
|---|---|---|
bool |
true, false |
2 |
Option<bool> |
None, Some(true), Some(false) |
3 |
Presence<bool> |
Absent, Null, Some(true), Some(false) |
4 |
This distinction is particularly important in schema design and APIs where the semantic difference between "field not present" and "field explicitly set to null" has meaning.
Why Not Option<Option<T>>?
While Option<Option<T>> can technically represent three states, Presence<T>
offers several advantages:
- Clarity:
Presence::Absent,Presence::Null, andPresence::Some(value)are self-documenting. Compare this toNone,Some(None), andSome(Some(value))where the meaning of nestedNonevalues is ambiguous. - Ergonomics: Method names like
is_absent(),is_null(), andis_present()clearly express intent, versus checkingoption.is_none()oroption == Some(None). - Type Safety: The compiler understands the three distinct states, making pattern matching more explicit and reducing cognitive load.
- Semantics:
Presencemodels the domain concept directly rather than forcing a tri-state model into a two-level optional structure.
// With Presence - clear and explicit
match value
// With Option<Option<T>> - confusing
match value
Usage
Add this to your Cargo.toml:
[]
= "0.2.0"
Examples
Basic Usage
use Presence;
// Create Presence values
let absent: = Absent;
let null: = Null;
let some: = Some;
// Query the state
assert!;
assert!;
assert!;
Practical Example: API Update Request
use Presence;
// Example: Partial update where only email is provided
let update = UserUpdate ;
apply_update;
// Output: "Name unchanged: Alice"
Use Cases
This type is particularly useful in:
- API clients/servers where you need to distinguish between a field not being sent vs. being explicitly set to null
- Partial updates where absence means "don't change" vs. null means "clear the value"
- Schema validation where field presence has semantic meaning
- GraphQL implementations where null and undefined are distinct concepts
- Database operations where you need to differentiate between "not provided" and "set to NULL"
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.