using concurrent**** A helper class used to store, access and retrieve mutable state within a 'const' class. For IoC ** this means your services can be declared as 'perApplication' or singleton scope.** ** 'ConcurrentState' wraps a state object in an Actor, and provides access to it via the ** 'withState' and 'getState' methods. Note that by their nature, these methods are immutable ** boundaries. Meaning that while all data in the State object can be mutable, but data passed in ** and out of the methods can not be. ** ** A full example of a mutable const map class is as follows:** ** pre>** const class ConstMap {** const ConcurrentState conState := ConcurrentState(ConstMapState#)** ** Str get(Str key) {** getState {** it.map[key]** }** }** ** Void put(Str key, Str value) {** withState {** it.map[key] = value** }** }** ** ** helper method used to narrow the state type** private Void withState(|ConstMapState| state) {** conState.withState(state)** }** ** ** helper method used to narrow the state type** private Obj? getState(|ConstMapState -> Obj| state) {** conState.getState(state)** }** }** ** class ConstMapState {** Str:Str map := [:]** }** <pre** constclass ConcurrentState {privatestaticconst Log log := Utils.getLog(ConcurrentState#)privatestaticconst ActorPool actorPool := ActorPool()privateconst Actor stateActor := Actor(actorPool, |Obj? obj -> Obj?| { receive(obj)})privateconst Type stateTypeprivateconst LocalStash stashprivate Obj? state { get { stash["state"]} set { stash["state"] = it}}** The given state type must have a public no-args ctor as per `sys::Type.make`new make(Type stateType){this.stateType = stateTypethis.stash = LocalStash(stateType)}** Use to access statevirtual Void withState(|Obj| f, Bool waitForErr := true){// explicit call to .toImmutable() - see http://fantom.org/sidewalk/topic/1798#c12190 func := f.toImmutable future := stateActor.send([!waitForErr, func].toImmutable)// use 'get' to so any Errs are re-thrown. As we're just setting / getting state the // messages should be fast anyway (and we don't want a 'get' to happen before a 'set')// Turn this off for event listeners when you really don't need it if(waitForErr) get(future)}** Use to return statevirtual Obj? getState(|Obj->Obj?| f){// explicit call to .toImmutable() - see http://fantom.org/sidewalk/topic/1798#c12190 func := f.toImmutable future := stateActor.send([false, func].toImmutable)return get(future)}private Obj? get(Future future){try{return future.get}catch(NotImmutableErr err){throw NotImmutableErr("Return value not immutable", err)}}protected Obj? receive(Obj[] msg){ reportErr := msg[0]as Bool func := msg[1]as |Obj?->Obj?|try{// lazily create our stateif(state == null) state = stateType.makereturn func.call(state)}catch(Err e){// if the func has a return type, then an the Err is rethrown on assignment// else we log the Err so the Thread doesn't fail silentlyif(reportErr || func.returns == Void#) log.err("receive()", e)throw e}}}