diff --git a/src/as/com/threerings/io/Streamer.as b/src/as/com/threerings/io/Streamer.as index 9cdc6ace7..79fec8258 100644 --- a/src/as/com/threerings/io/Streamer.as +++ b/src/as/com/threerings/io/Streamer.as @@ -32,7 +32,9 @@ import com.threerings.io.streamers.ArrayStreamer; import com.threerings.io.streamers.ByteArrayStreamer; import com.threerings.io.streamers.ByteEnumStreamer; import com.threerings.io.streamers.EnumStreamer; +import com.threerings.io.streamers.MapStreamer; import com.threerings.io.streamers.NumberStreamer; +import com.threerings.io.streamers.SetStreamer; import com.threerings.io.streamers.StringStreamer; public class Streamer @@ -51,10 +53,6 @@ public class Streamer public static function getStreamerByJavaName (jname :String) :Streamer { initStreamers(); - // unstream lists as simple arrays - if (jname == "java.util.List" || jname == "java.util.ArrayList") { - jname = "[Ljava.lang.Object;"; - } // see if we have a streamer for it var streamer :Streamer = _byJName[jname] as Streamer; @@ -130,9 +128,12 @@ public class Streamer return "[Streamer(" + _jname + ")]"; } - protected static function registerStreamer (st :Streamer) :void + protected static function registerStreamer (st :Streamer, ... extraJavaNames) :void { _byJName[st.getJavaClassName()] = st; + for each (var name :String in extraJavaNames) { + _byJName[name] = st; + } } /** @@ -146,10 +147,13 @@ public class Streamer return; } _byJName = new Dictionary(); - for each (var c :Class in - [ StringStreamer, NumberStreamer, ArrayStreamer, ByteArrayStreamer ]) { + for each (var c :Class in [ StringStreamer, NumberStreamer, ByteArrayStreamer ]) { registerStreamer(Streamer(new c())); } + registerStreamer(ArrayStreamer.INSTANCE, + "java.util.List", "java.util.ArrayList", "java.util.Collection"); + registerStreamer(SetStreamer.INSTANCE, "java.util.Set"); + registerStreamer(MapStreamer.INSTANCE, "java.util.Map"); } protected var _target :Class; diff --git a/src/as/com/threerings/io/streamers/ArrayStreamer.as b/src/as/com/threerings/io/streamers/ArrayStreamer.as index 5f4f5d1fe..f7ecd3678 100644 --- a/src/as/com/threerings/io/streamers/ArrayStreamer.as +++ b/src/as/com/threerings/io/streamers/ArrayStreamer.as @@ -42,6 +42,8 @@ import com.threerings.util.langBoolean; */ public class ArrayStreamer extends Streamer { + public static const INSTANCE :ArrayStreamer = new ArrayStreamer(); + public function ArrayStreamer (jname :String = "[Ljava.lang.Object;") { super(TypedArray, jname); diff --git a/src/as/com/threerings/io/streamers/MapStreamer.as b/src/as/com/threerings/io/streamers/MapStreamer.as new file mode 100644 index 000000000..20f008a73 --- /dev/null +++ b/src/as/com/threerings/io/streamers/MapStreamer.as @@ -0,0 +1,81 @@ +// +// $Id$ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.io.streamers { + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; +import com.threerings.io.Streamer; + +import com.threerings.util.ClassUtil; + +import com.threerings.util.Map; +import com.threerings.util.Maps; + +/** + * Streamer for Maps. + */ +public class MapStreamer extends Streamer +{ + public static const INSTANCE :MapStreamer = new MapStreamer(); + + public static const DEFAULT_MAP :Map = Maps.newBuilder(Object).makeImmutable().build(); + + public function MapStreamer () + { + super(Map, "java.util.HashMap"); + } + + override public function createObject (ins :ObjectInputStream) :Object + { + var size :int = ins.readInt(); + var map :Map; + if (size > 0) { + // guess the type of map based on the first key + var key :Object = ins.readObject(); + map = Maps.newMapOf(ClassUtil.getClass(key)); + map.put(key, ins.readObject()); + for (var ii :int = 1; ii < size; ii++) { + map.put(ins.readObject(), ins.readObject()); + } + } else { + // oh crap + map = DEFAULT_MAP; + } + return map; + } + + override public function readObject (obj :Object, ins :ObjectInputStream) :void + { + // nada + } + + override public function writeObject (obj :Object, out :ObjectOutputStream) :void + { + var map :Map = Map(obj); + out.writeInt(map.size()); + map.forEach(function (key :Object, value :Object) :void { + out.writeObject(key); + out.writeObject(value); + }); + } +} +} diff --git a/src/as/com/threerings/io/streamers/SetStreamer.as b/src/as/com/threerings/io/streamers/SetStreamer.as new file mode 100644 index 000000000..0208faa27 --- /dev/null +++ b/src/as/com/threerings/io/streamers/SetStreamer.as @@ -0,0 +1,80 @@ +// +// $Id$ +// +// Narya library - tools for developing networked games +// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved +// http://www.threerings.net/code/narya/ +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.threerings.io.streamers { + +import com.threerings.io.ObjectInputStream; +import com.threerings.io.ObjectOutputStream; +import com.threerings.io.Streamer; + +import com.threerings.util.ClassUtil; + +import com.threerings.util.Set; +import com.threerings.util.Sets; + +/** + * Streamer for Sets. + */ +public class SetStreamer extends Streamer +{ + public static const INSTANCE :SetStreamer = new SetStreamer(); + + public static const DEFAULT_SET :Set = Sets.newBuilder(Object).makeImmutable().build(); + + public function SetStreamer () + { + super(Set, "java.util.HashSet"); + } + + override public function createObject (ins :ObjectInputStream) :Object + { + var size :int = ins.readInt(); + var set :Set; + if (size > 0) { + // guess the type of set based on the first value + var first :Object = ins.readObject(); + set = Sets.newSetOf(ClassUtil.getClass(first)); + set.add(first); + for (var ii :int = 1; ii < size; ii++) { + set.add(ins.readObject()); + } + } else { + // oh crap + set = DEFAULT_SET; + } + return set; + } + + override public function readObject (obj :Object, ins :ObjectInputStream) :void + { + // nada + } + + override public function writeObject (obj :Object, out :ObjectOutputStream) :void + { + var set :Set = Set(obj); + out.writeInt(set.size()); + set.forEach(function (value :Object) :void { + out.writeObject(value); + }); + } +} +} diff --git a/src/as/com/threerings/util/StreamableHashMap.as b/src/as/com/threerings/util/StreamableHashMap.as index 884b21403..ad6c3105c 100644 --- a/src/as/com/threerings/util/StreamableHashMap.as +++ b/src/as/com/threerings/util/StreamableHashMap.as @@ -24,6 +24,7 @@ package com.threerings.util { import com.threerings.io.ObjectInputStream; import com.threerings.io.ObjectOutputStream; import com.threerings.io.Streamable; +import com.threerings.io.streamers.MapStreamer; import com.threerings.util.Maps; import com.threerings.util.maps.ForwardingMap; @@ -48,40 +49,19 @@ public class StreamableHashMap extends ForwardingMap */ public function StreamableHashMap (keyClazz :Class = null) { - super(keyClazz == null ? DEFAULT_MAP : Maps.newMapOf(keyClazz)); + super(keyClazz == null ? MapStreamer.DEFAULT_MAP : Maps.newMapOf(keyClazz)); } // documentation inherited from interface Streamable public function writeObject (out :ObjectOutputStream) :void { - out.writeInt(size()); - forEach(function (key :Object, value :Object) :void { - out.writeObject(key); - out.writeObject(value); - }); + MapStreamer.INSTANCE.writeObject(this, out); } // documentation inherited from interface Streamable public function readObject (ins :ObjectInputStream) :void { - var ecount :int = ins.readInt(); - if (ecount > 0) { - // guess the type of map based on the first key - var key :Object = ins.readObject(); - _source = Maps.newMapOf(ClassUtil.getClass(key)); - put(key, ins.readObject()); - // now read the rest - for (var ii :int = 1; ii < ecount; ii++) { - put(ins.readObject(), ins.readObject()); - } - - } else { - _source = DEFAULT_MAP; - } + _source = Map(MapStreamer.INSTANCE.createObject(ins)); } - - /** Used when we don't know the key class. Typically if a map is unstreamed it is - * read-only anyway, so this will work for empty maps that are unstreamed. */ - protected static const DEFAULT_MAP :Map = Maps.newBuilder(Object).makeImmutable().build(); } }