All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rojoma.json.v3.io.BlockJsonTokenIterator.scala Maven / Gradle / Ivy

The newest version!
package com.rojoma.json.v3
package io

import scala.annotation.tailrec

import java.io.{Reader, StringReader}

import `-impl`.util.AbstractBufferedIterator
import util.WrappedCharArray

/** Convert a character-stream into a token-stream.
  *
  * This reads characters in blocks of size `blockSize`, so if the
  * underlying `Reader` is to be re-used for other non-JSON purposes
  * after finishing reading, a [[com.rojoma.json.v3.io.JsonTokenIterator]]
  * should be used instead.
  *
  * As extensions to standard JSON, this reader supports single-quoted
  * strings and Javascript-style comments.
  * 
  * Unless you actually need tokens, prefer [[com.rojoma.json.v3.io.FusedBlockJsonEventIterator]].
  *
  * @see [[com.rojoma.json.v3.io.JsonTokenIterator]]
  * @see [[com.rojoma.json.v3.io.JsonTokenGenerator]]
  * @see [[com.rojoma.json.v3.io.JsonToken]]
  */
class BlockJsonTokenIterator private (private var remaining: WrappedCharArray, reader: Reader, buf: Array[Char]) extends AbstractBufferedIterator[JsonToken] {
  def this(reader: Reader, blockSize: Int = 1024) = this(null, reader, new Array[Char](blockSize))
  def this(text: String) = this(new StringReader(text), 1024)

  private var lexer = JsonTokenGenerator.newGenerator
  private var token: JsonToken = null
  private var lastPos = Position.Invalid

  private def fillRemaining() {
    reader.read(buf) match {
      case -1 => remaining = null
      case n => remaining = WrappedCharArray(buf, 0, n)
    }
  }

  def head =
    if(hasNext) token
    else throw new NoSuchTokenException(lastPos)

  def next() = {
    val result = head
    token = null
    result
  }

  override def toString =
    if(token ne null) "non-empty iterator"
    else if(lastPos.isValid) "empty iterator"
    else "possibly-empty iterator"

  def hasNext: Boolean =
    if(token ne null) true
    else if(lastPos.isValid) false
    else advance()

  @tailrec
  private def advance(): Boolean = {
    if(remaining eq null) {
      fillRemaining()
      if(remaining eq null) {
        lexer.finish() match {
          case JsonTokenGenerator.EndOfInput(pos) =>
            lastPos = pos
            return false
          case JsonTokenGenerator.FinalToken(t, pos) =>
            token = t
            lastPos = pos
            return true
        }
      }
    }
    // ok, remaining != null...
    lexer.lex(remaining) match {
      case JsonTokenGenerator.Token(t, newLexer, newRemaining) =>
        token = t
        lexer = newLexer
        if(newRemaining.isEmpty) remaining = null
        else remaining = newRemaining
        true
      case JsonTokenGenerator.More(newLexer) =>
        lexer = newLexer
        remaining = null
        advance()
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy