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/// Reference-shaped [`KpTrait`] (`Root = &R`, `Value = &V`) with HRTB navigation.
87///
88/// Use [`Self::focus`] / [`Self::focus_mut`] for local borrows; [`Readable::get`] / [`Writable::set`]
89/// use the `'static` link types and are intended for composition ([`KpTrait::then`], etc.).
90pub trait RefKpTrait<R, V>:
91    KpTrait<R, V, &'static R, &'static V, &'static mut R, &'static mut V>
92where
93    R: 'static,
94    V: 'static,
95{
96    fn focus<'a>(&self, root: &'a R) -> Option<&'a V>;
97    fn focus_mut<'a>(&self, root: &'a mut R) -> Option<&'a mut V>;
98}
99
100/// Optional-root and fallback helpers built on [`Readable`] / [`Writable`].
101pub trait AccessorTrait<Root, Value, MutRoot, MutValue>:
102    Readable<Root, Value> + Writable<MutRoot, MutValue>
103{
104    /// Like [`Readable::get`], but takes an optional root.
105    fn get_optional(&self, root: Option<Root>) -> Option<Value> {
106        root.and_then(|r| Readable::get(self, r))
107    }
108
109    /// Like [`Writable::set`], but takes an optional root.
110    fn get_mut_optional(&self, root: Option<MutRoot>) -> Option<MutValue> {
111        root.and_then(|r| Writable::set(self, r))
112    }
113
114    /// Returns the value if the keypath succeeds, otherwise calls `f`.
115    fn get_or_else<F>(&self, root: Root, f: F) -> Value
116    where
117        F: FnOnce() -> Value,
118    {
119        Readable::get(self, root).unwrap_or_else(f)
120    }
121
122    /// Returns the mutable value if the keypath succeeds, otherwise calls `f`.
123    fn get_mut_or_else<F>(&self, root: MutRoot, f: F) -> MutValue
124    where
125        F: FnOnce() -> MutValue,
126    {
127        Writable::set(self, root).unwrap_or_else(f)
128    }
129}