Package org.renjin.primitives.io.serialization

Source Code of org.renjin.primitives.io.serialization.Serialization

package org.renjin.primitives.io.serialization;

import org.renjin.eval.Context;
import org.renjin.eval.EvalException;
import org.renjin.invoke.annotations.Current;
import org.renjin.invoke.annotations.DotCall;
import org.renjin.invoke.annotations.Internal;
import org.renjin.primitives.io.connections.Connection;
import org.renjin.primitives.io.connections.Connections;
import org.renjin.primitives.io.connections.OpenSpec;
import org.renjin.primitives.io.serialization.RDataWriter.PersistenceHook;
import org.renjin.sexp.*;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

import static org.renjin.util.CDefines.*;


public class Serialization {


  private static final int DEFAULT_SERIALIZATION_VERSION = 0;

  public enum SERIALIZATION_TYPE { ASCII, XDR, BINARY};

  @Internal
  public static SEXP unserializeFromConn(@Current Context context,
      SEXP conn, Environment rho) throws IOException {
   
    RDataReader reader = new RDataReader(context, Connections.getConnection(context, conn).getInputStream());
    return reader.readFile();
  }

  @Internal
  public static SEXP unserializeFromConn(@Current Context context,
      SEXP conn, Null nz) throws IOException {
   
    RDataReader reader = new RDataReader(context,
        Connections.getConnection(context, conn).getInputStream());
    return reader.readFile();
  }

  /**
   *
   * @param context
   * @param object
   * @param con
   * @param ascii
   * @param versionSexp
   * @param refhook  A mechanism is provided to allow special handling of non-system
   reference objects (all weak references and external pointers, and
   all environments other than package environments, name space
   environments, and the global environment).  The hook function
   consists of a function pointer and a data value.  The serialization
   function pointer is called with the reference object and the data
   value as arguments.  It should return R_NilValue for standard
   handling and an STRSXP for special handling.  In an STRSXP is
   returned, then a special handing mark is written followed by the
   strings in the STRSXP (attributes are ignored). 
   * @throws IOException
   */
  @Internal
  public static void serializeToConn(@Current Context context, SEXP object,
      SEXP con, boolean ascii, SEXP versionSexp, SEXP refhook) throws IOException {
   
    if(ascii) {
      throw new EvalException("ascii format serialization not implemented");
    }
   
    int version = DEFAULT_SERIALIZATION_VERSION;
    if(versionSexp instanceof Vector && versionSexp.length() == 1) {
      version = ((Vector)versionSexp).getElementAsInt(0);
    }
   
    RDataWriter writer = new RDataWriter(context,
        createHook(context, refhook), Connections.getConnection(context, con).getOutputStream());
    writer.save(object);
   
  }
 
 
  /**
   * Serializes a list of objects within a given environment to a connnection
   *
   * @param context
   * @param names character vector of the names of objects to be serialized
   * @param connHandle the connection handle (int)
   * @param ascii TRUE for ascii (not implemented)
   * @param version the version number
   * @param envir the environment from which to save objects
   * @param evalPromises TRUE to force promises
   * @throws IOException
   */
  @Internal
  public static void saveToConn(@Current Context context,
      StringVector names,
      SEXP connHandle,
      boolean ascii,
      SEXP version,
      Environment envir,
      boolean evalPromises) throws IOException {
   
    Connection con = Connections.getConnection(context, connHandle);
    boolean wasOpen = con.isOpen();
    if(!wasOpen) {
      con.open(new OpenSpec("wb"));
    }
   
    if(!con.canWrite()) {
      throw new EvalException("connection not open for writing");
    }
    if(ascii) {
      throw new EvalException("ascii serialization not implemented");
    }
    PairList.Builder list = new PairList.Builder();
    for(String name : names) {
      SEXP value = envir.getVariable(name);
      if(value == Symbol.UNBOUND_VALUE) {
        throw new EvalException("object '%s' not found", name);
      }
      if(evalPromises) {
        value = value.force(context);
      }
      list.add(name, value);
    }
   
    RDataWriter writer = new RDataWriter(context, con.getOutputStream());
    writer.save(list.build());
   
    if (!wasOpen) {
      con.close();
    }
  }
 
