Cells/cells/shared/src/net/okennedy/cells/SeqOp.scala

77 lines
2.5 KiB
Scala

package net.okennedy.cells
import scala.collection.mutable
import play.api.libs.json.Json
import play.api.libs.json.Format
import play.api.libs.json.JsResult
import play.api.libs.json.JsValue
import play.api.libs.json.JsSuccess
import play.api.libs.json.JsObject
import play.api.libs.json.JsString
sealed trait SeqOp[T]
{
def apply(seq: Seq[T]): Seq[T]
def map[B](op: T => B): SeqOp[B]
def bufferApply(seq: mutable.Buffer[T]): Unit
}
case class SeqInsert[T](position: Int, value: T) extends SeqOp[T]
{
def apply(seq: Seq[T]): Seq[T] =
{
val (before, after) = seq.splitAt(position)
(before :+ value) ++ after
}
def map[B](op: T => B): SeqOp[B] = SeqInsert[B](position, op(value))
def bufferApply(seq: mutable.Buffer[T]): Unit =
seq.insert(position, value)
}
case class SeqDelete[T](position: Int) extends SeqOp[T]
{
def apply(seq: Seq[T]): Seq[T] =
{
val (before, after) = seq.splitAt(position)
before ++ after.drop(1)
}
def map[B](op: T => B): SeqOp[B] = SeqDelete(position)
def bufferApply(seq: mutable.Buffer[T]): Unit =
seq.remove(position)
}
case class SeqReplace[T](position: Int, value: T) extends SeqOp[T]
{
def apply(seq: Seq[T]): Seq[T] =
{
val (before, after) = seq.splitAt(position)
(before :+ value) ++ after.drop(1)
}
def map[B](op: T => B): SeqOp[B] = SeqReplace[B](position, op(value))
def bufferApply(seq: mutable.Buffer[T]): Unit =
seq(position) = value
}
object SeqOp
{
implicit def SeqInsertFormat[T](implicit format: Format[T]): Format[SeqInsert[T]] = Json.format
implicit def SeqDeleteFormat[T](implicit format: Format[T]): Format[SeqDelete[T]] = Json.format
implicit def SeqReplaceFormat[T](implicit format: Format[T]): Format[SeqReplace[T]] = Json.format
implicit def SeqOpFormat[T](implicit format: Format[T]): Format[SeqOp[T]] =
new Format[SeqOp[T]]{
def reads(json: JsValue): JsResult[SeqOp[T]] =
(json \ "op").as[String] match {
case "insert" => JsSuccess(json.as[SeqInsert[T]])
case "delete" => JsSuccess(json.as[SeqDelete[T]])
case "replace" => JsSuccess(json.as[SeqReplace[T]])
}
def writes(o: SeqOp[T]): JsValue =
JsObject(
o match {
case x:SeqInsert[T] => Json.toJson(x).as[Map[String,JsValue]] ++ Map("op" -> JsString("insert"))
case x:SeqDelete[T] => Json.toJson(x).as[Map[String,JsValue]] ++ Map("op" -> JsString("delete"))
case x:SeqReplace[T] => Json.toJson(x).as[Map[String,JsValue]] ++ Map("op" -> JsString("replace"))
}
)
}
}