mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-25 12:37:39 +08:00
fix EventEnv stackTrack problem, new method for GivenContext
This commit is contained in:
parent
6b961a3de3
commit
9574dd299b
@ -8,7 +8,7 @@ object MornyConfiguration {
|
||||
val MORNY_CODE_STORE = "https://github.com/Eyre-S/Coeur-Morny-Cono"
|
||||
val MORNY_COMMIT_PATH = "https://github.com/Eyre-S/Coeur-Morny-Cono/commit/%s"
|
||||
|
||||
val VERSION = "2.0.0-alpha5"
|
||||
val VERSION = "2.0.0-alpha6"
|
||||
val VERSION_DELTA: Option[String] = None
|
||||
val CODENAME = "guanggu"
|
||||
|
||||
|
@ -6,7 +6,6 @@ import cc.sukazyo.messiva.utils.StackUtils
|
||||
import com.pengrad.telegrambot.model.Update
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.reflect.{classTag, ClassTag}
|
||||
|
||||
class EventEnv (
|
||||
|
||||
@ -29,11 +28,11 @@ class EventEnv (
|
||||
|
||||
//noinspection UnitMethodIsParameterless
|
||||
def setEventOk: Unit =
|
||||
_status += State.OK(StackUtils.getStackTrace(1)(1))
|
||||
_status += State.OK(StackUtils.getStackTrace(1).head)
|
||||
|
||||
//noinspection UnitMethodIsParameterless
|
||||
def setEventCanceled: Unit =
|
||||
_status += State.CANCELED(StackUtils.getStackTrace(1)(1))
|
||||
_status += State.CANCELED(StackUtils.getStackTrace(1).head)
|
||||
|
||||
def state: State|Null =
|
||||
_status.lastOption match
|
||||
|
@ -1,9 +1,55 @@
|
||||
package cc.sukazyo.cono.morny.util
|
||||
|
||||
import cc.sukazyo.cono.morny.util.GivenContext.ContextNotGivenException
|
||||
|
||||
import scala.annotation.targetName
|
||||
import scala.collection.mutable
|
||||
import scala.reflect.{classTag, ClassTag}
|
||||
|
||||
object GivenContext {
|
||||
class ContextNotGivenException extends NoSuchElementException
|
||||
}
|
||||
|
||||
/** A mutable collection that can store(provide) any typed value and read(use/consume) that value by type.
|
||||
*
|
||||
* ## Simple Guide
|
||||
* {{{
|
||||
* val cxt = GivenContext()
|
||||
* class BaseClass {}
|
||||
* class MyImplementation extends BaseClass {}
|
||||
*
|
||||
*
|
||||
* cxt.provide(true) // this provides a Boolean
|
||||
* cxt.provide[BaseClass](new MyImplementation()) // although this object is of type MyImplementation, but it is stored
|
||||
* // as BaseClass so you can (and actually can only) read it using BaseClass
|
||||
* cxt << "string"
|
||||
* cxt << classOf[Int] -> 1 // you can also manually set the stored type using this method
|
||||
*
|
||||
*
|
||||
* cxt >> { (i: Int) => println(i) } || { println("no Int data in the context") }
|
||||
* val bool =
|
||||
* cxt.use[String, Boolean] { s => println(s); true } || { false } // when using .use, the return value must declared
|
||||
* cxt.consume[String] { s => println(s) } // you can use .consume if you don't care the return
|
||||
* // and this will return a cxt.ConsumeResult[Any]
|
||||
* val cxtResultOpt = // use toOption if you do not want fallback calculation
|
||||
* cxt.use[Int, String](int => s"int: $int").toOption // this returns Option[String]
|
||||
* val cxtResultOpt2 =
|
||||
* cxt >> { (int: Int) => s"int: $int" } |? // this returns Option[String] too
|
||||
* // cxt >> { (int: Int) => cxt >> { (str: String) => { str + int } } } |? // this below is not good to use due to .flatUse
|
||||
* // is not supported yet. It will return a
|
||||
* // cxt.ConsumeResult[Option[String]] which is very bad
|
||||
*
|
||||
* try { // for now, you can use this way to use multiple data
|
||||
* val int = cxt.use[Int] // this returns CxtOption[Int] which is Either[ContextNotGivenException, Int]
|
||||
* .toTry.get
|
||||
* val str = cxt >> classOf[String] match // this >> returns the same with the .use above
|
||||
* case Right(s) => s
|
||||
* case Left(err) => throw err // this is ContextNotGivenException
|
||||
* val bool = cxt >!> classOf[Boolean] // the easier way to do the above
|
||||
* } catch case e: ContextNotGivenException => // if any of the above val is not available, it will catch the exception
|
||||
* e.printStackTrace()
|
||||
* }}}
|
||||
*/
|
||||
class GivenContext {
|
||||
|
||||
private type ImplicitsMap [T <: Any] = mutable.HashMap[Class[?], T]
|
||||
@ -11,19 +57,31 @@ class GivenContext {
|
||||
private val variables: ImplicitsMap[Any] = mutable.HashMap.empty
|
||||
private val variablesWithOwner: ImplicitsMap[ImplicitsMap[Any]] = mutable.HashMap.empty
|
||||
|
||||
def provide (i: Any): Unit =
|
||||
variables += (i.getClass -> i)
|
||||
def << (i: Any): Unit =
|
||||
this.provide(i)
|
||||
def provide [T: ClassTag] (i: T): Unit =
|
||||
variables += (classTag[T].runtimeClass -> i)
|
||||
def << [T: ClassTag] (is: (Class[T], T)): Unit =
|
||||
val (_, i) = is
|
||||
this.provide[T](i)
|
||||
def << [T: ClassTag] (i: T): Unit =
|
||||
this.provide[T](i)
|
||||
|
||||
def >>[T: ClassTag] (consumer: T => Unit): ConsumeResult =
|
||||
this.use[T](consumer)
|
||||
def use [T: ClassTag] (consumer: T => Unit): ConsumeResult =
|
||||
private type CxtOption[T] = Either[ContextNotGivenException, T]
|
||||
def use [T: ClassTag]: CxtOption[T] =
|
||||
variables get classTag[T].runtimeClass match
|
||||
case Some(i) => consumer(i.asInstanceOf[T]); ConsumeResult(true)
|
||||
case None => ConsumeResult(false)
|
||||
def consume [T: ClassTag] (consume: T => Unit): ConsumeResult =
|
||||
this.use[T](consume)
|
||||
case Some(i) => Right(i.asInstanceOf[T])
|
||||
case None => Left(ContextNotGivenException())
|
||||
def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] =
|
||||
this.use[T] match
|
||||
case Left(_) => ConsumeFailed[U]()
|
||||
case Right(i) => ConsumeSucceed[U](consumer(i))
|
||||
def >> [T: ClassTag] (t: Class[T]): CxtOption[T] =
|
||||
this.use[T]
|
||||
def >!> [T: ClassTag] (t: Class[T]): T =
|
||||
this.use[T].toTry.get
|
||||
def >>[T: ClassTag, U] (consumer: T => U): ConsumeResult[U] =
|
||||
this.use[T,U](consumer)
|
||||
def consume [T: ClassTag] (consume: T => Any): ConsumeResult[Any] =
|
||||
this.use[T,Any](consume)
|
||||
|
||||
@targetName("ownedBy")
|
||||
def / [O: ClassTag] (owner: O): OwnedContext[O] =
|
||||
@ -33,26 +91,46 @@ class GivenContext {
|
||||
|
||||
class OwnedContext [O: ClassTag] {
|
||||
|
||||
def provide (i: Any): Unit =
|
||||
def provide [T: ClassTag] (i: T): Unit =
|
||||
(variablesWithOwner getOrElseUpdate (classTag[O].runtimeClass, mutable.HashMap.empty))
|
||||
.addOne(i.getClass -> i)
|
||||
def << (i: Any): Unit =
|
||||
this.provide(i)
|
||||
.addOne(classTag[T].runtimeClass -> i)
|
||||
def << [T: ClassTag] (is: (Class[T], T)): Unit =
|
||||
val (_, i) = is
|
||||
this.provide[T](i)
|
||||
def << [T: ClassTag] (i: T): Unit =
|
||||
this.provide[T](i)
|
||||
|
||||
def >> [T: ClassTag] (consumer: T => Unit): ConsumeResult =
|
||||
this.use[T](consumer)
|
||||
def use [T: ClassTag] (consumer: T => Unit): ConsumeResult =
|
||||
def use [T: ClassTag]: CxtOption[T] =
|
||||
variablesWithOwner(classTag[O].runtimeClass) get classTag[T].runtimeClass match
|
||||
case Some(i) => consumer(i.asInstanceOf[T]); ConsumeResult(true)
|
||||
case None => ConsumeResult(false)
|
||||
case Some(i) => Right(i.asInstanceOf[T])
|
||||
case None => Left(ContextNotGivenException())
|
||||
def use [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] =
|
||||
use[T] match
|
||||
case Left(_) => ConsumeFailed[U]()
|
||||
case Right(i) => ConsumeSucceed[U](consumer(i))
|
||||
def >> [T: ClassTag] (t: Class[T]): CxtOption[T] =
|
||||
this.use[T]
|
||||
def >!> [T: ClassTag] (t: Class[T]): T =
|
||||
this.use[T].toTry.get
|
||||
def >> [T: ClassTag, U] (consumer: T => U): ConsumeResult[U] =
|
||||
this.use[T,U](consumer)
|
||||
def consume [T: ClassTag] (consume: T => Any): ConsumeResult[Any] =
|
||||
this.use[T,Any](consume)
|
||||
|
||||
}
|
||||
|
||||
class ConsumeResult (success: Boolean) {
|
||||
trait ConsumeResult[U]:
|
||||
def toOption: Option[U]
|
||||
def |? : Option[U] = toOption
|
||||
@targetName("orElse")
|
||||
def || (processor: => Unit): Unit = {
|
||||
if !success then processor
|
||||
}
|
||||
}
|
||||
def || (processor: =>U): U
|
||||
private class ConsumeSucceed[U] (succeedValue: U) extends ConsumeResult[U]:
|
||||
override def toOption: Option[U] = Some(succeedValue)
|
||||
@targetName("orElse")
|
||||
override def || (processor: => U): U = succeedValue
|
||||
private class ConsumeFailed[U] extends ConsumeResult[U]:
|
||||
override def toOption: Option[U] = None
|
||||
@targetName("orElse")
|
||||
override def || (processor: => U): U = processor
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user