owned_family.bend

bendvy-ecs-core@0.1.0.1 · 112 lines · 0 definitions

1import Base
2import bendvy-ecs-core@0.1.0.1/change_tick.bend as Tick
3import bendvy-ecs-core@0.1.0.1/clock_state.bend as Clock
4import entity_allocator.bend as A
5import entity_key.bend as Key
6import restored_row.bend as R
7import lifecycle.bend as L
8import world.bend as W
9import component.bend as C
10import compose.bend as Q
11
12type Header<-S:Data> is Type:
13  Header{namespace:U32,allocator:A.Allocator,handle:W.Handle<S>,clock:Clock.State,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>}
14type WriteResult<-H:Type,-C:Type> is Type:
15  Written{owner:H}
16  Rejected{owner:H,incoming:C,error:W.WorldError}
17def handle_key(-S:Data,handle:W.Handle<S>) -> Key.Key:
18  match handle:
19    case W.Handle{_,key}:key
20def handle_index(-S:Data,handle:W.Handle<S>) -> U32:
21  Key.index(handle_key(S,handle))
22def checked_live(-S:Data,namespace:U32,handle:W.Handle<S>,clock:Clock.State,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>,observed:A.Allocator & Bool) -> Header<S> & Bool:
23  match observed:
24    case (allocator,valid):(Header{namespace,allocator,handle,clock,error,cursor},valid)
25def checked_namespace(-S:Data,same:Bool,namespace:U32,allocator:A.Allocator,+handle:W.Handle<S>,clock:Clock.State,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>) -> Header<S> & Bool:
26  match same:
27    case False{}:(Header{namespace,allocator,handle,clock,error,cursor},False{})
28    case True{}:checked_live(S,namespace,handle,clock,error,cursor,A.checked(allocator,handle_key(S,handle),1))
29def checked(-S:Data,header:Header<S>) -> Header<S> & Bool:
30  match header:
31    case Header{+namespace,allocator,W.Handle{+ns,+key},clock,error,cursor}:checked_namespace(S,U32.is_eq(namespace,ns),namespace,allocator,W.Handle{ns,key},clock,error,cursor)
32def target(-S:Data,header:Header<S>) -> Header<S> & U32:
33  match header:
34    case Header{namespace,allocator,+handle,clock,error,cursor}:(Header{namespace,allocator,handle,clock,error,cursor},handle_index(S,handle))
35
36def projected(~S:Data,~H:Type,~Rest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~bridge:H -> H & C.Access<V>,rest:Rest,result:R.Projected<S,C,V>) -> H & C.Access<V>:
37  match result:
38    case R.Projected{cell,None{}}: (put(rest,cell),C.ComponentAbsent{})
39    case R.Projected{cell,Some{value}}: (put(rest,cell),C.Found{value})
40    case R.Deferred{cell}: bridge(put(rest,cell))
41def get_ready(~S:Data,~H:Type,~Rest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~project:C -> C & V,~bridge:H -> H & C.Access<V>,rest:Rest,cell:R.Cell<S,C>,same:Bool) -> H & C.Access<V>:
42  match same:
43    case False{}: bridge(put(rest,cell))
44    case True{}: projected(~S,~H,~Rest,~C,~V,~put,~bridge,rest,R.project(~S,~C,~V,~project,cell))
45def cell_matches(~S:Data,~C:Type,cell:R.Cell<S,C>,+id:U32) -> R.Cell<S,C> & Bool:
46  match cell:
47    case R.Taken{+captured,owner,stamp,dirty,cold}: (R.Taken{captured,owner,stamp,dirty,cold},U32.is_eq(captured,id))
48    case other: (other,False{})
49def get_matching(~S:Data,~H:Type,~Rest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~project:C -> C & V,~bridge:H -> H & C.Access<V>,rest:Rest,observed:R.Cell<S,C> & Bool) -> H & C.Access<V>:
50  match observed:
51    case (cell,same): get_ready(~S,~H,~Rest,~C,~V,~put,~project,~bridge,rest,cell,same)
52def get_targeted(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~put_header:MetaRest -> Header<S> -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access<V>,rest:MetaRest,cell:R.Cell<S,C>,observed:Header<S> & U32) -> H & C.Access<V>:
53  match observed:
54    case (header,id): get_matching(~S,~H,~Rest,~C,~V,~put,~project,~bridge,put_header(rest,header),cell_matches(~S,~C,cell,id))
55def get_checked(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~put_header:MetaRest -> Header<S> -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access<V>,rest:MetaRest,cell:R.Cell<S,C>,observed:Header<S> & Bool) -> H & C.Access<V>:
56  match observed:
57    case (header,False{}): (put(put_header(rest,header),cell),C.MissingEntity{})
58    case (header,True{}): get_targeted(~S,~H,~Rest,~MetaRest,~C,~V,~put,~put_header,~project,~bridge,rest,cell,target(S,header))
59def get_split(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access<V>,cell:R.Cell<S,C>,observed:MetaRest & Header<S>) -> H & C.Access<V>:
60  match observed:
61    case (rest,meta): get_checked(~S,~H,~Rest,~MetaRest,~C,~V,~put,~put_header,~project,~bridge,rest,cell,checked(S,meta))
62def get_taken(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access<V>,observed:Rest & R.Cell<S,C>) -> H & C.Access<V>:
63  match observed:
64    case (rest,cell): get_split(~S,~H,~Rest,~MetaRest,~C,~V,~put,~header,~put_header,~project,~bridge,cell,header(rest))
65def get(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~take:H -> Rest & R.Cell<S,C>,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access<V>,owner:H) -> H & C.Access<V>:
66  get_taken(~S,~H,~Rest,~MetaRest,~C,~V,~put,~header,~put_header,~project,~bridge,take(owner))
67
68def reject_header(-S:Data,reason:W.WorldError,header:Header<S>) -> Header<S>:
69  match header:
70    case Header{namespace,allocator,handle,clock,error,cursor}: Header{namespace,allocator,handle,clock,Q.first_error(error,reason),cursor}
71def clock_advanced(-S:Data,namespace:U32,allocator:A.Allocator,handle:W.Handle<S>,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>,observed:Clock.State & Tick.Tick) -> Header<S> & Tick.Tick:
72  match observed:
73    case (clock,tick):(Header{namespace,allocator,handle,clock,error,cursor},tick)
74def clocked(-S:Data,header:Header<S>) -> Header<S> & Tick.Tick:
75  match header:
76    case Header{namespace,allocator,handle,clock,error,cursor}:clock_advanced(S,namespace,allocator,handle,error,cursor,Clock.write(clock))
77def rejected(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~put_header:MetaRest -> Header<S> -> Rest,rest:MetaRest,cell:R.Cell<S,C>,incoming:C,+reason:W.WorldError,header:Header<S>) -> WriteResult<H,C>:
78  Rejected{put(put_header(rest,reject_header(S,reason,header)),cell),incoming,reason}
79def replace_refused(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~put_header:MetaRest -> Header<S> -> Rest,cell:R.Cell<S,C>,incoming:C,observed:MetaRest & Header<S>) -> WriteResult<H,C>:
80  match observed:
81    case (rest,header): rejected(~S,~H,~Rest,~MetaRest,~C,~put,~put_header,rest,cell,incoming,W.CapacityExceeded{},header)
82def replaced(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,rest:Rest,result:R.Replacement<S,C>) -> WriteResult<H,C>:
83  match result:
84    case R.Replaced{cell,previous,stamp}: Written{put(journal(rest,previous,stamp),cell)}
85    case R.Refused{cell,incoming}: replace_refused(~S,~H,~Rest,~MetaRest,~C,~put,~put_header,cell,incoming,header(rest))
86def write_clocked(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,rest:MetaRest,cell:R.Cell<S,C>,incoming:C,observed:Header<S> & Tick.Tick) -> WriteResult<H,C>:
87  match observed:
88    case (meta,tick): replaced(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,put_header(rest,meta),R.replace(~S,~C,cell,incoming,tick))
89def write_matching(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult<H,C>,rest:MetaRest,meta:Header<S>,incoming:C,observed:R.Cell<S,C> & Bool) -> WriteResult<H,C>:
90  match observed:
91    case (cell,False{}): bridge(put(put_header(rest,meta),cell),incoming)
92    case (cell,True{}): write_clocked(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,rest,cell,incoming,clocked(S,meta))
93def write_targeted(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult<H,C>,rest:MetaRest,cell:R.Cell<S,C>,incoming:C,observed:Header<S> & U32) -> WriteResult<H,C>:
94  match observed:
95    case (meta,id): write_matching(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,~bridge,rest,meta,incoming,cell_matches(~S,~C,cell,id))
96def write_checked(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult<H,C>,rest:MetaRest,cell:R.Cell<S,C>,incoming:C,observed:Header<S> & Bool) -> WriteResult<H,C>:
97  match observed:
98    case (meta,False{}): rejected(~S,~H,~Rest,~MetaRest,~C,~put,~put_header,rest,cell,incoming,W.MissingEntity{},meta)
99    case (meta,True{}): write_targeted(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,~bridge,rest,cell,incoming,target(S,meta))
100def write_split(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult<H,C>,cell:R.Cell<S,C>,incoming:C,observed:MetaRest & Header<S>) -> WriteResult<H,C>:
101  match observed:
102    case (rest,meta): write_checked(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,~bridge,rest,cell,incoming,checked(S,meta))
103def write_taken(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult<H,C>,incoming:C,observed:Rest & R.Cell<S,C>) -> WriteResult<H,C>:
104  match observed:
105    case (rest,cell): write_split(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,~bridge,cell,incoming,header(rest))
106def write(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~take:H -> Rest & R.Cell<S,C>,~put:Rest -> R.Cell<S,C> -> H,~header:Rest -> MetaRest & Header<S>,~put_header:MetaRest -> Header<S> -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult<H,C>,owner:H,incoming:C) -> WriteResult<H,C>:
107  write_taken(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,~bridge,incoming,take(owner))
108# The public capability setter consumes refused incoming exactly like Q.written.
109def write_owner(~H:Type,~C:Type,result:WriteResult<H,C>) -> H:
110  match result:
111    case Written{owner}: owner
112    case Rejected{owner,_,_}: owner