linkspace/
argument_traits.rs

1// Traits that simplify arguments to functions.
2pub use try_as::TryAsSpace;
3
4pub mod try_as {
5    use linkspace_core::space_expr::SpaceExpr;
6
7    use crate::prelude::*;
8
9    pub trait TryAsSpace {
10        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space>;
11    }
12    impl<T: TryAsSpace + ?Sized> TryAsSpace for &T {
13        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
14            T::try_as_space(*self, scope)
15        }
16    }
17    impl TryAsSpace for Space {
18        fn try_as_space(&self, _scope: &dyn LkEnv) -> anyhow::Result<Space> {
19            Ok(*self)
20        }
21    }
22    impl TryAsSpace for (Domain, GroupID, &LkPath) {
23        fn try_as_space(&self, _scope: &dyn LkEnv) -> anyhow::Result<Space> {
24            Ok(Space {
25                domain: self.0,
26                group: self.1,
27                path: self.2.to_array(),
28            })
29        }
30    }
31    impl TryAsSpace for &dyn Point {
32        fn try_as_space(&self, _scope: &dyn LkEnv) -> anyhow::Result<Space> {
33            Ok(Space {
34                domain: *self.get_domain(),
35                group: *self.get_group(),
36                path: self.get_path().to_array(),
37            })
38        }
39    }
40    impl<T: TryAsSpace + Sized> TryAsSpace for (Domain, T) {
41        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
42            let mut space = self.1.try_as_space(scope)?;
43            space.domain = self.0;
44            Ok(space)
45        }
46    }
47    impl TryAsSpace for LkPath {
48        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
49            SpaceExpr::try_from(self)?.eval(scope.as_scope().as_dyn())
50        }
51    }
52    impl TryAsSpace for LkPathArray {
53        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
54            self.as_path().try_as_space(scope)
55        }
56    }
57    impl TryAsSpace for &[&[u8]] {
58        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
59            SpaceExpr::from_scope_local(
60                None,
61                None,
62                linkspace_core::point::LkPathArray::try_from_iter(self.iter())?.into(),
63            )?
64            .eval(scope.as_scope().as_dyn())
65        }
66    }
67    /// The full space expression format "domain:group:/some/path"
68    impl TryAsSpace for str {
69        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
70            let se: SpaceExpr = self.parse()?;
71            se.eval(scope.as_scope().as_dyn())
72        }
73    }
74    impl TryAsSpace for SpaceExpr {
75        fn try_as_space(&self, scope: &dyn LkEnv) -> anyhow::Result<Space> {
76            self.eval(scope.as_scope().as_dyn())
77        }
78    }
79}
80
81pub use work_env::LkEnv;
82pub mod work_env {
83    use linkspace_core::abe::eval::ScopeSet;
84    use linkspace_core::point::AsPointPtr;
85    use linkspace_core::space_expr::SubSpace;
86    use linkspace_system::thread_local::set_system;
87
88    use crate::prelude::*;
89    use crate::system::lks_current;
90    use crate::work_env::*;
91    /// [LkEnvData] is a collection of pointers the user can supply to extend the available expressions when evaluating an ab-expression
92    /// This [LkEnvData] is packed together with a set of default scopes into a [LkaScope] struct.
93    /// [LkEnv] is a utility trait - allowing you to quickly change a field in the effective [LkEnvData].
94    /// eg  lka_eval("", &() as &dyn UserScope);  lka_eval("[0] [1]", &["hello","world"]);
95    pub trait LkEnv {
96        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>);
97        fn as_scope(&self) -> LkaScope {
98            let mut ud = LkEnvData::default();
99            self.userdata(&mut ud);
100            ud.into()
101        }
102    }
103    impl LkEnv for (&dyn LkEnv, &dyn LkEnv) {
104        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
105            self.0.userdata(out);
106            self.1.userdata(out);
107        }
108    }
109    impl LkEnv for Option<&dyn LkEnv> {
110        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
111            if let Some(wv) = self {
112                wv.userdata(out);
113            }
114        }
115    }
116
117    impl<'o> From<LkEnvData<'o>> for LkaScope<'o> {
118        fn from(ud: LkEnvData<'o>) -> Self {
119            LkaScope(InlineScope::Std(ScopeSet(ud)))
120        }
121    }
122    impl LkEnv for () {
123        fn userdata<'o>(&'o self, _out: &mut LkEnvData<'o>) {}
124    }
125    impl LkEnv for LkEnvData<'_> {
126        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
127            *out = *self;
128        }
129    }
130    impl LkEnv for &dyn Point {
131        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
132            out.point = Some(self);
133        }
134    }
135    impl LkEnv for (&dyn Point, &[&[u8]]) {
136        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
137            out.point = Some(self.0);
138            out.argv = Some(self.1);
139        }
140    }
141    impl LkEnv for (Option<&dyn Point>, Option<&[&[u8]]>) {
142        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
143            out.point = self.0;
144            out.argv = self.1;
145        }
146    }
147    impl LkEnv for &[&[u8]] {
148        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
149            out.argv = Some(self)
150        }
151    }
152    impl<const N: usize> LkEnv for [&[u8]; N] {
153        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
154            out.argv = Some(self);
155        }
156    }
157    impl LkEnv for LkaScope<'_> {
158        fn userdata<'o>(&'o self, _out: &mut LkEnvData<'o>) {}
159        fn as_scope(&self) -> LkaScope {
160            self.clone()
161        }
162    }
163    impl LkEnv for Space {
164        fn userdata<'o>(&'o self, out: &mut crate::work_env::LkEnvData<'o>) {
165            out.domain = Some(&self.domain);
166            out.group = Some(&self.group);
167        }
168    }
169    impl LkEnv for SubSpace {
170        fn userdata<'o>(&'o self, out: &mut crate::work_env::LkEnvData<'o>) {
171            self.space.userdata(out);
172            out.pubkey = self.pubkey.as_ref()
173        }
174    }
175    impl LkEnv for LkIdentity {
176        fn userdata<'o>(&'o self, out: &mut crate::work_env::LkEnvData<'o>) {
177            out.key = Some(self);
178        }
179    }
180    impl LkEnv for (Domain, GroupID, PubKey) {
181        fn userdata<'o>(&'o self, out: &mut crate::work_env::LkEnvData<'o>) {
182            out.domain = Some(&self.0);
183            out.group = Some(&self.1);
184            out.pubkey = Some(&self.2);
185        }
186    }
187    impl LkEnv for (Domain, GroupID) {
188        fn userdata<'o>(&'o self, out: &mut crate::work_env::LkEnvData<'o>) {
189            out.domain = Some(&self.0);
190            out.group = Some(&self.1);
191        }
192    }
193    impl LkEnv for LkEnvDataSync {
194        fn userdata<'o>(&'o self, out: &mut LkEnvData<'o>) {
195            let LkEnvDataSync {
196                point,
197                argv,
198                domain,
199                group,
200                pubkey,
201                key,
202                lksi,
203            } = self;
204            if let Some(lksi) = lksi {
205                // FIXME: this is messy - Implementing LkEnv requires a reference to a LkSystem ( to keep LkEnvData as Copy)
206
207                if let Some(current) = lks_current() {
208                    let info = system::lks_info(Some(&current)).unwrap();
209                    assert!(
210                        info.name == lksi.name && info.kind == lksi.kind,
211                        "FIXME: Setting LKS via LkEnvDataSync is not supported beyond setting the global system"
212                    );
213                };
214                let lks = crate::system::lks_from_info(lksi).expect("bad LksInfo?");
215
216                unsafe {
217                    set_system(lks.into());
218                }
219            }
220            out.point = point.as_ref().map(|o| o.as_netptr() as &dyn Point);
221            if argv.is_some() {
222                unimplemented!("TODO: argv should be serializable");
223            }
224            out.domain = domain.as_ref();
225            out.group = group.as_ref();
226            out.pubkey = pubkey.as_ref();
227            out.key = key.as_ref();
228        }
229    }
230}
231
232pub use stmnts::Stmnts;
233pub mod stmnts {
234    use crate::{LkQuery, LkResult};
235    pub trait Stmnts {
236        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()>;
237    }
238    impl Stmnts for &[u8] {
239        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
240            per_line(self)
241        }
242    }
243    impl Stmnts for &str {
244        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
245            per_line(self.as_bytes())
246        }
247    }
248    impl Stmnts for LkQuery {
249        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
250            self.to_string().per_line(per_line)
251        }
252    }
253    impl Stmnts for String {
254        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
255            per_line(self.as_bytes())
256        }
257    }
258    impl Stmnts for () {
259        fn per_line(&self, _per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
260            Ok(())
261        }
262    }
263    impl<X: Stmnts> Stmnts for &[X] {
264        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
265            self.iter().try_for_each(|o| o.per_line(per_line))
266        }
267    }
268    impl<const L: usize, X: Stmnts> Stmnts for [X; L] {
269        fn per_line(&self, per_line: &mut dyn FnMut(&[u8]) -> LkResult<()>) -> LkResult<()> {
270            self.iter().try_for_each(|o| o.per_line(per_line))
271        }
272    }
273}