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}