From a75f496e76ad02db3b4eb1b80ccf3f4b3524b9cc Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Sat, 4 Mar 2006 02:43:14 +0000 Subject: [PATCH] Checkpoint. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@3912 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- src/as/com/threerings/io/ArrayMask.as | 6 +- src/as/com/threerings/io/ObjectInputStream.as | 2 +- .../com/threerings/io/ObjectOutputStream.as | 2 +- src/as/com/threerings/io/Streamable.as | 4 + src/as/com/threerings/io/Streamer.as | 14 ++- .../threerings/presents/client/TestClient.as | 98 +++++++++++++++++++ src/as/com/threerings/util/ClassUtil.as | 11 +++ src/as/com/threerings/util/TypedArray.as | 90 +++++++++++++++++ 8 files changed, 216 insertions(+), 11 deletions(-) create mode 100644 src/as/com/threerings/util/TypedArray.as diff --git a/src/as/com/threerings/io/ArrayMask.as b/src/as/com/threerings/io/ArrayMask.as index 25c77d44c..f777f659c 100644 --- a/src/as/com/threerings/io/ArrayMask.as +++ b/src/as/com/threerings/io/ArrayMask.as @@ -3,7 +3,6 @@ package com.threerings.io { import flash.util.ByteArray; public class ArrayMask - implements Streamable { public function ArrayMask (length :int = 0) { @@ -31,15 +30,14 @@ public class ArrayMask return (_mask[index/8] & (1 << (index % 8))) != 0; } - // documentation inherited from interface Streamable - public function writeObject (out :ObjectOutputStream) :void + public function writeTo (out :ObjectOutputStream) :void { out.writeShort(_mask.length); out.writeBytes(_mask); } // documentation inherited from interface Streamable - public function readObject (ins :ObjectInputStream) :void + public function readFrom (ins :ObjectInputStream) :void { _mask.length = ins.readShort(); ins.readBytes(_mask, 0, _mask.length); diff --git a/src/as/com/threerings/io/ObjectInputStream.as b/src/as/com/threerings/io/ObjectInputStream.as index cd9170415..fd9d93bc6 100644 --- a/src/as/com/threerings/io/ObjectInputStream.as +++ b/src/as/com/threerings/io/ObjectInputStream.as @@ -100,7 +100,7 @@ public class ObjectInputStream readBareObjectImpl(obj, Streamer.getStreamer(obj)); } - internal function readBareObjectImpl (obj :Object, streamer :Streamer) :void + public function readBareObjectImpl (obj :Object, streamer :Streamer) :void { // streamable objects if (streamer == null) { diff --git a/src/as/com/threerings/io/ObjectOutputStream.as b/src/as/com/threerings/io/ObjectOutputStream.as index 5b96b6ac9..1d8e3e080 100644 --- a/src/as/com/threerings/io/ObjectOutputStream.as +++ b/src/as/com/threerings/io/ObjectOutputStream.as @@ -74,7 +74,7 @@ public class ObjectOutputStream writeBareObjectImpl(obj, Streamer.getStreamer(obj)); } - protected function writeBareObjectImpl (obj :Object, streamer :Streamer) + public function writeBareObjectImpl (obj :Object, streamer :Streamer) { // if it's Streamable, it goes straight through if (streamer == null) { diff --git a/src/as/com/threerings/io/Streamable.as b/src/as/com/threerings/io/Streamable.as index 351b6c84b..e6a180413 100644 --- a/src/as/com/threerings/io/Streamable.as +++ b/src/as/com/threerings/io/Streamable.as @@ -1,5 +1,9 @@ package com.threerings.io { +/** + * Note: all Streamable instances should have a constructor that copes + * with no arguments. + */ public interface Streamable { function writeObject (out :ObjectOutputStream) :void; diff --git a/src/as/com/threerings/io/Streamer.as b/src/as/com/threerings/io/Streamer.as index 0dcaf7777..02579c8a2 100644 --- a/src/as/com/threerings/io/Streamer.as +++ b/src/as/com/threerings/io/Streamer.as @@ -36,7 +36,7 @@ public class Streamer initStreamers(); for each (var streamer :Streamer in _streamers) { - if (streamer._targ == clazz) { + if (streamer._target == clazz) { return streamer; } } @@ -61,13 +61,13 @@ public class Streamer public function Streamer (targ :Class, jname :String) //throws IOError { - _targ = targ; + _target = targ; _jname = jname; } public function isStreamerFor (obj :Object) :Boolean { - return (obj is _targ); // scripting langs are weird + return (obj is _target); // scripting langs are weird } /** @@ -97,7 +97,7 @@ public class Streamer //throws IOError { // actionscript is so fucked up - return new _targ(); + return new _target(); } public function readObject (obj :Object, ins :ObjectInputStream) :void @@ -124,10 +124,14 @@ public class Streamer } } - protected var _targ :Class; + protected var _target :Class; protected var _jname :String; + /** If our target class is an array, this is a reference to a streamer + * that can stream our array elements, otherwise it is null. */ + protected var _delegate :Streamer; + /** Just a list of our standard streamers. */ protected static var _streamers :Array; } diff --git a/src/as/com/threerings/presents/client/TestClient.as b/src/as/com/threerings/presents/client/TestClient.as index ec8eef9e2..c7d79c603 100644 --- a/src/as/com/threerings/presents/client/TestClient.as +++ b/src/as/com/threerings/presents/client/TestClient.as @@ -1,6 +1,9 @@ package com.threerings.presents.client { +import flash.util.describeType; + import com.threerings.util.Name; +import com.threerings.presents.Log; import com.threerings.presents.data.TimeBaseMarshaller; import com.threerings.presents.net.UsernamePasswordCreds; @@ -11,6 +14,47 @@ public class TestClient extends Client super(new UsernamePasswordCreds(new Name("Ray"), "fork-u-2")); setServer("tasman.sea.earth.threerings.net", DEFAULT_SERVER_PORT); logon(); + + var a :Object = new HelperClass(this); + + Log.debug("instance: " + describeType(a).toXMLString()); + Log.debug("class : " + describeType(HelperClass).toXMLString()); + + /* + var b :Object = new PooperClass(); + var c :Object = 2.4; + var d :Object = new HooperClass(this); + + Log.debug("1) " + (a as HelperClass)); + Log.debug("2) " + (b as HelperClass)); + Log.debug("3) " + HelperClass(a)); + //Log.debug("4) " + HelperClass(b)); + Log.debug("5) " + (c as int)); + Log.debug("6) " + int(c)); + + //Log.debug("7) " + (d === a)); + + Log.debug("8) " + (a as HooperClass)); + Log.debug("9) " + HelperClass(d)); + //Log.debug("X) " + HooperClass(a)); + + var x :HelperClass = HelperClass(d); + var y :HelperClass = (d as HelperClass); + var z :HooperClass = HooperClass(d); + d.hype(); + x.hype(); + y.hype(); + z.hype(); + Log.debug("x === d: " + (x === d)); + Log.debug("y === d: " + (y === d)); + Log.debug("x === y: " + (x === y)); + Log.debug("d === z: " + (d === z)); + Log.debug("y === z: " + (y === z)); + */ + + //var ta :TypedArray = new TypedArray(HooperClass); + //var ta2 :TypedArray = new TypedArray(HelperClass); + //var ta3 :TypedArray = new TypedArray(Pork); } @@ -20,5 +64,59 @@ public class TestClient extends Client { var i :int = TimeBaseMarshaller.GET_TIME_OID; } + + public function b () :void + { + } } } + +import com.threerings.presents.Log; +import com.threerings.presents.client.TestClient; + +class HelperClass +{ + public function HelperClass (cli :TestClient) + { + _cli = cli; + _cli.b(); + } + + public function hype () :void + { + Log.debug("helper hype"); + } + + protected var _cli :TestClient; +} + +interface Pork +{ + function porker () :void; +} + +final class HooperClass extends HelperClass + implements Pork +{ + public function HooperClass (cli :TestClient) + { + super(cli); + } + + public override function hype () :void + { + Log.debug("hooper hype"); + } + + public function porker () :void + { + // nada + } +} + +class PooperClass +{ + public function PooperClass () + { + } +} diff --git a/src/as/com/threerings/util/ClassUtil.as b/src/as/com/threerings/util/ClassUtil.as index f4a8a1341..64d059f0e 100644 --- a/src/as/com/threerings/util/ClassUtil.as +++ b/src/as/com/threerings/util/ClassUtil.as @@ -1,5 +1,7 @@ package com.threerings.util { +import flash.util.describeType; + public class ClassUtil { public static function getClassName (obj :Object) :String @@ -26,5 +28,14 @@ public class ClassUtil { return flash.util.getClassByName(cname); } + + public static function isFinal (type :Class) :Boolean + { + var attrs :XMLList = describeType(type).elements("type"); + + // FUCK!!! This information is lost in the Class introspection + + return true; //TODO + } } } diff --git a/src/as/com/threerings/util/TypedArray.as b/src/as/com/threerings/util/TypedArray.as new file mode 100644 index 000000000..91613ec9b --- /dev/null +++ b/src/as/com/threerings/util/TypedArray.as @@ -0,0 +1,90 @@ +package com.threerings.util { + +import flash.util.describeType; + +import mx.utils.ObjectUtil; + +import com.threerings.io.ArrayMask; +import com.threerings.io.Streamer; + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; +import com.threerings.io.Streamable; + +import com.threerings.presents.Log; + +public dynamic class TypedArray extends Array + implements Streamable +{ + // TODO: remove the isFinal parameter and determine it + // be introspecting on the class + public function TypedArray (type :Class, isFinal :Boolean, length :int = 0) + { + super(length); + _type = type; + _final = isFinal; + _delegate = Streamer.getStreamerByClass(type); + } + + // documentation inherited from interface Streamable + public function readObject (ins :ObjectInputStream) :void + { + if (_final) { + var mask = new ArrayMask(); + mask.readFrom(ins); + for (var ii :int = 0; ii < length; ii++) { + if (mask.isSet(ii)) { + var target :Object; + if (_delegate == null) { + target = new _type(); + } else { + target = _delegate.createObject(ins); + } + ins.readBareObjectImpl(target, _delegate); + this[ii] = target; + } + } + + } else { + for (var ii :int = 0; ii < length; ii++) { + this[ii] = ins.readObject(); + } + } + } + + // documentation inherited from interface Streamable + public function writeObject (out :ObjectOutputStream) :void + { + out.writeInt(length); + if (_final) { + var mask :ArrayMask = new ArrayMask(length); + for (var ii :int = 0; ii < length; ii++) { + if (this[ii] != null) { + mask.set(ii); + } + } + mask.writeTo(out); + // now write the populated elements + for (var ii :int = 0; ii < length; ii++) { + var element :Object = this[ii]; + if (element != null) { + out.writeBareObjectImpl(element, _delegate); + } + } + + } else { + for (var ii :int = 0; ii < length; ii++) { + out.writeObject(this[ii]); + } + } + } + + /** The 'type' of this array, which doesn't really mean anything + * except gives it a clue as to how to stream to our server. */ + protected var _type :Class; + + protected var _final :Boolean; + + protected var _delegate :Streamer; +} +}