lifecycle.bend

bendvy-ecs-core@0.1.0.3 · 83 lines · 18 definitions

1import Base
2import bendvy-ecs-core@0.1.0.3/change_tick.bend as Tick
3
4# Metadata is Data; payload ownership stays in the typed column. Identity is
5# the caller's closed typed column lens, never the family's display name.
6type Stamp is Data:
7  Stamp{added: Maybe<&2,Tick.Tick>,changed: Maybe<&2,Tick.Tick>}
8type Entry is Data:
9  Entry{id: U32,stamp: Stamp}
10
11def choose(found: Bool,stamp: Stamp,other: Stamp) -> Stamp:
12  match found:
13    case True{}: stamp
14    case False{}: other
15
16def get_selected(entries: List<&2,Entry>,+id: U32,found: Bool,stamp: Stamp) -> Stamp:
17  match entries found:
18    case _ True{}: stamp
19    case Nil{} False{}: Stamp{None{},None{}}
20    case Con{Entry{key,current},rest} False{}: get_selected(rest,id,U32.is_eq(key,id),current)
21
22def get(entries: List<&2,Entry>,id: U32) -> Stamp:
23  get_selected(entries,id,False{},Stamp{None{},None{}})
24
25
26def keep(equal: Bool,entry: Entry,rest: List<&2,Entry>) -> List<&2,Entry>:
27  match equal:
28    case True{}: rest
29    case False{}: entry <> rest
30
31def entry_id(entry:Entry) -> U32:
32  match entry:
33    case Entry{id,_}:id
34
35def clear_reversed(entries: List<&2,Entry>,+id: U32,acc: List<&2,Entry>) -> List<&2,Entry>:
36  match entries:
37    case []: List.reverse(&2,Entry,acc)
38    case +entry <> rest: clear_reversed(rest,id,keep(U32.is_eq(entry_id(entry),id),entry,acc))
39
40def clear(entries: List<&2,Entry>,id: U32) -> List<&2,Entry>:
41  clear_reversed(entries,id,[])
42
43def set(entries: List<&2,Entry>,+id: U32,stamp: Stamp) -> List<&2,Entry>:
44  Entry{id,stamp} <> clear(entries,id)
45
46def written(wasPresent: Bool,stamp: Stamp,+tick: Tick.Tick) -> Stamp:
47  match wasPresent stamp:
48    case False{} _: Stamp{Some{tick},Some{tick}}
49    case True{} Stamp{added,_}: Stamp{added,Some{tick}}
50
51def after_write(incoming: Bool,wasPresent: Bool,stamp: Stamp,tick: Tick.Tick) -> Stamp:
52  match incoming:
53    case False{}: Stamp{None{},None{}}
54    case True{}: written(wasPresent,stamp,tick)
55
56# Presence is explicit: wrapped tick zero is a valid component timestamp.
57def selected_age(+stamp:Tick.Tick,cursor:Maybe<&2,Tick.Tick>,+this:Tick.Tick) -> Bool:
58  match cursor:
59    case None{}:Bool.and(Tick.not_future(stamp,this),U32.is_lt(Tick.age(stamp,this),Tick.max_change_age()))
60    case Some{last}:Tick.newer(stamp,last,this)
61def selected(stamp:Maybe<&2,Tick.Tick>,cursor:Maybe<&2,Tick.Tick>,this:Tick.Tick) -> Bool:
62  match stamp:
63    case None{}:False{}
64    case Some{tick}:selected_age(tick,cursor,this)
65
66# Compare bounded true ages against this captured run; None is a first-run cursor.
67def added(stamp:Stamp,cursor:Maybe<&2,Tick.Tick>,this:Tick.Tick) -> Bool:
68  match stamp:
69    case Stamp{value,_}:selected(value,cursor,this)
70def changed(stamp:Stamp,cursor:Maybe<&2,Tick.Tick>,this:Tick.Tick) -> Bool:
71  match stamp:
72    case Stamp{_,value}:selected(value,cursor,this)
73
74# Bevy ad678262 query/filter.rs Added<T> and Changed<T> compare the selected
75# component tick with last_run/this_run. Here first execution is explicit None;
76# filters inspect the pre-write stamp in the owned query partition.
77type Filter is Data:
78  Added{}
79  Changed{}
80def matches(filter:Filter,stamp:Stamp,cursor:Maybe<&2,Tick.Tick>,this:Tick.Tick) -> Bool:
81  match filter:
82    case Added{}:added(stamp,cursor,this)
83    case Changed{}:changed(stamp,cursor,this)