key_paths_core/
lib.rs

1
2pub trait Readable<Root, Value> {
3    fn get<'a>(&self, root: &'a Root) -> &'a Value;
4
5    fn iter<'a>(&self, slice: &'a [Root]) -> Box<dyn Iterator<Item = &'a Value> + 'a>
6    where
7        Self: Sized,
8    {
9        let f = self.get_fn(); // capture fn pointer
10        Box::new(slice.iter().map(move |root| f(root)))
11    }
12
13    fn get_fn(&self) -> for<'a> fn(&'a Root) -> &'a Value;
14}
15
16/// Read-only keypath
17pub struct ReadableKeyPath<Root, Value> {
18    pub get: for<'a> fn(&'a Root) -> &'a Value,
19}
20
21impl<Root, Value> ReadableKeyPath<Root, Value> {
22    pub fn new(get: for<'a> fn(&'a Root) -> &'a Value) -> Self {
23        Self { get }
24    }
25}
26
27impl<Root, Value> Readable<Root, Value> for ReadableKeyPath<Root, Value> {
28    fn get<'a>(&self, root: &'a Root) -> &'a Value {
29        (self.get)(root)
30    }
31
32    fn get_fn(&self) -> for<'a> fn(&'a Root) -> &'a Value {
33        self.get
34    }
35}
36
37
38/// Read/write keypath
39pub struct WritableKeyPath<Root, Value> {
40    pub get: for<'a> fn(&'a Root) -> &'a Value,
41    pub get_mut: for<'a> fn(&'a mut Root) -> &'a mut Value,
42}
43
44pub trait Writable<Root, Value>: Readable<Root, Value> {
45    fn get_mut<'a>(&self, root: &'a mut Root) -> &'a mut Value;
46
47    fn iter_mut<'a>(&self, slice: &'a mut [Root]) -> Box<dyn Iterator<Item = &'a mut Value> + 'a>
48    where
49        Self: Sized,
50    {
51        let f = self.get_mut_fn(); // capture fn pointer
52        Box::new(slice.iter_mut().map(move |root| f(root)))
53    }
54
55    fn get_mut_fn(&self) -> for<'a> fn(&'a mut Root) -> &'a mut Value;
56}
57
58impl<Root, Value> WritableKeyPath<Root, Value> {
59    pub fn new(
60        get: for<'a> fn(&'a Root) -> &'a Value,
61        get_mut: for<'a> fn(&'a mut Root) -> &'a mut Value,
62    ) -> Self {
63        Self { get, get_mut }
64    }
65}
66
67impl<Root, Value> Readable<Root, Value> for WritableKeyPath<Root, Value> {
68    fn get<'a>(&self, root: &'a Root) -> &'a Value {
69        (self.get)(root)
70    }
71
72    fn get_fn(&self) -> for<'a> fn(&'a Root) -> &'a Value {
73        self.get
74    }
75}
76
77impl<Root, Value> Writable<Root, Value> for WritableKeyPath<Root, Value> {
78    fn get_mut<'a>(&self, root: &'a mut Root) -> &'a mut Value {
79        (self.get_mut)(root)
80    }
81
82    fn get_mut_fn(&self) -> for<'a> fn(&'a mut Root) -> &'a mut Value {
83        self.get_mut
84    }
85}
86
87
88pub struct EnumKeyPath<Enum, Inner> {
89    pub extract: fn(&Enum) -> Option<&Inner>,
90    pub embed: fn(Inner) -> Enum,
91}
92
93impl<Enum, Inner> EnumKeyPath<Enum, Inner> {
94    pub fn new(extract: fn(&Enum) -> Option<&Inner>, embed: fn(Inner) -> Enum) -> Self {
95        Self { extract, embed }
96    }
97
98    pub fn extract<'a>(&self, e: &'a Enum) -> Option<&'a Inner> {
99        (self.extract)(e)
100    }
101
102    pub fn embed(&self, inner: Inner) -> Enum {
103        (self.embed)(inner)
104    }
105}
106
107#[macro_export]
108macro_rules! enum_keypath {
109    // Case with payload
110    ($enum:ident :: $variant:ident ( $inner:ty )) => {{
111        EnumKeyPath::<$enum, $inner>::new(
112            |root: &$enum| {
113                if let $enum::$variant(inner) = root {
114                    Some(inner)
115                } else {
116                    None
117                }
118            },
119            |inner: $inner| $enum::$variant(inner),
120        )
121    }};
122    // Case without payload
123    ($enum:ident :: $variant:ident) => {{
124        EnumKeyPath::<$enum, ()>::new(
125            |root: &$enum| {
126                if let $enum::$variant = root {
127                    Some(&())
128                } else {
129                    None
130                }
131            },
132            |_| $enum::$variant,
133        )
134    }};
135}
136
137/// Macro for readable keypaths
138#[macro_export]
139macro_rules! readable_keypath {
140    ($Root:ty, $field:ident) => {
141        ReadableKeyPath::new(|root: &$Root| &root.$field)
142    };
143}
144
145/// Macro for writable keypaths
146#[macro_export]
147macro_rules! writable_keypath {
148    ($Root:ty, $field:ident) => {
149        WritableKeyPath::new(
150            |root: &$Root| &root.$field,
151            |root: &mut $Root| &mut root.$field,
152        )
153    };
154}
155