  @Internal
  public static void save(SEXP list, SEXP file, SEXP ascii, SEXP version, SEXP environment, SEXP evalPromises) {
    throw new EvalException("Serialization version 1 not supported.");
  }
 
  private static PersistenceHook createHook(final Context context, final SEXP hookExp) {
    if(hookExp == Null.INSTANCE) {
      return null;
    }
    if(!(hookExp instanceof Closure)) {
      throw new EvalException("Illegal type for refhook");
   
    return new PersistenceHook() {
     
      @Override
      public Vector apply(SEXP exp) {
       
        // make sure exp doesn't get evaled
        Promise promisedExp = Promise.repromise(exp);
       
        FunctionCall hookCall = FunctionCall.newCall(hookExp, promisedExp);
        SEXP result = context.evaluate(hookCall);
        if(result == Null.INSTANCE) {
          return Null.INSTANCE;
        } else if(result instanceof StringVector) {
          return (StringVector) result;
        } else {
          throw new EvalException("Unexpected result from hook function: " + result);
        }
      }
    };
 
  }
 
 
  /**
   * Reload datasets written with the function save.
   *
   * @param context
   * @param conn
   *          a (readable binary) connection or a character string giving the
   *          name of the file to load.
   * @param env
   *          the environment where the data should be loaded.
   * @return A character vector of the names of objects created, invisibly.
   * @throws IOException
   */
  @Internal
  public static SEXP loadFromConn2(@Current Context context, SEXP conn,
      Environment env) throws IOException {

    RDataReader reader = new RDataReader(context,
        Connections.getConnection(context, conn).getInputStream());
    HasNamedValues data = EvalException.checkedCast(reader.readFile());

    StringArrayVector.Builder names = new StringArrayVector.Builder();

    for (NamedValue pair : data.namedValues()) {
      env.setVariable(Symbol.get(pair.getName()), pair.getValue());
      names.add(pair.getName());
    }

    return names.build();
  }


  /**
   *
   * Writes ‘object’ to the specified connection.  If ‘connection’ is ‘NULL’ then
   * ‘object’ is serialized to a raw vector, which is returned as the result of
   * ‘serialize’.
   *
   * @param object the object to serialize
   * @param connection  an open connection handle OR {@code Null.INSTANCE} if the object is to be serialized
   * to a raw vector
   * @param ascii if 'TRUE' an ASCII representation is written (not implemented)
   * @param version
   * @param refhook  a hook function for handling reference objects.
   * @return a {@code RawVector}
   * @throws IOException
   */
  @DotCall("R_serialize")
  public static SEXP serialize(@Current Context context, SEXP object, SEXP connection, boolean ascii,
      SEXP version, SEXP refhook) throws IOException {
    //EvalException.check(!ascii, "ascii = TRUE has not been implemented");
    EvalException.check(refhook == Null.INSTANCE, "refHook != NULL has not been implemented yet.");
    EvalException.check(connection == Null.INSTANCE, "Only connection = NULL has been implemented so far.");

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    RDataWriter writer = new RDataWriter(context, baos,
            ascii? SERIALIZATION_TYPE.ASCII: SERIALIZATION_TYPE.XDR);
    writer.serialize(object);
  
    return new RawVector(baos.toByteArray());
  }
 
  /**
   *
   * @param connection a {@code RawVector}
   * @param refhook a hook function for handling reference objects.
   * @return a object
   * @throws IOException
   */
  @DotCall("R_unserialize")
  public static SEXP unserialize(@Current Context context, SEXP connection, SEXP refhook) throws IOException {
    EvalException.check(refhook == Null.INSTANCE, "refHook != NULL has not been implemented yet.");
   
    if(connection instanceof StringVector) {
        error(_("character vectors are no longer accepted by unserialize()"));
        return R_NilValue/* -Wall */;
    } else if(connection instanceof RawVector) {
      RDataReader reader = new RDataReader(context,
              new ByteArrayInputStream(((RawVector)connection).toByteArray()));
      return reader.readFile();
    } else {
      return unserializeFromConn(context, connection, Null.INSTANCE);
    }
  }
}
TOP

Related Classes of org.renjin.primitives.io.serialization.Serialization

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.