key_paths_core/
lib.rs

1/// Read-only keypath
2pub struct ReadableKeyPath<Root, Value> {
3    pub get: Box<dyn for<'a> Fn(&'a Root) -> &'a Value>,
4}
5
6impl<Root, Value> ReadableKeyPath<Root, Value> {
7    pub fn new(get: impl for<'a> Fn(&'a Root) -> &'a Value + 'static) -> Self {
8        Self { get: Box::new(get) }
9    }
10    pub fn get<'a>(&self, root: &'a Root) -> &'a Value {
11        (self.get)(root)
12    }
13
14    /// Iterate a slice of `Root` and yield references to `Value`
15    pub fn iter<'a>(&'a self, slice: &'a [Root]) -> impl Iterator<Item = &'a Value> + 'a {
16        slice.iter().map(move |root| (self.get)(root))
17    }
18}
19
20impl<Root, Mid> ReadableKeyPath<Root, Mid>
21where
22    Root: 'static,
23    Mid: 'static,
24{
25    pub fn compose<Value>(self, mid: ReadableKeyPath<Mid, Value>) -> ReadableKeyPath<Root, Value>
26    where
27        Value: 'static,
28    {
29        ReadableKeyPath::new(move |r: &Root| {
30            let mid_ref: &Mid = (self.get)(r);
31            (mid.get)(mid_ref)
32        })
33    }
34}
35
36pub struct WritableKeyPath<Root, Value> {
37    pub get: Box<dyn for<'a> Fn(&'a Root) -> &'a Value>,
38    pub get_mut: Box<dyn for<'a> Fn(&'a mut Root) -> &'a mut Value>,
39}
40
41impl<Root, Value> WritableKeyPath<Root, Value> {
42    pub fn new(
43        get: impl for<'a> Fn(&'a Root) -> &'a Value + 'static,
44        get_mut: impl for<'a> Fn(&'a mut Root) -> &'a mut Value + 'static,
45    ) -> Self {
46        Self {
47            get: Box::new(get),
48            get_mut: Box::new(get_mut),
49        }
50    }
51
52    pub fn try_get<'a>(&self, root: &'a Root) -> &'a Value {
53        (self.get)(root)
54    }
55
56    pub fn try_get_mut<'a>(&self, root: &'a mut Root) -> &'a mut Value {
57        (self.get_mut)(root)
58    }
59
60    /// Mutable iteration
61    pub fn iter<'a>(&'a self, slice: &'a [Root]) -> impl Iterator<Item = &'a Value> + 'a {
62        slice.iter().map(move |root| (self.get)(root))
63    }
64
65    /// Mutable iteration
66    pub fn iter_mut<'a>(
67        &'a self,
68        slice: &'a mut [Root],
69    ) -> impl Iterator<Item = &'a mut Value> + 'a {
70        slice.iter_mut().map(move |root| (self.get_mut)(root))
71    }
72}
73
74// --- Compose: impl over (Root, Mid); Value is method-generic ---
75// --- Compose ---
76impl<Root, Mid> WritableKeyPath<Root, Mid>
77where
78    Root: 'static,
79    Mid: 'static,
80{
81    pub fn compose<Value>(self, mid: WritableKeyPath<Mid, Value>) -> WritableKeyPath<Root, Value>
82    where
83        Value: 'static,
84    {
85        WritableKeyPath::new(
86            move |r: &Root| {
87                let mid_ref: &Mid = (self.get)(r);
88                (mid.get)(mid_ref)
89            },
90            move |r: &mut Root| {
91                let mid_ref: &mut Mid = (self.get_mut)(r);
92                (mid.get_mut)(mid_ref)
93            },
94        )
95    }
96}
97
98pub struct FailableReadableKeyPath<Root, Value> {
99    pub get: Box<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>,
100}
101
102impl<Root, Value> FailableReadableKeyPath<Root, Value> {
103    pub fn new(get: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static) -> Self {
104        Self { get: Box::new(get) }
105    }
106    pub fn try_get<'a>(&self, root: &'a Root) -> Option<&'a Value> {
107        (self.get)(root)
108    }
109
110    /// Iterate a slice of `Root` and yield references to `Value`
111    pub fn iter<'a>(&'a self, slice: &'a [Root]) -> impl Iterator<Item = Option<&'a Value>> + 'a {
112        slice.iter().map(move |root| (self.get)(root))
113    }
114}
115
116impl<Root, Mid> FailableReadableKeyPath<Root, Mid>
117where
118    Root: 'static,
119    Mid: 'static,
120{
121    pub fn compose<Value>(
122        self,
123        mid: FailableReadableKeyPath<Mid, Value>,
124    ) -> FailableReadableKeyPath<Root, Value>
125    where
126        Value: 'static,
127    {
128        FailableReadableKeyPath::new(move |r: &Root| (self.get)(r).and_then(|m: &Mid| (mid.get)(m)))
129    }
130}
131
132pub struct FailableWritableKeyPath<Root, Value> {
133    pub get: Box<dyn for<'a> Fn(&'a Root) -> Option<&'a Value>>,
134    pub get_mut: Box<dyn for<'a> Fn(&'a mut Root) -> Option<&'a mut Value>>,
135}
136
137impl<Root, Value> FailableWritableKeyPath<Root, Value> {
138    pub fn new(
139        get: impl for<'a> Fn(&'a Root) -> Option<&'a Value> + 'static,
140        get_mut: impl for<'a> Fn(&'a mut Root) -> Option<&'a mut Value> + 'static,
141    ) -> Self {
142        Self {
143            get: Box::new(get),
144            get_mut: Box::new(get_mut),
145        }
146    }
147
148    pub fn try_get<'a>(&self, root: &'a Root) -> Option<&'a Value> {
149        (self.get)(root)
150    }
151
152    pub fn try_get_mut<'a>(&self, root: &'a mut Root) -> Option<&'a mut Value> {
153        (self.get_mut)(root)
154    }
155
156    pub fn iter<'a>(&'a self, slice: &'a [Root]) -> impl Iterator<Item = Option<&'a Value>> + 'a {
157        slice.iter().map(move |root| (self.get)(root))
158    }
159
160    /// Mutable iteration
161    pub fn iter_mut<'a>(
162        &'a self,
163        slice: &'a mut [Root],
164    ) -> impl Iterator<Item = Option<&'a mut Value>> + 'a {
165        slice.iter_mut().map(move |root| (self.get_mut)(root))
166    }
167}
168
169impl<Root, Mid> FailableWritableKeyPath<Root, Mid>
170where
171    Root: 'static,
172    Mid: 'static,
173{
174    pub fn compose<Value>(
175        self,
176        mid: FailableWritableKeyPath<Mid, Value>,
177    ) -> FailableWritableKeyPath<Root, Value>
178    where
179        Value: 'static,
180    {
181        FailableWritableKeyPath::new(
182            move |r: &Root| (self.get)(r).and_then(|m: &Mid| (mid.get)(m)),
183            move |r: &mut Root| (self.get_mut)(r).and_then(|m: &mut Mid| (mid.get_mut)(m)),
184        )
185    }
186}
187
188pub struct EnumKeyPath<Enum, Inner> {
189    pub extract: fn(&Enum) -> Option<&Inner>,
190    pub embed: fn(Inner) -> Enum,
191}
192
193impl<Enum, Inner> EnumKeyPath<Enum, Inner> {
194    pub fn new(extract: fn(&Enum) -> Option<&Inner>, embed: fn(Inner) -> Enum) -> Self {
195        Self { extract, embed }
196    }
197
198    pub fn extract<'a>(&self, e: &'a Enum) -> Option<&'a Inner> {
199        (self.extract)(e)
200    }
201
202    pub fn embed(&self, inner: Inner) -> Enum {
203        (self.embed)(inner)
204    }
205}
206
207#[macro_export]
208macro_rules! enum_keypath {
209    // Case with payload
210    ($enum:ident :: $variant:ident ( $inner:ty )) => {{
211        EnumKeyPath::<$enum, $inner>::new(
212            |root: &$enum| {
213                if let $enum::$variant(inner) = root {
214                    Some(inner)
215                } else {
216                    None
217                }
218            },
219            |inner: $inner| $enum::$variant(inner),
220        )
221    }};
222    // Case without payload
223    ($enum:ident :: $variant:ident) => {{
224        EnumKeyPath::<$enum, ()>::new(
225            |root: &$enum| {
226                if let $enum::$variant = root {
227                    Some(&())
228                } else {
229                    None
230                }
231            },
232            |_| $enum::$variant,
233        )
234    }};
235}
236
237/*
238    let name_key = ReadableKeyPath::new(|u: &User| &u.name);
239*/
240/// Macro for readable keypaths
241#[macro_export]
242macro_rules! readable_keypath {
243    ($Root:ty, $field:ident) => {
244        ReadableKeyPath::new(|root: &$Root| &root.$field)
245    };
246}
247
248/*
249    let age_key = WritableKeyPath::new(
250        |u: & User| & u.age,
251        |u: &mut User| &mut u.age,
252    );
253*/
254/// Macro for writable keypaths
255#[macro_export]
256macro_rules! writable_keypath {
257    ($Root:ty, $field:ident) => {
258        WritableKeyPath::new(
259            |root: &$Root| &root.$field,
260            |root: &mut $Root| &mut root.$field,
261        )
262    };
263}