|
Play Framework/Scala example source code file (Parsing.scala)
The Parsing.scala Play Framework example source code/* * Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com> */ package play.api.libs.iteratee import scala.concurrent.Future import play.api.libs.iteratee.Execution.Implicits.{ defaultExecutionContext => dec } object Parsing { sealed trait MatchInfo[A] { def content: A def isMatch = this match { case Matched(_) => true case Unmatched(_) => false } } case class Matched[A](val content: A) extends MatchInfo[A] case class Unmatched[A](val content: A) extends MatchInfo[A] def search(needle: Array[Byte]): Enumeratee[Array[Byte], MatchInfo[Array[Byte]]] = new Enumeratee[Array[Byte], MatchInfo[Array[Byte]]] { val needleSize = needle.size val fullJump = needleSize val jumpBadCharecter: (Byte => Int) = { val map = Map(needle.dropRight(1).reverse.zipWithIndex.reverse: _*) //remove the last byte => map.get(byte).map(_ + 1).getOrElse(fullJump) } def applyOn[A](inner: Iteratee[MatchInfo[Array[Byte]], A]): Iteratee[Array[Byte], Iteratee[MatchInfo[Array[Byte]], A]] = { Iteratee.flatten(inner.fold1((a, e) => Future.successful(Done(Done(a, e), Input.Empty: Input[Array[Byte]])), k => Future.successful(Cont(step(Array[Byte](), Cont(k)))), (err, r) => throw new Exception())(dec)) } def scan(previousMatches: List[MatchInfo[Array[Byte]]], piece: Array[Byte], startScan: Int): (List[MatchInfo[Array[Byte]]], Array[Byte]) = { if (piece.length < needleSize) { (previousMatches, piece) } else { val fullMatch = Range(needleSize - 1, -1, -1).forall(scan => needle(scan) == piece(scan + startScan)) if (fullMatch) { val (prefix, suffix) = piece.splitAt(startScan) val (matched, left) = suffix.splitAt(needleSize) val newResults = previousMatches ++ List(Unmatched(prefix), Matched(matched)) filter (!_.content.isEmpty) if (left.length < needleSize) (newResults, left) else scan(newResults, left, 0) } else { val jump = jumpBadCharecter(piece(startScan + needleSize - 1)) val isFullJump = jump == fullJump val newScan = startScan + jump if (newScan + needleSize > piece.length) { val (prefix, suffix) = (piece.splitAt(startScan)) (previousMatches ++ List(Unmatched(prefix)), suffix) } else scan(previousMatches, piece, newScan) } } } def step[A](rest: Array[Byte], inner: Iteratee[MatchInfo[Array[Byte]], A])(in: Input[Array[Byte]]): Iteratee[Array[Byte], Iteratee[MatchInfo[Array[Byte]], A]] = { in match { case Input.Empty => Cont(step(rest, inner)) //here should rather pass Input.Empty along case Input.EOF => Done(inner, Input.El(rest)) case Input.El(chunk) => val all = rest ++ chunk def inputOrEmpty(a: Array[Byte]) = if (a.isEmpty) Input.Empty else Input.El(a) Iteratee.flatten(inner.fold1((a, e) => Future.successful(Done(Done(a, e), inputOrEmpty(rest))), k => { val (result, suffix) = scan(Nil, all, 0) val fed = result.filter(!_.content.isEmpty).foldLeft(Future.successful(Array[Byte]() -> Cont(k))) { (p, m) => p.flatMap(i => i._2.fold1((a, e) => Future.successful((i._1 ++ m.content, Done(a, e))), k => Future.successful((i._1, k(Input.El(m)))), (err, e) => throw new Exception())(dec) )(dec) } fed.flatMap { case (ss, i) => i.fold1((a, e) => Future.successful(Done(Done(a, e), inputOrEmpty(ss ++ suffix))), k => Future.successful(Cont[Array[Byte], Iteratee[MatchInfo[Array[Byte]], A]]((in: Input[Array[Byte]]) => in match { case Input.EOF => Done(k(Input.El(Unmatched(suffix))), Input.EOF) //suffix maybe empty case other => step(ss ++ suffix, Cont(k))(other) })), (err, e) => throw new Exception())(dec) }(dec) }, (err, e) => throw new Exception())(dec) ) } } } } Other Play Framework source code examplesHere is a short list of links related to this Play Framework Parsing.scala source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.