1 import Base 2 import ./change_tick.bend as Tick 3 import ./clock_state.bend as Clock 4 import entity_allocator.bend as A 5 import entity_key.bend as Key 6 import restored_row.bend as R 7 import lifecycle.bend as L 8 import world.bend as W 9 import component.bend as C 10 import compose.bend as Q 11 12 type Header<-S:Data> is Type: 13 Header{namespace:U32,allocator:A.Allocator,handle:W.Handle,clock:Clock.State,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>} 14 type WriteResult<-H:Type,-C:Type> is Type: 15 Written{owner:H} 16 Rejected{owner:H,incoming:C,error:W.WorldError} 17 def handle_key(-S:Data,handle:W.Handle) -> Key.Key: 18 match handle: 19 case W.Handle{_,key}:key 20 def handle_index(-S:Data,handle:W.Handle) -> U32: 21 Key.index(handle_key(S,handle)) 22 def checked_live(-S:Data,namespace:U32,handle:W.Handle,clock:Clock.State,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>,observed:A.Allocator & Bool) -> Header & Bool: 23 match observed: 24 case (allocator,valid):(Header{namespace,allocator,handle,clock,error,cursor},valid) 25 def checked_namespace(-S:Data,same:Bool,namespace:U32,allocator:A.Allocator,+handle:W.Handle,clock:Clock.State,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>) -> Header & 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)) 29 def checked(-S:Data,header:Header) -> Header & 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) 32 def target(-S:Data,header:Header) -> Header & 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 36 def projected(~S:Data,~H:Type,~Rest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~bridge:H -> H & C.Access,rest:Rest,result:R.Projected) -> H & C.Access: 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)) 41 def get_ready(~S:Data,~H:Type,~Rest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~project:C -> C & V,~bridge:H -> H & C.Access,rest:Rest,cell:R.Cell,same:Bool) -> H & C.Access: 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)) 45 def cell_matches(~S:Data,~C:Type,cell:R.Cell,+id:U32) -> R.Cell & 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{}) 49 def get_matching(~S:Data,~H:Type,~Rest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~project:C -> C & V,~bridge:H -> H & C.Access,rest:Rest,observed:R.Cell & Bool) -> H & C.Access: 50 match observed: 51 case (cell,same): get_ready(~S,~H,~Rest,~C,~V,~put,~project,~bridge,rest,cell,same) 52 def get_targeted(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~put_header:MetaRest -> Header -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access,rest:MetaRest,cell:R.Cell,observed:Header & U32) -> H & C.Access: 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)) 55 def get_checked(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~put_header:MetaRest -> Header -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access,rest:MetaRest,cell:R.Cell,observed:Header & Bool) -> H & C.Access: 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)) 59 def get_split(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access,cell:R.Cell,observed:MetaRest & Header) -> H & C.Access: 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)) 62 def get_taken(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access,observed:Rest & R.Cell) -> H & C.Access: 63 match observed: 64 case (rest,cell): get_split(~S,~H,~Rest,~MetaRest,~C,~V,~put,~header,~put_header,~project,~bridge,cell,header(rest)) 65 def get(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~V:Data,~take:H -> Rest & R.Cell,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~project:C -> C & V,~bridge:H -> H & C.Access,owner:H) -> H & C.Access: 66 get_taken(~S,~H,~Rest,~MetaRest,~C,~V,~put,~header,~put_header,~project,~bridge,take(owner)) 67 68 def reject_header(-S:Data,reason:W.WorldError,header:Header) -> Header: 69 match header: 70 case Header{namespace,allocator,handle,clock,error,cursor}: Header{namespace,allocator,handle,clock,Q.first_error(error,reason),cursor} 71 def clock_advanced(-S:Data,namespace:U32,allocator:A.Allocator,handle:W.Handle,error:Maybe<&2,W.WorldError>,cursor:Maybe<&2,Tick.Tick>,observed:Clock.State & Tick.Tick) -> Header & Tick.Tick: 72 match observed: 73 case (clock,tick):(Header{namespace,allocator,handle,clock,error,cursor},tick) 74 def clocked(-S:Data,header:Header) -> Header & 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)) 77 def rejected(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~put_header:MetaRest -> Header -> Rest,rest:MetaRest,cell:R.Cell,incoming:C,+reason:W.WorldError,header:Header) -> WriteResult: 78 Rejected{put(put_header(rest,reject_header(S,reason,header)),cell),incoming,reason} 79 def replace_refused(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~put_header:MetaRest -> Header -> Rest,cell:R.Cell,incoming:C,observed:MetaRest & Header) -> WriteResult: 80 match observed: 81 case (rest,header): rejected(~S,~H,~Rest,~MetaRest,~C,~put,~put_header,rest,cell,incoming,W.CapacityExceeded{},header) 82 def replaced(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,rest:Rest,result:R.Replacement) -> WriteResult: 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)) 86 def write_clocked(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,rest:MetaRest,cell:R.Cell,incoming:C,observed:Header & Tick.Tick) -> WriteResult: 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)) 89 def write_matching(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult,rest:MetaRest,meta:Header,incoming:C,observed:R.Cell & Bool) -> WriteResult: 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)) 93 def write_targeted(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult,rest:MetaRest,cell:R.Cell,incoming:C,observed:Header & U32) -> WriteResult: 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)) 96 def write_checked(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult,rest:MetaRest,cell:R.Cell,incoming:C,observed:Header & Bool) -> WriteResult: 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)) 100 def write_split(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult,cell:R.Cell,incoming:C,observed:MetaRest & Header) -> WriteResult: 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)) 103 def write_taken(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult,incoming:C,observed:Rest & R.Cell) -> WriteResult: 104 match observed: 105 case (rest,cell): write_split(~S,~H,~Rest,~MetaRest,~C,~put,~header,~put_header,~journal,~bridge,cell,incoming,header(rest)) 106 def write(~S:Data,~H:Type,~Rest:Type,~MetaRest:Type,~C:Type,~take:H -> Rest & R.Cell,~put:Rest -> R.Cell -> H,~header:Rest -> MetaRest & Header,~put_header:MetaRest -> Header -> Rest,~journal:Rest -> Maybe<&1,C> -> L.Stamp -> Rest,~bridge:H -> C -> WriteResult,owner:H,incoming:C) -> WriteResult: 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. 109 def write_owner(~H:Type,~C:Type,result:WriteResult) -> H: 110 match result: 111 case Written{owner}: owner 112 case Rejected{owner,_,_}: owner