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