view src/luan/lib/PickleCon.java @ 130:0594c132888b

cleanup git-svn-id: https://luan-java.googlecode.com/svn/trunk@131 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Tue, 10 Jun 2014 02:43:40 +0000
parents 486a0641bca4
children 0517a4a7fcc5
line wrap: on
line source

package luan.lib;

import java.io.OutputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.IdentityHashMap;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
import luan.Luan;
import luan.LuanTable;
import luan.LuanState;
import luan.LuanFunction;
import luan.LuanJavaFunction;
import luan.LuanException;


public final class PickleCon {
	final LuanState luan;
	private final DataInputStream in;
	private final LuanFunction _read_binary;
	private final LuanTable ioModule;
	private final DataOutputStream out;
	private final List<byte[]> binaries = new ArrayList<byte[]>();
	String src;

	PickleCon(LuanState luan,DataInputStream in,DataOutputStream out) {
		this.in = in;
		this.luan = luan;
		try {
			this._read_binary = new LuanJavaFunction(
				PickleCon.class.getMethod( "_read_binary", Integer.TYPE ), this
			);
		} catch(NoSuchMethodException e) {
			throw new RuntimeException(e);
		}
		this.ioModule = (LuanTable)luan.loaded().get("Io");

		this.out = out;
	}

	public byte[] _read_binary(int size) throws IOException, LuanException {
		byte[] a = new byte[size];
		int i = 0;
		while( i < size ) {
			int n = in.read(a,i,size-i);
			if( n == -1 )
				throw luan.exception( "end of stream" );
			i += n;
		}
		return a;
	}

	public Object read() throws IOException, LuanException {
		ioModule.put("_read_binary",_read_binary);
		src = in.readUTF();
		LuanFunction fn = BasicLib.load(luan,src,"pickle-reader",true,false);
		Object rtn = luan.call(fn);
		ioModule.put("_binaries",null);
		return rtn;
	}

	public String pickle(Object obj) throws LuanException {
		if( obj == null )
			return "nil";
		if( obj instanceof Number )
			return Luan.toString((Number)obj);
		if( obj instanceof String )
			return "\"" + Luan.stringEncode((String)obj) + "\"";
		if( obj instanceof LuanTable )
			return pickle( (LuanTable)obj, Collections.newSetFromMap(new IdentityHashMap<LuanTable,Boolean>()) );
		if( obj instanceof byte[] ) {
			byte[] a = (byte[])obj;
			binaries.add(a);
			return "Io._binaries[" + binaries.size() + "]";
		}
		throw luan.exception( "invalid type: " + obj.getClass() );
	}

	private String pickle(Object obj,Set<LuanTable> set) throws LuanException {
		return obj instanceof LuanTable ? pickle((LuanTable)obj,set) : pickle(obj);
	}

	private String pickle(LuanTable tbl,Set<LuanTable> set) throws LuanException {
		if( !set.add(tbl) ) {
			throw luan.exception( "circular reference in table" );
		}
		StringBuilder sb = new StringBuilder();
		sb.append( "{" );
		for( Map.Entry<Object,Object> entry : tbl ) {
			sb.append( "[" );
			sb.append( pickle(entry.getKey(),set) );
			sb.append( "]=" );
			sb.append( pickle(entry.getValue(),set) );
			sb.append( ", " );
		}
		sb.append( "}" );
		return sb.toString();
	}

	public void write(Object... args) throws LuanException, IOException {
		StringBuilder sb = new StringBuilder();
		if( !binaries.isEmpty() ) {
			sb.append( "Io._binaries = {}\n" );
			for( byte[] a : binaries ) {
				sb.append( "Io._binaries[#Io._binaries+1] = Io._read_binary(" + a.length + ")\n" );
			}
		}
		for( Object obj : args ) {
			sb.append( luan.toString(obj) );
		}
		out.writeUTF( sb.toString() );
		for( byte[] a : binaries ) {
			out.write(a);
		}
		out.flush();
		binaries.clear();
	}

	public void close() throws IOException {
		in.close();
		out.close();
	}
}