Skip to main content

graphix_package_array/
lib.rs

1use anyhow::{bail, Result};
2use compact_str::format_compact;
3use graphix_compiler::{
4    expr::ExprId,
5    node::genn,
6    typ::{FnType, Type},
7    Apply, BindId, BuiltIn, Event, ExecCtx, LambdaId, Node, Refs, Rt, UserEvent,
8};
9use graphix_package_core::{
10    deftype, CachedArgs, CachedVals, EvalCached, FoldFn, FoldQ, MapFn, MapQ, Slot,
11};
12use graphix_rt::GXRt;
13use netidx::{publisher::Typ, subscriber::Value, utils::Either};
14use netidx_value::ValArray;
15use smallvec::{smallvec, SmallVec};
16use std::{collections::VecDeque, fmt::Debug, iter};
17
18#[derive(Debug, Default)]
19struct MapImpl;
20
21impl<R: Rt, E: UserEvent> MapFn<R, E> for MapImpl {
22    type Collection = ValArray;
23
24    const NAME: &str = "array_map";
25    deftype!("fn(Array<'a>, fn('a) -> 'b throws 'e) -> Array<'b> throws 'e");
26
27    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
28        Some(Value::Array(ValArray::from_iter_exact(
29            slots.iter().map(|s| s.cur.clone().unwrap()),
30        )))
31    }
32}
33
34type Map<R, E> = MapQ<R, E, MapImpl>;
35
36#[derive(Debug, Default)]
37struct FilterImpl;
38
39impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterImpl {
40    type Collection = ValArray;
41
42    const NAME: &str = "array_filter";
43    deftype!("fn(Array<'a>, fn('a) -> bool throws 'e) -> Array<'a> throws 'e");
44
45    fn finish(&mut self, slots: &[Slot<R, E>], a: &ValArray) -> Option<Value> {
46        Some(Value::Array(ValArray::from_iter(slots.iter().zip(a.iter()).filter_map(
47            |(p, v)| match p.cur {
48                Some(Value::Bool(true)) => Some(v.clone()),
49                _ => None,
50            },
51        ))))
52    }
53}
54
55type Filter<R, E> = MapQ<R, E, FilterImpl>;
56
57#[derive(Debug, Default)]
58struct FlatMapImpl;
59
60impl<R: Rt, E: UserEvent> MapFn<R, E> for FlatMapImpl {
61    type Collection = ValArray;
62
63    const NAME: &str = "array_flat_map";
64    deftype!("fn(Array<'a>, fn('a) -> ['b, Array<'b>] throws 'e) -> Array<'b> throws 'e");
65
66    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
67        Some(Value::Array(ValArray::from_iter(slots.iter().flat_map(|s| {
68            match s.cur.as_ref().unwrap() {
69                Value::Array(a) => Either::Left(a.clone().into_iter()),
70                v => Either::Right(iter::once(v.clone())),
71            }
72        }))))
73    }
74}
75
76type FlatMap<R, E> = MapQ<R, E, FlatMapImpl>;
77
78#[derive(Debug, Default)]
79struct FilterMapImpl;
80
81impl<R: Rt, E: UserEvent> MapFn<R, E> for FilterMapImpl {
82    type Collection = ValArray;
83
84    const NAME: &str = "array_filter_map";
85    deftype!("fn(Array<'a>, fn('a) -> Option<'b> throws 'e) -> Array<'b> throws 'e");
86
87    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
88        Some(Value::Array(ValArray::from_iter(slots.iter().filter_map(|s| {
89            match s.cur.as_ref().unwrap() {
90                Value::Null => None,
91                v => Some(v.clone()),
92            }
93        }))))
94    }
95}
96
97type FilterMap<R, E> = MapQ<R, E, FilterMapImpl>;
98
99#[derive(Debug, Default)]
100struct FindImpl;
101
102impl<R: Rt, E: UserEvent> MapFn<R, E> for FindImpl {
103    type Collection = ValArray;
104
105    const NAME: &str = "array_find";
106    deftype!("fn(Array<'a>, fn('a) -> bool throws 'e) -> Option<'a> throws 'e");
107
108    fn finish(&mut self, slots: &[Slot<R, E>], a: &ValArray) -> Option<Value> {
109        let r = slots
110            .iter()
111            .enumerate()
112            .find(|(_, s)| match s.cur.as_ref() {
113                Some(Value::Bool(true)) => true,
114                _ => false,
115            })
116            .map(|(i, _)| a[i].clone())
117            .unwrap_or(Value::Null);
118        Some(r)
119    }
120}
121
122type Find<R, E> = MapQ<R, E, FindImpl>;
123
124#[derive(Debug, Default)]
125struct FindMapImpl;
126
127impl<R: Rt, E: UserEvent> MapFn<R, E> for FindMapImpl {
128    type Collection = ValArray;
129
130    const NAME: &str = "array_find_map";
131    deftype!("fn(Array<'a>, fn('a) -> Option<'b> throws 'e) -> Option<'b> throws 'e");
132
133    fn finish(&mut self, slots: &[Slot<R, E>], _: &ValArray) -> Option<Value> {
134        let r = slots
135            .iter()
136            .find_map(|s| match s.cur.as_ref().unwrap() {
137                Value::Null => None,
138                v => Some(v.clone()),
139            })
140            .unwrap_or(Value::Null);
141        Some(r)
142    }
143}
144
145type FindMap<R, E> = MapQ<R, E, FindMapImpl>;
146
147#[derive(Debug)]
148struct FoldImpl;
149
150impl<R: Rt, E: UserEvent> FoldFn<R, E> for FoldImpl {
151    type Collection = ValArray;
152
153    const NAME: &str = "array_fold";
154    deftype!("fn(Array<'a>, 'b, fn('b, 'a) -> 'b throws 'e) -> 'b throws 'e");
155}
156
157type Fold<R, E> = FoldQ<R, E, FoldImpl>;
158
159#[derive(Debug, Default)]
160struct ConcatEv(SmallVec<[Value; 32]>);
161
162impl EvalCached for ConcatEv {
163    const NAME: &str = "array_concat";
164    deftype!("fn(Array<'a>, @args: Array<'a>) -> Array<'a>");
165
166    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
167        let mut present = true;
168        for v in from.0.iter() {
169            match v {
170                Some(Value::Array(a)) => {
171                    for v in a.iter() {
172                        self.0.push(v.clone())
173                    }
174                }
175                Some(v) => self.0.push(v.clone()),
176                None => present = false,
177            }
178        }
179        if present {
180            let a = ValArray::from_iter_exact(self.0.drain(..));
181            Some(Value::Array(a))
182        } else {
183            self.0.clear();
184            None
185        }
186    }
187}
188
189type Concat = CachedArgs<ConcatEv>;
190
191#[derive(Debug, Default)]
192struct PushBackEv(SmallVec<[Value; 32]>);
193
194impl EvalCached for PushBackEv {
195    const NAME: &str = "array_push_back";
196    deftype!("fn(Array<'a>, @args: 'a) -> Array<'a>");
197
198    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
199        let mut present = true;
200        match &from.0[..] {
201            [Some(Value::Array(a)), tl @ ..] => {
202                self.0.extend(a.iter().map(|v| v.clone()));
203                for v in tl {
204                    match v {
205                        Some(v) => self.0.push(v.clone()),
206                        None => present = false,
207                    }
208                }
209            }
210            [] | [None, ..] | [Some(_), ..] => present = false,
211        }
212        if present {
213            let a = ValArray::from_iter_exact(self.0.drain(..));
214            Some(Value::Array(a))
215        } else {
216            self.0.clear();
217            None
218        }
219    }
220}
221
222type PushBack = CachedArgs<PushBackEv>;
223
224#[derive(Debug, Default)]
225struct PushFrontEv(SmallVec<[Value; 32]>);
226
227impl EvalCached for PushFrontEv {
228    const NAME: &str = "array_push_front";
229    deftype!("fn(Array<'a>, @args: 'a) -> Array<'a>");
230
231    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
232        let mut present = true;
233        match &from.0[..] {
234            [Some(Value::Array(a)), tl @ ..] => {
235                for v in tl {
236                    match v {
237                        Some(v) => self.0.push(v.clone()),
238                        None => present = false,
239                    }
240                }
241                self.0.extend(a.iter().map(|v| v.clone()));
242            }
243            [] | [None, ..] | [Some(_), ..] => present = false,
244        }
245        if present {
246            let a = ValArray::from_iter_exact(self.0.drain(..));
247            Some(Value::Array(a))
248        } else {
249            self.0.clear();
250            None
251        }
252    }
253}
254
255type PushFront = CachedArgs<PushFrontEv>;
256
257#[derive(Debug, Default)]
258struct WindowEv(SmallVec<[Value; 32]>);
259
260impl EvalCached for WindowEv {
261    const NAME: &str = "array_window";
262    deftype!("fn(#n:i64, Array<'a>, @args: 'a) -> Array<'a>");
263
264    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
265        let mut present = true;
266        match &from.0[..] {
267            [Some(Value::I64(window)), Some(Value::Array(a)), tl @ ..] => {
268                let window = *window as usize;
269                let total = a.len() + tl.len();
270                if total <= window {
271                    self.0.extend(a.iter().cloned());
272                    for v in tl {
273                        match v {
274                            Some(v) => self.0.push(v.clone()),
275                            None => present = false,
276                        }
277                    }
278                } else if a.len() >= (total - window) {
279                    self.0.extend(a[(total - window)..].iter().cloned());
280                    for v in tl {
281                        match v {
282                            Some(v) => self.0.push(v.clone()),
283                            None => present = false,
284                        }
285                    }
286                } else {
287                    for v in &tl[tl.len() - window..] {
288                        match v {
289                            Some(v) => self.0.push(v.clone()),
290                            None => present = false,
291                        }
292                    }
293                }
294            }
295            [] | [_] | [_, None, ..] | [None, _, ..] | [Some(_), Some(_), ..] => {
296                present = false
297            }
298        }
299        if present {
300            let a = ValArray::from_iter_exact(self.0.drain(..));
301            Some(Value::Array(a))
302        } else {
303            self.0.clear();
304            None
305        }
306    }
307}
308
309type Window = CachedArgs<WindowEv>;
310
311#[derive(Debug, Default)]
312struct LenEv;
313
314impl EvalCached for LenEv {
315    const NAME: &str = "array_len";
316    deftype!("fn(Array<'a>) -> i64");
317
318    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
319        match &from.0[0] {
320            Some(Value::Array(a)) => Some(Value::I64(a.len() as i64)),
321            Some(_) | None => None,
322        }
323    }
324}
325
326type Len = CachedArgs<LenEv>;
327
328#[derive(Debug, Default)]
329struct FlattenEv(SmallVec<[Value; 32]>);
330
331impl EvalCached for FlattenEv {
332    const NAME: &str = "array_flatten";
333    deftype!("fn(Array<Array<'a>>) -> Array<'a>");
334
335    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
336        match &from.0[0] {
337            Some(Value::Array(a)) => {
338                for v in a.iter() {
339                    match v {
340                        Value::Array(a) => self.0.extend(a.iter().map(|v| v.clone())),
341                        v => self.0.push(v.clone()),
342                    }
343                }
344                let a = ValArray::from_iter_exact(self.0.drain(..));
345                Some(Value::Array(a))
346            }
347            Some(_) | None => None,
348        }
349    }
350}
351
352type Flatten = CachedArgs<FlattenEv>;
353
354#[derive(Debug, Default)]
355struct SortEv(SmallVec<[Value; 32]>);
356
357impl EvalCached for SortEv {
358    const NAME: &str = "array_sort";
359    deftype!("fn(?#dir:Direction, ?#numeric:bool, Array<'a>) -> Array<'a>");
360
361    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
362        fn cn(v: &Value) -> Value {
363            v.clone().cast(Typ::F64).unwrap_or_else(|| v.clone())
364        }
365        match &from.0[..] {
366            [Some(Value::String(dir)), Some(Value::Bool(numeric)), Some(Value::Array(a))] => {
367                match &**dir {
368                    "Ascending" => {
369                        self.0.extend(a.iter().cloned());
370                        if *numeric {
371                            self.0.sort_by(|v0, v1| cn(v0).cmp(&cn(v1)))
372                        } else {
373                            self.0.sort();
374                        }
375                        Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))))
376                    }
377                    "Descending" => {
378                        self.0.extend(a.iter().cloned());
379                        if *numeric {
380                            self.0.sort_by(|a0, a1| cn(a1).cmp(&cn(a0)))
381                        } else {
382                            self.0.sort_by(|a0, a1| a1.cmp(a0));
383                        }
384                        Some(Value::Array(ValArray::from_iter_exact(self.0.drain(..))))
385                    }
386                    _ => None,
387                }
388            }
389            _ => None,
390        }
391    }
392}
393
394type Sort = CachedArgs<SortEv>;
395
396#[derive(Debug, Default)]
397struct EnumerateEv;
398
399impl EvalCached for EnumerateEv {
400    const NAME: &str = "array_enumerate";
401    deftype!("fn(Array<'a>) -> Array<(i64, 'a)>");
402
403    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
404        if let Some(Value::Array(a)) = &from.0[0] {
405            let a = ValArray::from_iter_exact(
406                a.iter().enumerate().map(|(i, v)| (i, v.clone()).into()),
407            );
408            return Some(Value::Array(a));
409        }
410        None
411    }
412}
413
414type Enumerate = CachedArgs<EnumerateEv>;
415
416#[derive(Debug, Default)]
417struct ZipEv;
418
419impl EvalCached for ZipEv {
420    const NAME: &str = "array_zip";
421    deftype!("fn(Array<'a>, Array<'b>) -> Array<('a, 'b)>");
422
423    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
424        match &from.0[..] {
425            [Some(Value::Array(a0)), Some(Value::Array(a1))] => {
426                Some(Value::Array(ValArray::from_iter_exact(
427                    a0.iter().cloned().zip(a1.iter().cloned()).map(|p| p.into()),
428                )))
429            }
430            _ => None,
431        }
432    }
433}
434
435type Zip = CachedArgs<ZipEv>;
436
437#[derive(Debug, Default)]
438struct UnzipEv {
439    t0: Vec<Value>,
440    t1: Vec<Value>,
441}
442
443impl EvalCached for UnzipEv {
444    const NAME: &str = "array_unzip";
445    deftype!("fn(Array<('a, 'b)>) -> (Array<'a>, Array<'b>)");
446
447    fn eval(&mut self, from: &CachedVals) -> Option<Value> {
448        match &from.0[..] {
449            [Some(Value::Array(a))] => {
450                for v in a {
451                    if let Value::Array(a) = v {
452                        match &a[..] {
453                            [v0, v1] => {
454                                self.t0.push(v0.clone());
455                                self.t1.push(v1.clone());
456                            }
457                            _ => (),
458                        }
459                    }
460                }
461                let v0 = Value::Array(ValArray::from_iter_exact(self.t0.drain(..)));
462                let v1 = Value::Array(ValArray::from_iter_exact(self.t1.drain(..)));
463                Some(Value::Array(ValArray::from_iter_exact([v0, v1].into_iter())))
464            }
465            _ => None,
466        }
467    }
468}
469
470type Unzip = CachedArgs<UnzipEv>;
471
472#[derive(Debug)]
473struct Group<R: Rt, E: UserEvent> {
474    queue: VecDeque<Value>,
475    buf: SmallVec<[Value; 16]>,
476    pred: Node<R, E>,
477    ready: bool,
478    pid: BindId,
479    nid: BindId,
480    xid: BindId,
481}
482
483impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Group<R, E> {
484    const NAME: &str = "array_group";
485    deftype!("fn('a, fn(i64, 'a) -> bool throws 'e) -> Array<'a> throws 'e");
486
487    fn init<'a, 'b, 'c>(
488        ctx: &'a mut ExecCtx<R, E>,
489        typ: &'a FnType,
490        scope: &'b graphix_compiler::Scope,
491        from: &'c [Node<R, E>],
492        top_id: ExprId,
493    ) -> Result<Box<dyn Apply<R, E>>> {
494        match from {
495            [_, _] => {
496                let scope =
497                    scope.append(&format_compact!("fn{}", LambdaId::new().inner()));
498                let n_typ = Type::Primitive(Typ::I64.into());
499                let etyp = typ.args[0].typ.clone();
500                let mftyp = match &typ.args[1].typ {
501                    Type::Fn(ft) => ft.clone(),
502                    t => bail!("expected function not {t}"),
503                };
504                let (nid, n) =
505                    genn::bind(ctx, &scope.lexical, "n", n_typ.clone(), top_id);
506                let (xid, x) = genn::bind(ctx, &scope.lexical, "x", etyp.clone(), top_id);
507                let pid = BindId::new();
508                let fnode = genn::reference(ctx, pid, Type::Fn(mftyp.clone()), top_id);
509                let pred = genn::apply(fnode, scope, vec![n, x], &mftyp, top_id);
510                Ok(Box::new(Self {
511                    queue: VecDeque::new(),
512                    buf: smallvec![],
513                    pred,
514                    ready: true,
515                    pid,
516                    nid,
517                    xid,
518                }))
519            }
520            _ => bail!("expected two arguments"),
521        }
522    }
523}
524
525impl<R: Rt, E: UserEvent> Apply<R, E> for Group<R, E> {
526    fn update(
527        &mut self,
528        ctx: &mut ExecCtx<R, E>,
529        from: &mut [Node<R, E>],
530        event: &mut Event<E>,
531    ) -> Option<Value> {
532        macro_rules! set {
533            ($v:expr) => {{
534                self.ready = false;
535                self.buf.push($v.clone());
536                let len = Value::I64(self.buf.len() as i64);
537                ctx.cached.insert(self.nid, len.clone());
538                event.variables.insert(self.nid, len);
539                ctx.cached.insert(self.xid, $v.clone());
540                event.variables.insert(self.xid, $v);
541            }};
542        }
543        if let Some(v) = from[0].update(ctx, event) {
544            self.queue.push_back(v);
545        }
546        if let Some(v) = from[1].update(ctx, event) {
547            ctx.cached.insert(self.pid, v.clone());
548            event.variables.insert(self.pid, v);
549        }
550        if self.ready && self.queue.len() > 0 {
551            let v = self.queue.pop_front().unwrap();
552            set!(v);
553        }
554        loop {
555            match self.pred.update(ctx, event) {
556                None => break None,
557                Some(v) => {
558                    self.ready = true;
559                    match v {
560                        Value::Bool(true) => {
561                            break Some(Value::Array(ValArray::from_iter_exact(
562                                self.buf.drain(..),
563                            )))
564                        }
565                        _ => match self.queue.pop_front() {
566                            None => break None,
567                            Some(v) => set!(v),
568                        },
569                    }
570                }
571            }
572        }
573    }
574
575    fn typecheck(
576        &mut self,
577        ctx: &mut ExecCtx<R, E>,
578        _from: &mut [Node<R, E>],
579    ) -> anyhow::Result<()> {
580        self.pred.typecheck(ctx)
581    }
582
583    fn refs(&self, refs: &mut Refs) {
584        self.pred.refs(refs)
585    }
586
587    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
588        ctx.cached.remove(&self.nid);
589        ctx.cached.remove(&self.pid);
590        ctx.cached.remove(&self.xid);
591        self.pred.delete(ctx);
592    }
593
594    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
595        self.pred.sleep(ctx);
596    }
597}
598
599#[derive(Debug)]
600struct Iter(BindId, ExprId);
601
602impl<R: Rt, E: UserEvent> BuiltIn<R, E> for Iter {
603    const NAME: &str = "array_iter";
604    deftype!("fn(Array<'a>) -> 'a");
605
606    fn init<'a, 'b, 'c>(
607        ctx: &'a mut ExecCtx<R, E>,
608        _typ: &'a FnType,
609        _scope: &'b graphix_compiler::Scope,
610        _from: &'c [Node<R, E>],
611        top_id: ExprId,
612    ) -> Result<Box<dyn Apply<R, E>>> {
613        let id = BindId::new();
614        ctx.rt.ref_var(id, top_id);
615        Ok(Box::new(Iter(id, top_id)))
616    }
617}
618
619impl<R: Rt, E: UserEvent> Apply<R, E> for Iter {
620    fn update(
621        &mut self,
622        ctx: &mut ExecCtx<R, E>,
623        from: &mut [Node<R, E>],
624        event: &mut Event<E>,
625    ) -> Option<Value> {
626        if let Some(Value::Array(a)) = from[0].update(ctx, event) {
627            for v in a.iter() {
628                ctx.rt.set_var(self.0, v.clone());
629            }
630        }
631        event.variables.get(&self.0).map(|v| v.clone())
632    }
633
634    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
635        ctx.rt.unref_var(self.0, self.1)
636    }
637
638    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
639        ctx.rt.unref_var(self.0, self.1);
640        self.0 = BindId::new();
641        ctx.rt.ref_var(self.0, self.1);
642    }
643}
644
645#[derive(Debug)]
646struct IterQ {
647    triggered: usize,
648    queue: VecDeque<(usize, ValArray)>,
649    id: BindId,
650    top_id: ExprId,
651}
652
653impl<R: Rt, E: UserEvent> BuiltIn<R, E> for IterQ {
654    const NAME: &str = "array_iterq";
655    deftype!("fn(#clock:Any, Array<'a>) -> 'a");
656
657    fn init<'a, 'b, 'c>(
658        ctx: &'a mut ExecCtx<R, E>,
659        _typ: &'a FnType,
660        _scope: &'b graphix_compiler::Scope,
661        _from: &'c [Node<R, E>],
662        top_id: ExprId,
663    ) -> Result<Box<dyn Apply<R, E>>> {
664        let id = BindId::new();
665        ctx.rt.ref_var(id, top_id);
666        Ok(Box::new(IterQ { triggered: 0, queue: VecDeque::new(), id, top_id }))
667    }
668}
669
670impl<R: Rt, E: UserEvent> Apply<R, E> for IterQ {
671    fn update(
672        &mut self,
673        ctx: &mut ExecCtx<R, E>,
674        from: &mut [Node<R, E>],
675        event: &mut Event<E>,
676    ) -> Option<Value> {
677        if from[0].update(ctx, event).is_some() {
678            self.triggered += 1;
679        }
680        if let Some(Value::Array(a)) = from[1].update(ctx, event) {
681            if a.len() > 0 {
682                self.queue.push_back((0, a));
683            }
684        }
685        while self.triggered > 0 && self.queue.len() > 0 {
686            let (i, a) = self.queue.front_mut().unwrap();
687            while self.triggered > 0 && *i < a.len() {
688                ctx.rt.set_var(self.id, a[*i].clone());
689                *i += 1;
690                self.triggered -= 1;
691            }
692            if *i == a.len() {
693                self.queue.pop_front();
694            }
695        }
696        event.variables.get(&self.id).cloned()
697    }
698
699    fn delete(&mut self, ctx: &mut ExecCtx<R, E>) {
700        ctx.rt.unref_var(self.id, self.top_id)
701    }
702
703    fn sleep(&mut self, ctx: &mut ExecCtx<R, E>) {
704        ctx.rt.unref_var(self.id, self.top_id);
705        self.id = BindId::new();
706        self.queue.clear();
707        self.triggered = 0;
708    }
709}
710
711graphix_derive::defpackage! {
712    builtins => [
713        Concat,
714        Filter as Filter<GXRt<X>, X::UserEvent>,
715        FilterMap as FilterMap<GXRt<X>, X::UserEvent>,
716        Find as Find<GXRt<X>, X::UserEvent>,
717        FindMap as FindMap<GXRt<X>, X::UserEvent>,
718        FlatMap as FlatMap<GXRt<X>, X::UserEvent>,
719        Enumerate,
720        Zip,
721        Unzip,
722        Flatten,
723        Fold as Fold<GXRt<X>, X::UserEvent>,
724        Group as Group<GXRt<X>, X::UserEvent>,
725        Iter,
726        IterQ,
727        Len,
728        Map as Map<GXRt<X>, X::UserEvent>,
729        PushBack,
730        PushFront,
731        Sort,
732        Window,
733    ],
734}