Skip to main content

key_paths_core/
lib.rs

1//! Lightweight, dependency-free keypath traits for Rust.
2//!
3//! Implement [`Readable`] and [`Writable`] on your keypath types so callers can navigate
4//! roots uniformly. Use [`KpTrait`] for `TypeId` helpers and [`KpTrait::then`] composition.
5//!
6//! Higher-level crates (for example `rust-key-paths`) add concrete keypath structs,
7//! chaining, and lock/async adapters on top of these traits.
8
9#![no_std]
10
11use core::any::TypeId;
12
13/// Used so async chaining can infer the referent of a reference-valued step
14/// (e.g. `&T` and `&mut T` both map to `T`).
15pub trait KeyPathValueTarget {
16    /// The type pointed to when `Self` is a reference.
17    type Target: Sized;
18}
19
20impl<T: Sized> KeyPathValueTarget for &T {
21    type Target = T;
22}
23
24impl<T: Sized> KeyPathValueTarget for &mut T {
25    type Target = T;
26}
27
28/// Read-only keypath: navigate from `Root` to `Value`.
29pub trait Readable<Root, Value> {
30    /// Getter path. Returns `None` when navigation fails.
31    fn get(&self, root: Root) -> Option<Value>;
32}
33
34/// Mutable keypath: setter path (same semantics as a `get_mut` closure on many keypath APIs).
35pub trait Writable<MutRoot, MutValue> {
36    /// Setter path. Returns `None` when navigation fails.
37    fn set(&self, root: MutRoot) -> Option<MutValue>;
38}
39
40/// A keypath that supports both read and write navigation.
41pub trait KeyPath<Root, Value, MutRoot, MutValue>:
42    Readable<Root, Value> + Writable<MutRoot, MutValue>
43{
44}
45
46impl<T, Root, Value, MutRoot, MutValue> KeyPath<Root, Value, MutRoot, MutValue> for T where
47    T: Readable<Root, Value> + Writable<MutRoot, MutValue>
48{
49}
50
51/// Logical root/value type identity and composition for a keypath.
52pub trait KpTrait<R, V, Root, Value, MutRoot, MutValue>:
53    Readable<Root, Value> + Writable<MutRoot, MutValue>
54{
55    /// `TypeId` of the logical root type `R`.
56    fn type_id_of_root() -> TypeId
57    where
58        R: 'static,
59    {
60        TypeId::of::<R>()
61    }
62
63    /// `TypeId` of the logical value type `V`.
64    fn type_id_of_value() -> TypeId
65    where
66        V: 'static,
67    {
68        TypeId::of::<V>()
69    }
70
71    /// Chain with a keypath over this segment's value (`Value` / `MutValue` are the link types).
72    ///
73    /// `Next` must read/write from the current value. The returned type is opaque at the trait
74    /// level; concrete crates (for example `rust-key-paths` `Kp`) choose their own struct.
75    fn then<SV, SubValue, MutSubValue, Next>(
76        self,
77        next: Next,
78    ) -> impl KeyPath<Root, SubValue, MutRoot, MutSubValue>
79    where
80        Self: Sized,
81        SubValue: core::borrow::Borrow<SV>,
82        MutSubValue: core::borrow::BorrowMut<SV>,
83        Next: Readable<Value, SubValue> + Writable<MutValue, MutSubValue> + Clone;
84}
85
86/// Optional-root and fallback helpers built on [`Readable`] / [`Writable`].
87pub trait AccessorTrait<Root, Value, MutRoot, MutValue>:
88    Readable<Root, Value> + Writable<MutRoot, MutValue>
89{
90    /// Like [`Readable::get`], but takes an optional root.
91    fn get_optional(&self, root: Option<Root>) -> Option<Value> {
92        root.and_then(|r| Readable::get(self, r))
93    }
94
95    /// Like [`Writable::set`], but takes an optional root.
96    fn get_mut_optional(&self, root: Option<MutRoot>) -> Option<MutValue> {
97        root.and_then(|r| Writable::set(self, r))
98    }
99
100    /// Returns the value if the keypath succeeds, otherwise calls `f`.
101    fn get_or_else<F>(&self, root: Root, f: F) -> Value
102    where
103        F: FnOnce() -> Value,
104    {
105        Readable::get(self, root).unwrap_or_else(f)
106    }
107
108    /// Returns the mutable value if the keypath succeeds, otherwise calls `f`.
109    fn get_mut_or_else<F>(&self, root: MutRoot, f: F) -> MutValue
110    where
111        F: FnOnce() -> MutValue,
112    {
113        Writable::set(self, root).unwrap_or_else(f)
114    }
115}