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

org.scalajs.linker.NodeIRFile.scala Maven / Gradle / Ivy

The newest version!
/*
 * Scala.js (https://www.scala-js.org/)
 *
 * Copyright EPFL.
 *
 * Licensed under Apache License 2.0
 * (https://www.apache.org/licenses/LICENSE-2.0).
 *
 * See the NOTICE file distributed with this work for
 * additional information regarding copyright ownership.
 */

package org.scalajs.linker

import scala.concurrent._

import scala.scalajs.js
import scala.scalajs.js.typedarray._
import scala.scalajs.js.typedarray.TypedArrayBufferOps._

import org.scalajs.linker.interface.IRFile
import org.scalajs.linker.interface.unstable.IRFileImpl

import java.io.EOFException
import java.nio._

import org.scalajs.ir

object NodeIRFile {
  import NodeFS._

  def apply(path: String)(implicit ec: ExecutionContext): Future[IRFile] = {
    cbFuture[Stats](stat(path, _)).map(stats =>
        new NodeIRFileImpl(path, stats.mtime.toOption))
  }

  private[linker] def dateToVersion(optDate: Option[js.Date]): ir.Version = {
    optDate
      .map(_.getTime())
      // filter invalid dates and over / underflows.
      .filter(d => !d.isNaN && !d.isInfinity)
      .map(_.toLong)
      .fold(ir.Version.Unversioned)(ir.Version.fromLong(_))
  }

  private final class NodeIRFileImpl(path: String, version: Option[js.Date])
      extends IRFileImpl(path, dateToVersion(version)) {

    def entryPointsInfo(implicit ec: ExecutionContext): Future[ir.EntryPointsInfo] = {
      def loop(fd: Int, buf: ByteBuffer): Future[ir.EntryPointsInfo] = {
        val len = buf.remaining()
        val off = buf.position()

        cbFuture[Int](read(fd, buf.typedArray(), off, len, off, _)).map { bytesRead =>
          if (bytesRead <= 0)
            throw new EOFException

          buf.position(buf.position() + bytesRead)
          buf.flip()
          ir.Serializers.deserializeEntryPointsInfo(buf)
        }.recoverWith {
          case _: BufferUnderflowException =>
            // Reset to write again.
            buf.position(buf.limit())
            buf.limit(buf.capacity())

            val newBuf = if (buf.remaining() <= 0) {
              val newBuf = ByteBuffer.allocateDirect(buf.capacity() * 2)
              buf.flip()
              newBuf.put(buf)
              buf
            } else {
              buf
            }

            loop(fd, newBuf)
        }
      }

      val result = cbFuture[Int](open(path, "r", _)).flatMap { fd =>
        loop(fd, ByteBuffer.allocateDirect(1024))
          .finallyWith(cbFuture[Unit](close(fd, _)))
      }

      IRFileImpl.withPathExceptionContext(path, result)
    }

    def tree(implicit ec: ExecutionContext): Future[ir.Trees.ClassDef] = {
      val result = cbFuture[Uint8Array](readFile(path, _)).map { arr =>
        ir.Serializers.deserialize(TypedArrayBuffer.wrap(arr.buffer))
      }

      IRFileImpl.withPathExceptionContext(path, result)
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy