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