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

scala.tools.tasty.TastyHeaderUnpickler.scala Maven / Gradle / Ivy

/*
 * Scala (https://www.scala-lang.org)
 *
 * Copyright EPFL and Lightbend, Inc.
 *
 * Licensed under Apache License 2.0
 * (http://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package scala.tools.tasty

import java.util.UUID

import TastyFormat.{MajorVersion, MinorVersion, ExperimentalVersion, header}

class TastyHeaderUnpickler(reader: TastyReader) {
  import TastyHeaderUnpickler._
  import reader._

  def this(bytes: Array[Byte]) = this(new TastyReader(bytes))

  /** reads and verifies the TASTy version, extracting the UUID */
  def readHeader(): UUID = {

    for (i <- 0 until header.length)
      check(readByte() == header(i), "not a TASTy file")
    val fileMajor = readNat()
    if (fileMajor <= 27) { // old behavior before `tasty-core` 3.0.0-RC1
      val fileMinor = readNat()
      val signature = signatureString(fileMajor, fileMinor, 0)
      throw new UnpickleException(signature + backIncompatAddendum + toolingAddendum)
    }
    else {
      val fileMinor = readNat()
      val fileExperimental = readNat()
      val toolingLength = readNat()
      val toolingStart = {
        val start = currentAddr
        val end = start + toolingLength
        goto(end)
        start
      }

      val validVersion = TastyFormat.isVersionCompatible(
        fileMajor            = fileMajor,
        fileMinor            = fileMinor,
        fileExperimental     = fileExperimental,
        compilerMajor        = MajorVersion,
        compilerMinor        = MinorVersion,
        compilerExperimental = ExperimentalVersion
      )

      check(validVersion, {
        val signature = signatureString(fileMajor, fileMinor, fileExperimental)
        val toolingVersion = new String(bytes, toolingStart.index, toolingLength)
        val producedByAddendum = s"\nThe TASTy file was produced by $toolingVersion.$toolingAddendum"
        val msg = (
          if (fileExperimental != 0) unstableAddendum
          else if (fileMajor < MajorVersion) backIncompatAddendum
          else forwardIncompatAddendum
        )
        signature + msg + producedByAddendum
      })

      new UUID(readUncompressedLong(), readUncompressedLong())
    }
  }

  private def check(cond: Boolean, msg: => String): Unit = {
    if (!cond) throw new UnpickleException(msg)
  }
}

object TastyHeaderUnpickler {

  private def toolingAddendum = (
    if (ExperimentalVersion > 0)
      "\nNote that your tooling is currently using an unstable TASTy version."
    else
      ""
  )

  private def signatureString(fileMajor: Int, fileMinor: Int, fileExperimental: Int) = {
    def showMinorVersion(min: Int, exp: Int) = {
      val expStr = if (exp == 0) "" else s" [unstable release: $exp]"
      s"$min$expStr"
    }
    val minorVersion = showMinorVersion(MinorVersion, ExperimentalVersion)
    val fileMinorVersion = showMinorVersion(fileMinor, fileExperimental)
    s"""TASTy signature has wrong version.
      | expected: {majorVersion: $MajorVersion, minorVersion: $minorVersion}
      | found   : {majorVersion: $fileMajor, minorVersion: $fileMinorVersion}
      |
      |""".stripMargin
  }

  private def unstableAddendum =
    """This TASTy file was produced by an unstable release.
      |To read this TASTy file, your tooling must be at the same version.""".stripMargin

  private def backIncompatAddendum =
    """This TASTy file was produced by an earlier release that is not supported anymore.
      |Please recompile this TASTy with a later version.""".stripMargin

  private def forwardIncompatAddendum =
    """This TASTy file was produced by a more recent, forwards incompatible release.
      |To read this TASTy file, please upgrade your tooling.""".stripMargin
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy